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)function View(window) {
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.display = window.document.querySelector('#calculator-display');
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.buttons = window.document.querySelectorAll('#calculator-buttons button');
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window.addEventListener('keydown', this.handleKey_.bind(this));
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Array.prototype.forEach.call(this.buttons, function(button) {
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    button.addEventListener('click', this.handleClick_.bind(this));
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    button.addEventListener('mousedown', this.handleMouse_.bind(this));
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    button.addEventListener('touchstart', this.handleTouch_.bind(this));
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    button.addEventListener('touchmove', this.handleTouch_.bind(this));
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    button.addEventListener('touchend', this.handleTouchEnd_.bind(this));
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    button.addEventListener('touchcancel', this.handleTouchEnd_.bind(this));
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }, this);
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.clearDisplay = function(values) {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.display.innerHTML = '';
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.addValues(values);
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.addResults = function(values) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.appendChild_(this.display, null, 'div', 'hr');
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.addValues(values);
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.addValues = function(values) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var equation = this.makeElement_('div', 'equation');
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.appendChild_(equation, null, 'span', 'accumulator', values.accumulator);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.appendChild_(equation, null, 'span', 'operation');
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.appendChild_(equation, '.operation', 'span', 'operator');
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.appendChild_(equation, '.operation', 'span', 'operand', values.operand);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.appendChild_(equation, '.operator', 'div', 'spacer');
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.appendChild_(equation, '.operator', 'div', 'value', values.operator);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.setAttribute_(equation, '.accumulator', 'aria-hidden', 'true');
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.display.appendChild(equation).scrollIntoView();
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.setValues = function(values) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var equation = this.display.lastElementChild;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.setContent_(equation, '.accumulator', values.accumulator || '');
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.setContent_(equation, '.operator .value', values.operator || '');
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.setContent_(equation, '.operand', values.operand || '');
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.getValues = function() {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var equation = this.display.lastElementChild;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    accumulator: this.getContent_(equation, '.accumulator') || null,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    operator: this.getContent_(equation, '.operator .value') || null,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    operand: this.getContent_(equation, '.operand') || null,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.handleKey_ = function(event) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.onKey.call(this, event.shiftKey ? ('^' + event.which) : event.which);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.handleClick_ = function(event) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.onButton.call(this, event.target.dataset.button)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.handleMouse_ = function(event) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.target.setAttribute('data-active', 'mouse');
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.handleTouch_ = function(event) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event.preventDefault();
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.handleTouchChange_(event.touches[0]);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.handleTouchEnd_ = function(event) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.handleTouchChange_(null);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.handleTouchChange_ = function(location) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var previous = this.touched;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!this.isInButton_(previous, location)) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.touched = this.findButtonContaining_(location);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (previous)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      previous.removeAttribute('data-active');
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (this.touched) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.touched.setAttribute('data-active', 'touch');
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.onButton.call(this, this.touched.dataset.button);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.findButtonContaining_ = function(location) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var found;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (var i = 0; location && i < this.buttons.length && !found; ++i) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (this.isInButton_(this.buttons[i], location))
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      found = this.buttons[i];
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return found;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.isInButton_ = function(button, location) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var bounds = location && button && button.getClientRects()[0];
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var x = bounds && location.clientX;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var y = bounds && location.clientY;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var x1 = bounds && bounds.left;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var x2 = bounds && bounds.right;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var y1 = bounds && bounds.top;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var y2 = bounds && bounds.bottom;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (bounds && x >= x1 && x < x2 && y >= y1 && y < y2);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.makeElement_ = function(tag, classes, content) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var element = this.display.ownerDocument.createElement(tag);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  element.setAttribute('class', classes);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  element.textContent = content || '';
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return element;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.appendChild_ = function(root, selector, tag, classes, content) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var parent = (root && selector) ? root.querySelector(selector) : root;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parent.appendChild(this.makeElement_(tag, classes, content));
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.setAttribute_ = function(root, selector, name, value) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var element = root && root.querySelector(selector);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (element)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    element.setAttribute(name, value);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.setContent_ = function(root, selector, content) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var element = root && root.querySelector(selector);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (element)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    element.textContent = content || '';
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @private */
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)View.prototype.getContent_ = function(root, selector) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var element = root && root.querySelector(selector);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return element ? element.textContent : null;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
154