blob: 2dfbbc3a0937070409825178a6d9a561e2e5954a [file] [log] [blame]
/**
@license
Copyright (c) 2017 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
*/
import { TemplateInstanceBase, templatize, modelForElement } from '../utils/templatize.js'; // eslint-disable-line no-unused-vars
/**
* @typedef {{
* _templatizerTemplate: HTMLTemplateElement,
* _parentModel: boolean,
* _instanceProps: Object,
* _forwardHostPropV2: Function,
* _notifyInstancePropV2: Function,
* ctor: TemplateInstanceBase
* }}
*/
let TemplatizerUser; // eslint-disable-line
/**
* The `Templatizer` behavior adds methods to generate instances of
* templates that are each managed by an anonymous `PropertyEffects`
* instance where data-bindings in the stamped template content are bound to
* accessors on itself.
*
* This behavior is provided in Polymer 2.x-3.x as a hybrid-element convenience
* only. For non-hybrid usage, the `Templatize` library
* should be used instead.
*
* Example:
*
* import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
* // Get a template from somewhere, e.g. light DOM
* let template = this.querySelector('template');
* // Prepare the template
* this.templatize(template);
* // Instance the template with an initial data model
* let instance = this.stamp({myProp: 'initial'});
* // Insert the instance's DOM somewhere, e.g. light DOM
* dom(this).appendChild(instance.root);
* // Changing a property on the instance will propagate to bindings
* // in the template
* instance.myProp = 'new value';
*
* Users of `Templatizer` may need to implement the following abstract
* API's to determine how properties and paths from the host should be
* forwarded into to instances:
*
* _forwardHostPropV2: function(prop, value)
*
* Likewise, users may implement these additional abstract API's to determine
* how instance-specific properties that change on the instance should be
* forwarded out to the host, if necessary.
*
* _notifyInstancePropV2: function(inst, prop, value)
*
* In order to determine which properties are instance-specific and require
* custom notification via `_notifyInstanceProp`, define an `_instanceProps`
* object containing keys for each instance prop, for example:
*
* _instanceProps: {
* item: true,
* index: true
* }
*
* Any properties used in the template that are not defined in _instanceProp
* will be forwarded out to the Templatize `owner` automatically.
*
* Users may also implement the following abstract function to show or
* hide any DOM generated using `stamp`:
*
* _showHideChildren: function(shouldHide)
*
* Note that some callbacks are suffixed with `V2` in the Polymer 2.x behavior
* as the implementations will need to differ from the callbacks required
* by the 1.x Templatizer API due to changes in the `TemplateInstance` API
* between versions 1.x and 2.x.
*
* @polymerBehavior
*/
export const Templatizer = {
/**
* Generates an anonymous `TemplateInstance` class (stored as `this.ctor`)
* for the provided template. This method should be called once per
* template to prepare an element for stamping the template, followed
* by `stamp` to create new instances of the template.
*
* @param {!HTMLTemplateElement} template Template to prepare
* @param {boolean=} mutableData When `true`, the generated class will skip
* strict dirty-checking for objects and arrays (always consider them to
* be "dirty"). Defaults to false.
* @return {void}
* @this {TemplatizerUser}
*/
templatize(template, mutableData) {
this._templatizerTemplate = template;
this.ctor = templatize(template, this, {
mutableData: Boolean(mutableData),
parentModel: this._parentModel,
instanceProps: this._instanceProps,
forwardHostProp: this._forwardHostPropV2,
notifyInstanceProp: this._notifyInstancePropV2
});
},
/**
* Creates an instance of the template prepared by `templatize`. The object
* returned is an instance of the anonymous class generated by `templatize`
* whose `root` property is a document fragment containing newly cloned
* template content, and which has property accessors corresponding to
* properties referenced in template bindings.
*
* @param {Object=} model Object containing initial property values to
* populate into the template bindings.
* @return {TemplateInstanceBase} Returns the created instance of
* the template prepared by `templatize`.
* @this {TemplatizerUser}
*/
stamp(model) {
return new this.ctor(model);
},
/**
* Returns the template "model" (`TemplateInstance`) associated with
* a given element, which serves as the binding scope for the template
* instance the element is contained in. A template model should be used
* to manipulate data associated with this template instance.
*
* @param {HTMLElement} el Element for which to return a template model.
* @return {TemplateInstanceBase} Model representing the binding scope for
* the element.
* @this {TemplatizerUser}
*/
modelForElement(el) {
return modelForElement(this._templatizerTemplate, el);
}
};