/* * 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(scope) { /** * Common prototype for all Polymer Elements. * * @class polymer-base * @homepage polymer.github.io */ var base = { /** * Tags this object as the canonical Base prototype. * * @property PolymerBase * @type boolean * @default true */ PolymerBase: true, /** * Debounce signals. * * Call `job` to defer a named signal, and all subsequent matching signals, * until a wait time has elapsed with no new signal. * * debouncedClickAction: function(e) { * // processClick only when it's been 100ms since the last click * this.job('click', function() { * this.processClick; * }, 100); * } * * @method job * @param String {String} job A string identifier for the job to debounce. * @param Function {Function} callback A function that is called (with `this` context) when the wait time elapses. * @param Number {Number} wait Time in milliseconds (ms) after the last signal that must elapse before invoking `callback` * @type Handle */ job: function(job, callback, wait) { if (typeof job === 'string') { var n = '___' + job; this[n] = Polymer.job.call(this, this[n], callback, wait); } else { // TODO(sjmiles): suggest we deprecate this call signature return Polymer.job.call(this, job, callback, wait); } }, /** * Invoke a superclass method. * * Use `super()` to invoke the most recently overridden call to the * currently executing function. * * To pass arguments through, use the literal `arguments` as the parameter * to `super()`. * * nextPageAction: function(e) { * // invoke the superclass version of `nextPageAction` * this.super(arguments); * } * * To pass custom arguments, arrange them in an array. * * appendSerialNo: function(value, serial) { * // prefix the superclass serial number with our lot # before * // invoking the superlcass * return this.super([value, this.lotNo + serial]) * } * * @method super * @type Any * @param {args) An array of arguments to use when calling the superclass method, or null. */ super: Polymer.super, /** * Lifecycle method called when the element is instantiated. * * Override `created` to perform custom create-time tasks. No need to call * super-class `created` unless you are extending another Polymer element. * Created is called before the element creates `shadowRoot` or prepares * data-observation. * * @method created * @type void */ created: function() { }, /** * Lifecycle method called when the element has populated it's `shadowRoot`, * prepared data-observation, and made itself ready for API interaction. * * @method ready * @type void */ ready: function() { }, /** * Low-level lifecycle method called as part of standard Custom Elements * operation. Polymer implements this method to provide basic default * functionality. For custom create-time tasks, implement `created` * instead, which is called immediately after `createdCallback`. * * @method createdCallback */ createdCallback: function() { if (this.templateInstance && this.templateInstance.model) { console.warn('Attributes on ' + this.localName + ' were data bound ' + 'prior to Polymer upgrading the element. This may result in ' + 'incorrect binding types.'); } this.created(); this.prepareElement(); if (!this.ownerDocument.isStagingDocument) { this.makeElementReady(); } }, // system entry point, do not override prepareElement: function() { if (this._elementPrepared) { console.warn('Element already prepared', this.localName); return; } this._elementPrepared = true; // storage for shadowRoots info this.shadowRoots = {}; // install property observers this.createPropertyObserver(); this.openPropertyObserver(); // install boilerplate attributes this.copyInstanceAttributes(); // process input attributes this.takeAttributes(); // add event listeners this.addHostListeners(); }, // system entry point, do not override makeElementReady: function() { if (this._readied) { return; } this._readied = true; this.createComputedProperties(); this.parseDeclarations(this.__proto__); // NOTE: Support use of the `unresolved` attribute to help polyfill // custom elements' `:unresolved` feature. this.removeAttribute('unresolved'); // user entry point this.ready(); }, /** * Low-level lifecycle method called as part of standard Custom Elements * operation. Polymer implements this method to provide basic default * functionality. For custom tasks in your element, implement `attributeChanged` * instead, which is called immediately after `attributeChangedCallback`. * * @method attributeChangedCallback */ attributeChangedCallback: function(name, oldValue) { // TODO(sjmiles): adhoc filter if (name !== 'class' && name !== 'style') { this.attributeToProperty(name, this.getAttribute(name)); } if (this.attributeChanged) { this.attributeChanged.apply(this, arguments); } }, /** * Low-level lifecycle method called as part of standard Custom Elements * operation. Polymer implements this method to provide basic default * functionality. For custom create-time tasks, implement `attached` * instead, which is called immediately after `attachedCallback`. * * @method attachedCallback */ attachedCallback: function() { // when the element is attached, prevent it from unbinding. this.cancelUnbindAll(); // invoke user action if (this.attached) { this.attached(); } if (!this.hasBeenAttached) { this.hasBeenAttached = true; if (this.domReady) { this.async('domReady'); } } }, /** * Implement to access custom elements in dom descendants, ancestors, * or siblings. Because custom elements upgrade in document order, * elements accessed in `ready` or `attached` may not be upgraded. When * `domReady` is called, all registered custom elements are guaranteed * to have been upgraded. * * @method domReady */ /** * Low-level lifecycle method called as part of standard Custom Elements * operation. Polymer implements this method to provide basic default * functionality. For custom create-time tasks, implement `detached` * instead, which is called immediately after `detachedCallback`. * * @method detachedCallback */ detachedCallback: function() { if (!this.preventDispose) { this.asyncUnbindAll(); } // invoke user action if (this.detached) { this.detached(); } // TODO(sorvell): bc if (this.leftView) { this.leftView(); } }, /** * Walks the prototype-chain of this element and allows specific * classes a chance to process static declarations. * * In particular, each polymer-element has it's own `template`. * `parseDeclarations` is used to accumulate all element `template`s * from an inheritance chain. * * `parseDeclaration` static methods implemented in the chain are called * recursively, oldest first, with the `` associated * with the current prototype passed as an argument. * * An element may override this method to customize shadow-root generation. * * @method parseDeclarations */ parseDeclarations: function(p) { if (p && p.element) { this.parseDeclarations(p.__proto__); p.parseDeclaration.call(this, p.element); } }, /** * Perform init-time actions based on static information in the * `` instance argument. * * For example, the standard implementation locates the template associated * with the given `` and stamps it into a shadow-root to * implement shadow inheritance. * * An element may override this method for custom behavior. * * @method parseDeclaration */ parseDeclaration: function(elementElement) { var template = this.fetchTemplate(elementElement); if (template) { var root = this.shadowFromTemplate(template); this.shadowRoots[elementElement.name] = root; } }, /** * Given a ``, find an associated template (if any) to be * used for shadow-root generation. * * An element may override this method for custom behavior. * * @method fetchTemplate */ fetchTemplate: function(elementElement) { return elementElement.querySelector('template'); }, /** * Create a shadow-root in this host and stamp `template` as it's * content. * * An element may override this method for custom behavior. * * @method shadowFromTemplate */ shadowFromTemplate: function(template) { if (template) { // make a shadow root var root = this.createShadowRoot(); // stamp template // which includes parsing and applying MDV bindings before being // inserted (to avoid {{}} in attribute values) // e.g. to prevent from generating a 404. var dom = this.instanceTemplate(template); // append to shadow dom root.appendChild(dom); // perform post-construction initialization tasks on shadow root this.shadowRootReady(root, template); // return the created shadow root return root; } }, // utility function that stamps a