15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (c) 2012 The Chromium Authors. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * found in the LICENSE file. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) **/ 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checking for "chrome.app.runtime" availability allows this Chrome app code to 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be tested in a regular web page (like tests/manual.html). Checking for 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "chrome" and "chrome.app" availability further allows this code to be tested 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in non-Chrome browsers, which is useful for example to test touch support 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with a non-Chrome touch device. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if (typeof chrome !== 'undefined' && chrome.app && chrome.app.runtime) { 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var showCalculatorWindow = function () { 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome.app.window.create('calculator.html', { 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) defaultWidth: 243, minWidth: 243, maxWidth: 243, 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) defaultHeight: 380, minHeight: 380, maxHeight: 380, 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) id: 'calculator' 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, function(appWindow) { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) appWindow.contentWindow.onload = function() { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new Controller(new Model(9), new View(appWindow.contentWindow)); 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome.storage.local.set({windowVisible: true}); 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) appWindow.onClosed.addListener(function() { 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome.storage.local.set({windowVisible: false}); 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }); 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }); 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome.app.runtime.onLaunched.addListener(showCalculatorWindow); 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome.app.runtime.onRestarted.addListener(function() { 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome.storage.local.get('windowVisible', function(data) { 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (data.windowVisible) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) showCalculatorWindow(); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function Controller(model, view) { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.inputs = this.defineInputs_(); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.model = model; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.view = view; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.view.onButton = function(button) { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.handleInput_(this.inputs.byButton[button]); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }.bind(this); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.view.onKey = function(key) { 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.handleInput_(this.inputs.byKey[key]); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }.bind(this); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */ 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Controller.prototype.defineInputs_ = function() { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var inputs = {byButton: {}, byKey: {}}; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['zero'] = inputs.byKey['48'] = '0'; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['one'] = inputs.byKey['49'] = '1'; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['two'] = inputs.byKey['50'] = '2'; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['three'] = inputs.byKey['51'] = '3'; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['four'] = inputs.byKey['52'] = '4'; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['five'] = inputs.byKey['53'] = '5'; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['six'] = inputs.byKey['54'] = '6'; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['seven'] = inputs.byKey['55'] = '7'; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['eight'] = inputs.byKey['56'] = '8'; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['nine'] = inputs.byKey['57'] = '9'; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['point'] = inputs.byKey['190'] = '.'; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['add'] = inputs.byKey['^187'] = '+'; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['subtract'] = inputs.byKey['189'] = '-'; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['multiply'] = inputs.byKey['^56'] = '*'; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['divide'] = inputs.byKey['191'] = '/'; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['equals'] = inputs.byKey['187'] = inputs.byKey['13'] = '='; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['negate'] = inputs.byKey['32'] = '+ / -'; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['clear'] = inputs.byKey['67'] = 'AC'; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs.byButton['back'] = inputs.byKey['8'] = 'back'; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return inputs; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */ 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Controller.prototype.handleInput_ = function(input) { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var values, accumulator, operator, operand; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (input) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values = this.model.handle(input); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accumulator = values.accumulator; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) operator = values.operator; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) operand = values.operand; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (input === 'AC') { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.view.clearDisplay({operand: '0'}); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (input === '=') { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.view.addResults({accumulator: accumulator, operand: accumulator}); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (input.match(/^[+*/-]$/)) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.updateValues_({accumulator: accumulator}); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.view.addValues({operator: values.operator}); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!this.updateValues_({operator: operator, operand: operand})) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.view.addValues({operator: operator, operand: operand}); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */ 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Controller.prototype.updateValues_ = function(values) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Values which are "finalized" (which have an accumulator value) shouldn't 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and won't be updated, and this method will return false for them. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var before = this.view.getValues(); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var after = !before.accumulator ? values : {}; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.view.setValues({ 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accumulator: this.getUpdatedValue_(before, after, 'accumulator'), 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) operator: this.getUpdatedValue_(before, after, 'operator'), 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) operand: this.getUpdatedValue_(before, after, 'operand', !before.operator) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !before.accumulator; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */ 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Controller.prototype.getUpdatedValue_ = function(before, after, key, zero) { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var value = (typeof after[key] !== 'undefined') ? after[key] : before[key]; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return zero ? (value || '0') : value; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 116