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