-
Notifications
You must be signed in to change notification settings - Fork 2k
/
ready.html
174 lines (155 loc) · 5.74 KB
/
ready.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
<!--
@license
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
-->
<script>
/**
* Provides `ready` lifecycle callback which is called parent to child.
*
* This can be useful in a number of cases. Here are some examples:
*
* Setting a default property value that should have a side effect: To ensure
* the side effect, an element must set a default value no sooner than
* `created`; however, since `created` flows child to host, this is before the
* host has had a chance to set a property value on the child. The `ready`
* method solves this problem since it's called host to child.
*
* Dom distribution: To support reprojection efficiently, it's important to
* distribute from host to child in one shot. The `attachedCallback` mostly
* goes in the desired order except for elements that are in dom to start; in
* this case, all children are attached before the host element. Ready also
* addresses this case since it's guaranteed to be called host to child.
*
* @class standard feature: ready
*/
(function() {
var baseAttachedCallback = Polymer.Base.attachedCallback;
Polymer.Base._addFeature({
_hostStack: [],
/**
* Lifecycle callback invoked when all local DOM children of this element
* have been created and "configured" with data bound from this element,
* attribute values, or defaults.
*
* @method ready
*/
ready: function() {
},
// NOTE: The concept of 'host' is overloaded. There are two different
// notions:
// 1. an element hosts the elements in its local dom root.
// 2. an element hosts the elements on which it configures data.
// Practially, these notions are almost always coincident.
// Some special elements like templates may separate them.
// In order not to over-emphaisize this technical difference, we expose
// one concept to the user and it maps to the dom-related meaning of host.
//
// set this element's `host` and push this element onto the `host`'s
// list of `client` elements
// this.dataHost reflects the parent element who manages
// any bindings for the element. Only elements originally
// stamped from Polymer templates have a dataHost, and this
// never changes
_registerHost: function(host) {
// NOTE: The `dataHost` of an element never changes.
this.dataHost = host = host ||
Polymer.Base._hostStack[Polymer.Base._hostStack.length-1];
if (host && host._clients) {
host._clients.push(this);
}
this._clients = null;
this._clientsReadied = false;
},
// establish this element as the current hosting element (allows
// any elements we stamp to easily set host to us).
_beginHosting: function() {
Polymer.Base._hostStack.push(this);
if (!this._clients) {
this._clients = [];
}
},
_endHosting: function() {
// this element is no longer the current hosting element
Polymer.Base._hostStack.pop();
},
_tryReady: function() {
this._readied = false;
if (this._canReady()) {
this._ready();
}
},
_canReady: function() {
return !this.dataHost || this.dataHost._clientsReadied;
},
_ready: function() {
// extension point
this._beforeClientsReady();
if (this._template) {
// prepare root
this._setupRoot();
this._readyClients();
}
this._clientsReadied = true;
this._clients = null;
// extension point
this._afterClientsReady();
this._readySelf();
},
_readyClients: function() {
// logically distribute self
this._beginDistribute();
// now fully prepare localChildren
var c$ = this._clients;
if (c$) {
for (var i=0, l= c$.length, c; (i<l) && (c=c$[i]); i++) {
c._ready();
}
}
// perform actual dom composition
this._finishDistribute();
// ensure elements are attached if they are in the dom at ready time
// helps normalize attached ordering between native and polyfill ce.
// TODO(sorvell): worth perf cost? ~6%
// if (!Polymer.Settings.useNativeCustomElements) {
// CustomElements.takeRecords();
// }
},
// mark readied and call `ready`
// note: called localChildren -> host
_readySelf: function() {
this._doBehavior('ready');
this._readied = true;
if (this._attachedPending) {
this._attachedPending = false;
this.attachedCallback();
}
},
// for system overriding
_beforeClientsReady: function() {},
_afterClientsReady: function() {},
_beforeAttached: function() {},
/**
* Polymer library implementation of the Custom Elements `attachedCallback`.
*
* Note, users should not override `attachedCallback`, and instead should
* implement the `attached` method on Polymer elements to receive
* attached-time callbacks.
*
* @protected
*/
attachedCallback: function() {
if (this._readied) {
this._beforeAttached();
baseAttachedCallback.call(this);
} else {
this._attachedPending = true;
}
}
});
})();
</script>