1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5var blankClockImage; 6var blankClockAnim1Image; 7var blankClockAnim2Image; 8var animationTimer; 9var currentClockImage; 10var port; 11 12function updateEnabledStatus(alarm) { 13 var enabled = $('a' + alarm + '_on').checked; 14 $('a' + alarm + '_tt').disabled = !enabled; 15 $('a' + alarm + '_ampm').disabled = !enabled; 16 var valid = true; 17 try { 18 var tt = $('a' + alarm + '_tt').value; 19 var ampm = $('a' + alarm + '_ampm').selectedIndex; 20 parseTime(tt, ampm); 21 } catch (x) { 22 valid = false; 23 } 24 if (valid) { 25 $('a' + alarm + '_wrap').removeAttribute('aria-invalid'); 26 } else { 27 $('a' + alarm + '_wrap').setAttribute('aria-invalid', 'true'); 28 } 29 if (enabled) { 30 $('a' + alarm + '_wrap').classList.remove('disabled'); 31 } else { 32 $('a' + alarm + '_wrap').classList.add('disabled'); 33 } 34} 35 36function loadAllImages() { 37 var loadCount = 0; 38 var img = new Image(); 39 img.onload = function() { 40 blankClockImage = img; 41 currentClockImage = blankClockImage; 42 drawClock(); 43 }; 44 img.src = 'blank-clock-150.png'; 45 46 // These will finish loading before they're needed, no need 47 // for an onload handler. 48 blankClockAnim1Image = new Image(); 49 blankClockAnim1Image.src = 'blank-clock-ring1-150.png'; 50 blankClockAnim2Image = new Image(); 51 blankClockAnim2Image.src = 'blank-clock-ring2-150.png'; 52} 53 54function drawClock(hh, mm, ss) { 55 if (hh == undefined || mm == undefined) { 56 var d = new Date(); 57 hh = d.getHours(); 58 mm = d.getMinutes(); 59 ss = d.getSeconds() + 0.001 * d.getMilliseconds(); 60 } 61 62 if (!currentClockImage) { 63 loadAllImages(); 64 return; 65 } 66 67 var ctx = $('clock').getContext('2d'); 68 ctx.drawImage(currentClockImage, 0, 0); 69 70 // Move the hour by the fraction of the minute 71 hh = (hh % 12) + (mm / 60); 72 73 // Move the minute by the fraction of the second 74 mm += (ss / 60); 75 76 var hourAngle = Math.PI * hh / 6; 77 var hourX = Math.sin(hourAngle); 78 var hourY = -Math.cos(hourAngle); 79 var minAngle = Math.PI * mm / 30; 80 var minX = Math.sin(minAngle); 81 var minY = -Math.cos(minAngle); 82 var secAngle = Math.PI * ss / 30; 83 var secX = Math.sin(secAngle); 84 var secY = -Math.cos(secAngle); 85 86 var cx = 75; 87 var cy = 77; 88 89 ctx.lineWidth = 5; 90 ctx.strokeStyle = '#ffffff'; 91 ctx.globalAlpha = 0.5; 92 ctx.beginPath(); 93 ctx.moveTo(cx - 4 * hourX, cy - 4 * hourY); 94 ctx.lineTo(cx + 20 * hourX, cy + 20 * hourY); 95 ctx.stroke(); 96 ctx.beginPath(); 97 ctx.moveTo(cx - 8 * minX, cy - 8 * minY); 98 ctx.lineTo(cx + 35 * minX, cy + 33 * minY); 99 ctx.stroke(); 100 101 ctx.lineWidth = 3; 102 ctx.strokeStyle = '#696969'; 103 ctx.globalAlpha = 1.0; 104 ctx.beginPath(); 105 ctx.moveTo(cx - 4 * hourX, cy - 4 * hourY); 106 ctx.lineTo(cx + 20 * hourX, cy + 20 * hourY); 107 ctx.stroke(); 108 ctx.beginPath(); 109 ctx.moveTo(cx - 8 * minX, cy - 8 * minY); 110 ctx.lineTo(cx + 35 * minX, cy + 33 * minY); 111 ctx.stroke(); 112 113 ctx.lineWidth = 1; 114 ctx.strokeStyle = '#990000'; 115 ctx.globalAlpha = 1.0; 116 ctx.beginPath(); 117 ctx.moveTo(cx - 4 * secX, cy - 4 * secY); 118 ctx.lineTo(cx + 40 * secX, cy + 40 * secY); 119 ctx.stroke(); 120} 121 122function updateCurrentTime() { 123 var now = new Date(); 124 var hh = now.getHours(); 125 var mm = now.getMinutes(); 126 var ss = now.getSeconds(); 127 var str = ''; 128 if (hh % 12 == 0) { 129 str += '12'; 130 } else { 131 str += (hh % 12); 132 } 133 str += ':'; 134 if (mm >= 10) { 135 str += mm; 136 } else { 137 str += '0' + mm; 138 } 139 str += ':'; 140 if (ss >= 10) { 141 str += ss; 142 } else { 143 str += '0' + ss; 144 } 145 if (hh >= 12) { 146 str += " PM"; 147 } else { 148 str += " AM"; 149 } 150 $('current_time').innerText = str; 151} 152 153// Override from common.js 154window.stopAlarmAnimation = function() { 155 window.clearTimeout(animationTimer); 156 currentClockImage = blankClockImage; 157 drawClock(); 158 isAnimating = false; 159}; 160 161// Override from common.js 162window.displayAlarmAnimation = function() { 163 isAnimating = true; 164 var rings = 100; 165 function ring() { 166 if (rings == 0) { 167 stopAlarmAnimation(); 168 return; 169 } 170 currentClockImage = (rings % 2 == 0)? 171 blankClockAnim1Image: 172 blankClockAnim2Image; 173 drawClock(); 174 rings--; 175 animationTimer = window.setTimeout(ring, 50); 176 } 177 ring(); 178}; 179 180function addOutlineStyleListeners() { 181 document.addEventListener('click', function(evt) { 182 document.body.classList.add('nooutline'); 183 return true; 184 }, true); 185 document.addEventListener('keydown', function(evt) { 186 document.body.classList.remove('nooutline'); 187 return true; 188 }, true); 189} 190 191function load() { 192 try { 193 port = chrome.runtime.connect(); 194 port.onMessage.addListener(function(msg) { 195 if (msg.cmd == 'anim') { 196 displayAlarmAnimation(); 197 } 198 }); 199 } catch (e) { 200 } 201 202 addOutlineStyleListeners(); 203 204 stopAll(); 205 drawClock(); 206 setInterval(drawClock, 100); 207 208 updateCurrentTime(); 209 setInterval(updateCurrentTime, 250); 210 211 function updateTime(timeElement) { 212 if (!parseTime(timeElement.value)) { 213 return false; 214 } 215 216 timeElement.valueAsNumber = 217 timeElement.valueAsNumber % (12 * 60 * 60 * 1000); 218 if (timeElement.valueAsNumber < (1 * 60 * 60 * 1000)) 219 timeElement.valueAsNumber += (12 * 60 * 60 * 1000); 220 return true; 221 } 222 223 $('clock').addEventListener('click', function(evt) { 224 if (isPlaying || isSpeaking || isAnimating) { 225 stopAll(); 226 } else { 227 ringAlarmWithCurrentTime(); 228 } 229 }, false); 230 $('clock').addEventListener('keydown', function(evt) { 231 if (evt.keyCode == 13 || evt.keyCode == 32) { 232 if (isPlaying || isSpeaking || isAnimating) { 233 stopAll(); 234 } else { 235 ringAlarmWithCurrentTime(); 236 } 237 } 238 }, false); 239 240 // Alarm 1 241 242 var a1_tt = localStorage['a1_tt'] || DEFAULT_A1_TT; 243 $('a1_tt').value = a1_tt; 244 $('a1_tt').addEventListener('input', function(evt) { 245 updateEnabledStatus(1); 246 if (!updateTime($('a1_tt'))) { 247 evt.stopPropagation(); 248 return false; 249 } 250 localStorage['a1_tt'] = $('a1_tt').value; 251 updateEnabledStatus(1); 252 return true; 253 }, false); 254 $('a1_tt').addEventListener('change', function(evt) { 255 if ($('a1_tt').value.length == 4 && 256 parseTime('0' + $('a1_tt').value)) { 257 $('a1_tt').value = '0' + $('a1_tt').value; 258 } 259 if (!updateTime($('a1_tt'))) { 260 evt.stopPropagation(); 261 return false; 262 } 263 localStorage['a1_tt'] = $('a1_tt').value; 264 updateEnabledStatus(1); 265 return true; 266 }, false); 267 268 var a1_on = (localStorage['a1_on'] == 'true'); 269 $('a1_on').checked = a1_on; 270 $('a1_on').addEventListener('change', function(evt) { 271 window.setTimeout(function() { 272 localStorage['a1_on'] = $('a1_on').checked; 273 updateEnabledStatus(1); 274 }, 0); 275 }, false); 276 277 var a1_ampm = localStorage['a1_ampm'] || DEFAULT_A1_AMPM; 278 $('a1_ampm').selectedIndex = a1_ampm; 279 $('a1_ampm').addEventListener('change', function(evt) { 280 localStorage['a1_ampm'] = $('a1_ampm').selectedIndex; 281 }, false); 282 283 updateEnabledStatus(1); 284 285 // Alarm 2 286 287 var a2_tt = localStorage['a2_tt'] || DEFAULT_A2_TT; 288 $('a2_tt').value = a2_tt; 289 $('a2_tt').addEventListener('input', function(evt) { 290 updateEnabledStatus(2); 291 if (!updateTime($('a2_tt'))) { 292 evt.stopPropagation(); 293 return false; 294 } 295 localStorage['a2_tt'] = $('a2_tt').value; 296 updateEnabledStatus(2); 297 return true; 298 }, false); 299 $('a2_tt').addEventListener('change', function(evt) { 300 if ($('a2_tt').value.length == 4 && 301 parseTime('0' + $('a2_tt').value)) { 302 $('a2_tt').value = '0' + $('a2_tt').value; 303 } 304 if (!updateTime($('a2_tt'))) { 305 evt.stopPropagation(); 306 return false; 307 } 308 localStorage['a2_tt'] = $('a2_tt').value; 309 updateEnabledStatus(2); 310 return true; 311 }, false); 312 313 var a2_on = (localStorage['a2_on'] == 'true'); 314 $('a2_on').checked = a2_on; 315 $('a2_on').addEventListener('change', function(evt) { 316 window.setTimeout(function() { 317 localStorage['a2_on'] = $('a2_on').checked; 318 updateEnabledStatus(2); 319 }, 0); 320 }, false); 321 322 var a2_ampm = localStorage['a2_ampm'] || DEFAULT_A2_AMPM; 323 $('a2_ampm').selectedIndex = a2_ampm; 324 $('a2_ampm').addEventListener('change', function(evt) { 325 localStorage['a2_ampm'] = $('a2_ampm').selectedIndex; 326 }, false); 327 328 updateEnabledStatus(2); 329 330 // Phrase 331 332 var phrase = localStorage['phrase'] || DEFAULT_PHRASE; 333 $('phrase').value = phrase; 334 $('phrase').addEventListener('change', function(evt) { 335 localStorage['phrase'] = $('phrase').value; 336 }, false); 337 338 // Speech parameters 339 340 var rateElement = $('rate'); 341 var volumeElement = $('volume'); 342 var rate = localStorage['rate'] || DEFAULT_RATE; 343 var volume = localStorage['volume'] || DEFAULT_VOLUME; 344 rateElement.value = rate; 345 volumeElement.value = volume; 346 function listener(evt) { 347 rate = rateElement.value; 348 localStorage['rate'] = rate; 349 volume = volumeElement.value; 350 localStorage['volume'] = volume; 351 } 352 rateElement.addEventListener('keyup', listener, false); 353 volumeElement.addEventListener('keyup', listener, false); 354 rateElement.addEventListener('mouseup', listener, false); 355 volumeElement.addEventListener('mouseup', listener, false); 356 357 var sound = $('sound'); 358 var currentSound = localStorage['sound'] || DEFAULT_SOUND; 359 for (var i = 0; i < sound.options.length; i++) { 360 if (sound.options[i].value == currentSound) { 361 sound.selectedIndex = i; 362 break; 363 } 364 } 365 localStorage['sound'] = sound.options[sound.selectedIndex].value; 366 sound.addEventListener('change', function() { 367 localStorage['sound'] = sound.options[sound.selectedIndex].value; 368 }, false); 369 370 var playSoundButton = $('playsound'); 371 playSoundButton.addEventListener('click', function(evt) { 372 playSound(false); 373 }); 374 375 var playSpeechButton = $('playspeech'); 376 playSpeechButton.addEventListener('click', function(evt) { 377 speakPhraseWithCurrentTime(); 378 }); 379 380 var voice = $('voice'); 381 var voiceArray = []; 382 if (chrome && chrome.tts) { 383 chrome.tts.getVoices(function(va) { 384 voiceArray = va; 385 for (var i = 0; i < voiceArray.length; i++) { 386 var opt = document.createElement('option'); 387 var name = voiceArray[i].voiceName; 388 if (name == localStorage['voice']) { 389 opt.setAttribute('selected', ''); 390 } 391 opt.setAttribute('value', name); 392 opt.innerText = voiceArray[i].voiceName; 393 voice.appendChild(opt); 394 } 395 }); 396 } 397 voice.addEventListener('change', function() { 398 var i = voice.selectedIndex; 399 localStorage['voice'] = voiceArray[i].voiceName; 400 }, false); 401} 402 403document.addEventListener('DOMContentLoaded', load); 404