Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1181)

Unified Diff: pkg/template_binding/lib/js/node_bind.js

Issue 558673004: update polymer js to 0.4.0 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: review updates Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/template_binding/lib/js/microtask.js ('k') | pkg/template_binding/lib/js/observe.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/template_binding/lib/js/node_bind.js
diff --git a/pkg/template_binding/lib/js/node_bind.js b/pkg/template_binding/lib/js/node_bind.js
new file mode 100644
index 0000000000000000000000000000000000000000..270c557b185ea8a36c5cabb97affeb865322e483
--- /dev/null
+++ b/pkg/template_binding/lib/js/node_bind.js
@@ -0,0 +1,343 @@
+// Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+// This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+// The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+// The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+// Code distributed by Google as part of the polymer project is also
+// subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+
+(function(global) {
+ 'use strict';
+
+ var filter = Array.prototype.filter.call.bind(Array.prototype.filter);
+
+ function getTreeScope(node) {
+ while (node.parentNode) {
+ node = node.parentNode;
+ }
+
+ return typeof node.getElementById === 'function' ? node : null;
+ }
+
+ Node.prototype.bind = function(name, observable) {
+ console.error('Unhandled binding to Node: ', this, name, observable);
+ };
+
+ Node.prototype.bindFinished = function() {};
+
+ function updateBindings(node, name, binding) {
+ var bindings = node.bindings_;
+ if (!bindings)
+ bindings = node.bindings_ = {};
+
+ if (bindings[name])
+ binding[name].close();
+
+ return bindings[name] = binding;
+ }
+
+ function returnBinding(node, name, binding) {
+ return binding;
+ }
+
+ function sanitizeValue(value) {
+ return value == null ? '' : value;
+ }
+
+ function updateText(node, value) {
+ node.data = sanitizeValue(value);
+ }
+
+ function textBinding(node) {
+ return function(value) {
+ return updateText(node, value);
+ };
+ }
+
+ var maybeUpdateBindings = returnBinding;
+
+ Object.defineProperty(Platform, 'enableBindingsReflection', {
+ get: function() {
+ return maybeUpdateBindings === updateBindings;
+ },
+ set: function(enable) {
+ maybeUpdateBindings = enable ? updateBindings : returnBinding;
+ return enable;
+ },
+ configurable: true
+ });
+
+ Text.prototype.bind = function(name, value, oneTime) {
+ if (name !== 'textContent')
+ return Node.prototype.bind.call(this, name, value, oneTime);
+
+ if (oneTime)
+ return updateText(this, value);
+
+ var observable = value;
+ updateText(this, observable.open(textBinding(this)));
+ return maybeUpdateBindings(this, name, observable);
+ }
+
+ function updateAttribute(el, name, conditional, value) {
+ if (conditional) {
+ if (value)
+ el.setAttribute(name, '');
+ else
+ el.removeAttribute(name);
+ return;
+ }
+
+ el.setAttribute(name, sanitizeValue(value));
+ }
+
+ function attributeBinding(el, name, conditional) {
+ return function(value) {
+ updateAttribute(el, name, conditional, value);
+ };
+ }
+
+ Element.prototype.bind = function(name, value, oneTime) {
+ var conditional = name[name.length - 1] == '?';
+ if (conditional) {
+ this.removeAttribute(name);
+ name = name.slice(0, -1);
+ }
+
+ if (oneTime)
+ return updateAttribute(this, name, conditional, value);
+
+
+ var observable = value;
+ updateAttribute(this, name, conditional,
+ observable.open(attributeBinding(this, name, conditional)));
+
+ return maybeUpdateBindings(this, name, observable);
+ };
+
+ var checkboxEventType;
+ (function() {
+ // Attempt to feature-detect which event (change or click) is fired first
+ // for checkboxes.
+ var div = document.createElement('div');
+ var checkbox = div.appendChild(document.createElement('input'));
+ checkbox.setAttribute('type', 'checkbox');
+ var first;
+ var count = 0;
+ checkbox.addEventListener('click', function(e) {
+ count++;
+ first = first || 'click';
+ });
+ checkbox.addEventListener('change', function() {
+ count++;
+ first = first || 'change';
+ });
+
+ var event = document.createEvent('MouseEvent');
+ event.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false,
+ false, false, false, 0, null);
+ checkbox.dispatchEvent(event);
+ // WebKit/Blink don't fire the change event if the element is outside the
+ // document, so assume 'change' for that case.
+ checkboxEventType = count == 1 ? 'change' : first;
+ })();
+
+ function getEventForInputType(element) {
+ switch (element.type) {
+ case 'checkbox':
+ return checkboxEventType;
+ case 'radio':
+ case 'select-multiple':
+ case 'select-one':
+ return 'change';
+ case 'range':
+ if (/Trident|MSIE/.test(navigator.userAgent))
+ return 'change';
+ default:
+ return 'input';
+ }
+ }
+
+ function updateInput(input, property, value, santizeFn) {
+ input[property] = (santizeFn || sanitizeValue)(value);
+ }
+
+ function inputBinding(input, property, santizeFn) {
+ return function(value) {
+ return updateInput(input, property, value, santizeFn);
+ }
+ }
+
+ function noop() {}
+
+ function bindInputEvent(input, property, observable, postEventFn) {
+ var eventType = getEventForInputType(input);
+
+ function eventHandler() {
+ observable.setValue(input[property]);
+ observable.discardChanges();
+ (postEventFn || noop)(input);
+ Platform.performMicrotaskCheckpoint();
+ }
+ input.addEventListener(eventType, eventHandler);
+
+ return {
+ close: function() {
+ input.removeEventListener(eventType, eventHandler);
+ observable.close();
+ },
+
+ observable_: observable
+ }
+ }
+
+ function booleanSanitize(value) {
+ return Boolean(value);
+ }
+
+ // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
+ // Returns an array containing all radio buttons other than |element| that
+ // have the same |name|, either in the form that |element| belongs to or,
+ // if no form, in the document tree to which |element| belongs.
+ //
+ // This implementation is based upon the HTML spec definition of a
+ // "radio button group":
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state.html#radio-button-group
+ //
+ function getAssociatedRadioButtons(element) {
+ if (element.form) {
+ return filter(element.form.elements, function(el) {
+ return el != element &&
+ el.tagName == 'INPUT' &&
+ el.type == 'radio' &&
+ el.name == element.name;
+ });
+ } else {
+ var treeScope = getTreeScope(element);
+ if (!treeScope)
+ return [];
+ var radios = treeScope.querySelectorAll(
+ 'input[type="radio"][name="' + element.name + '"]');
+ return filter(radios, function(el) {
+ return el != element && !el.form;
+ });
+ }
+ }
+
+ function checkedPostEvent(input) {
+ // Only the radio button that is getting checked gets an event. We
+ // therefore find all the associated radio buttons and update their
+ // check binding manually.
+ if (input.tagName === 'INPUT' &&
+ input.type === 'radio') {
+ getAssociatedRadioButtons(input).forEach(function(radio) {
+ var checkedBinding = radio.bindings_.checked;
+ if (checkedBinding) {
+ // Set the value directly to avoid an infinite call stack.
+ checkedBinding.observable_.setValue(false);
+ }
+ });
+ }
+ }
+
+ HTMLInputElement.prototype.bind = function(name, value, oneTime) {
+ if (name !== 'value' && name !== 'checked')
+ return HTMLElement.prototype.bind.call(this, name, value, oneTime);
+
+ this.removeAttribute(name);
+ var sanitizeFn = name == 'checked' ? booleanSanitize : sanitizeValue;
+ var postEventFn = name == 'checked' ? checkedPostEvent : noop;
+
+ if (oneTime)
+ return updateInput(this, name, value, sanitizeFn);
+
+
+ var observable = value;
+ var binding = bindInputEvent(this, name, observable, postEventFn);
+ updateInput(this, name,
+ observable.open(inputBinding(this, name, sanitizeFn)),
+ sanitizeFn);
+
+ // Checkboxes may need to update bindings of other checkboxes.
+ return updateBindings(this, name, binding);
+ }
+
+ HTMLTextAreaElement.prototype.bind = function(name, value, oneTime) {
+ if (name !== 'value')
+ return HTMLElement.prototype.bind.call(this, name, value, oneTime);
+
+ this.removeAttribute('value');
+
+ if (oneTime)
+ return updateInput(this, 'value', value);
+
+ var observable = value;
+ var binding = bindInputEvent(this, 'value', observable);
+ updateInput(this, 'value',
+ observable.open(inputBinding(this, 'value', sanitizeValue)));
+ return maybeUpdateBindings(this, name, binding);
+ }
+
+ function updateOption(option, value) {
+ var parentNode = option.parentNode;;
+ var select;
+ var selectBinding;
+ var oldValue;
+ if (parentNode instanceof HTMLSelectElement &&
+ parentNode.bindings_ &&
+ parentNode.bindings_.value) {
+ select = parentNode;
+ selectBinding = select.bindings_.value;
+ oldValue = select.value;
+ }
+
+ option.value = sanitizeValue(value);
+
+ if (select && select.value != oldValue) {
+ selectBinding.observable_.setValue(select.value);
+ selectBinding.observable_.discardChanges();
+ Platform.performMicrotaskCheckpoint();
+ }
+ }
+
+ function optionBinding(option) {
+ return function(value) {
+ updateOption(option, value);
+ }
+ }
+
+ HTMLOptionElement.prototype.bind = function(name, value, oneTime) {
+ if (name !== 'value')
+ return HTMLElement.prototype.bind.call(this, name, value, oneTime);
+
+ this.removeAttribute('value');
+
+ if (oneTime)
+ return updateOption(this, value);
+
+ var observable = value;
+ var binding = bindInputEvent(this, 'value', observable);
+ updateOption(this, observable.open(optionBinding(this)));
+ return maybeUpdateBindings(this, name, binding);
+ }
+
+ HTMLSelectElement.prototype.bind = function(name, value, oneTime) {
+ if (name === 'selectedindex')
+ name = 'selectedIndex';
+
+ if (name !== 'selectedIndex' && name !== 'value')
+ return HTMLElement.prototype.bind.call(this, name, value, oneTime);
+
+ this.removeAttribute(name);
+
+ if (oneTime)
+ return updateInput(this, name, value);
+
+ var observable = value;
+ var binding = bindInputEvent(this, name, observable);
+ updateInput(this, name,
+ observable.open(inputBinding(this, name)));
+
+ // Option update events may need to access select bindings.
+ return updateBindings(this, name, binding);
+ }
+})(this);
« no previous file with comments | « pkg/template_binding/lib/js/microtask.js ('k') | pkg/template_binding/lib/js/observe.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698