1/** 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 * Use of this source code is governed by a BSD-style license that can be 4 * found in the LICENSE file. 5 **/ 6 7// Checking for "chrome.app.runtime" availability allows this Chrome app code to 8// be tested in a regular web page (like tests/manual.html). Checking for 9// "chrome" and "chrome.app" availability further allows this code to be tested 10// in non-Chrome browsers, which is useful for example to test touch support 11// with a non-Chrome touch device. 12if (typeof chrome !== 'undefined' && chrome.app && chrome.app.runtime) { 13 var showCalculatorWindow = function () { 14 chrome.app.window.create('calculator.html', { 15 defaultWidth: 243, minWidth: 243, maxWidth: 243, 16 defaultHeight: 380, minHeight: 380, maxHeight: 380, 17 id: 'calculator' 18 }, function(appWindow) { 19 appWindow.contentWindow.onload = function() { 20 new Controller(new Model(9), new View(appWindow.contentWindow)); 21 }; 22 23 chrome.storage.local.set({windowVisible: true}); 24 appWindow.onClosed.addListener(function() { 25 chrome.storage.local.set({windowVisible: false}); 26 }); 27 }); 28 } 29 30 chrome.app.runtime.onLaunched.addListener(showCalculatorWindow); 31 chrome.app.runtime.onRestarted.addListener(function() { 32 chrome.storage.local.get('windowVisible', function(data) { 33 if (data.windowVisible) 34 showCalculatorWindow(); 35 }); 36 }); 37} 38 39function Controller(model, view) { 40 this.inputs = this.defineInputs_(); 41 this.model = model; 42 this.view = view; 43 this.view.onButton = function(button) { 44 this.handleInput_(this.inputs.byButton[button]); 45 }.bind(this); 46 this.view.onKey = function(key) { 47 this.handleInput_(this.inputs.byKey[key]); 48 }.bind(this); 49} 50 51/** @private */ 52Controller.prototype.defineInputs_ = function() { 53 var inputs = {byButton: {}, byKey: {}}; 54 inputs.byButton['zero'] = inputs.byKey['48'] = '0'; 55 inputs.byButton['one'] = inputs.byKey['49'] = '1'; 56 inputs.byButton['two'] = inputs.byKey['50'] = '2'; 57 inputs.byButton['three'] = inputs.byKey['51'] = '3'; 58 inputs.byButton['four'] = inputs.byKey['52'] = '4'; 59 inputs.byButton['five'] = inputs.byKey['53'] = '5'; 60 inputs.byButton['six'] = inputs.byKey['54'] = '6'; 61 inputs.byButton['seven'] = inputs.byKey['55'] = '7'; 62 inputs.byButton['eight'] = inputs.byKey['56'] = '8'; 63 inputs.byButton['nine'] = inputs.byKey['57'] = '9'; 64 inputs.byButton['point'] = inputs.byKey['190'] = '.'; 65 inputs.byButton['add'] = inputs.byKey['^187'] = '+'; 66 inputs.byButton['subtract'] = inputs.byKey['189'] = '-'; 67 inputs.byButton['multiply'] = inputs.byKey['^56'] = '*'; 68 inputs.byButton['divide'] = inputs.byKey['191'] = '/'; 69 inputs.byButton['equals'] = inputs.byKey['187'] = inputs.byKey['13'] = '='; 70 inputs.byButton['negate'] = inputs.byKey['32'] = '+ / -'; 71 inputs.byButton['clear'] = inputs.byKey['67'] = 'AC'; 72 inputs.byButton['back'] = inputs.byKey['8'] = 'back'; 73 return inputs; 74}; 75 76/** @private */ 77Controller.prototype.handleInput_ = function(input) { 78 var values, accumulator, operator, operand; 79 if (input) { 80 values = this.model.handle(input); 81 accumulator = values.accumulator; 82 operator = values.operator; 83 operand = values.operand; 84 if (input === 'AC') { 85 this.view.clearDisplay({operand: '0'}); 86 } else if (input === '=') { 87 this.view.addResults({accumulator: accumulator, operand: accumulator}); 88 } else if (input.match(/^[+*/-]$/)) { 89 this.updateValues_({accumulator: accumulator}); 90 this.view.addValues({operator: values.operator}); 91 } else if (!this.updateValues_({operator: operator, operand: operand})) { 92 this.view.addValues({operator: operator, operand: operand}); 93 } 94 } 95}; 96 97/** @private */ 98Controller.prototype.updateValues_ = function(values) { 99 // Values which are "finalized" (which have an accumulator value) shouldn't 100 // and won't be updated, and this method will return false for them. 101 var before = this.view.getValues(); 102 var after = !before.accumulator ? values : {}; 103 this.view.setValues({ 104 accumulator: this.getUpdatedValue_(before, after, 'accumulator'), 105 operator: this.getUpdatedValue_(before, after, 'operator'), 106 operand: this.getUpdatedValue_(before, after, 'operand', !before.operator) 107 }); 108 return !before.accumulator; 109} 110 111/** @private */ 112Controller.prototype.getUpdatedValue_ = function(before, after, key, zero) { 113 var value = (typeof after[key] !== 'undefined') ? after[key] : before[key]; 114 return zero ? (value || '0') : value; 115} 116