Home | History | Annotate | Download | only in app
      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.
     12 if (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 
     39 function 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 */
     52 Controller.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 */
     77 Controller.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 */
     98 Controller.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 */
    112 Controller.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