-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathpatch-polymer.html
185 lines (152 loc) · 5.27 KB
/
patch-polymer.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
175
176
177
178
179
180
181
182
183
184
185
<script>
"use strict";
/*
Overwrite the Collection.add and .initMap methods.
Here we provide the option of using "intrusive" keys
for objects..although it's not fully intrusive, because
the non-intrusive version still exists and is used by
the Collection class itself.
Objects with a ._pkey=null property will have it set to the
key when inserted into the collection, and when the
collection is initialized.
Note that if the object is in multiple collections only the
first insertion will set the pkey, because after that the
value will no longer be null. It is up to the user to be
aware of this and use it appropriately.
*/
Polymer.Collection.prototype.add = function(item) {
var key = this.store.push(item) - 1;
if (item && typeof item == 'object') {
this.omap.set(item, key);
item._pkey === null && (item._pkey = '#' + key); // << this is extra
} else {
this.pmap[item] = key;
}
return '#' + key;
};
Polymer.Collection.prototype.initMap = function() {
var omap = this.omap = new WeakMap();
var pmap = this.pmap = {};
var s = this.store;
for (var i=0; i<s.length; i++) {
var item = s[i];
if (item && typeof item == 'object') {
omap.set(item, i);
item._pkey === null && (item._pkey = '#' + i); // << this is extra
} else {
pmap[item] = i;
}
}
};
/*
The following is an important hack which allows you to avoid doing expensive
notifications if you really have to.
It is to be used when an object has various properties that are known to only
be of interest to a very specific set of elements.
The "target" elements should use the Polymer.ShortcutNotifyTargetBehavior(),
behavior factory function, passing in an array of path strings.
For example:
<dom-module id="lovely-view">
<template>
some_property is: [[my_model.some_property]]
</template>
<script>
Polymer({
is: 'lovely-view',
behaviors: [
Polymer.ShortcutNotifyTargetBehavior(['my_model'])
],
properties: {
my_model: {
// whatever
}
}
});
< /script>
</dom-module>
The "notifiyer" element should use the Polymer.ShortcutNotifyerBehavior,
and then replace calls like this:
this.notifyPath('some_array.#42.some_property', mutated_object.some_property)
with this:
this.shortcutNotify('some_property', mutated_object.some_property, mutated_object);
Note how here we only use the final suffix for the path, and we provide the actual
object as the final argument.
I think this mechanism supports multi-part paths, but I haven't tested it.
Using this approach very much goes against the Polymeric way of doing things,
but it's far easier to implement than something less hacky (I did try something
much fancier, but ran in to all kinds of complciations and decided to abandon the effort.)
*/
(function(){
let targetsForModel = new WeakMap();
let OLD_MODEL_PREFIX = '_oldModelFor_';
Polymer.ShortcutNotifyTargetBehavior = function(paths) {
return {
observers: (function(){
let observers = [];
for(let [ii, path] of paths.entries()){
observers.push('_updateShorcutMapping("' + path + '", ' + path + ')');
}
return observers;
})(),
_updateShorcutMapping: function(path, newModel){
this._removeAsTargetForModel(path);
this._addAsTargetForModel(path, newModel);
},
attached: function(){
this._isAttached = true;
for(let path of paths){
this._addAsTargetForModel(path, this.get(path));
}
},
detached: function(){
this._isAttached = false;
for(let path of paths){
this._removeAsTargetForModel(path);
}
},
_removeAsTargetForModel: function(path){
let oldModel = this[OLD_MODEL_PREFIX + path];
let oldTargets;
if(oldModel && (typeof oldModel === "object") && (oldTargets=targetsForModel.get(oldModel))){
let oldIdx = -1;
for(let [ii, target] of oldTargets.entries()){
if(target.el === this){
oldIdx = ii;
break;
}
}
if(oldIdx !== -1){
if(oldTargets.length === 1){
targetsForModel.delete(oldModel); // this was the only remaining target for the given model
} else {
oldTargets.splice(oldIdx, 1); // there are still other targets observing this model
}
}
}
},
_addAsTargetForModel: function(path, newModel){
if(this._isAttached && newModel && (typeof newModel === "object")){
let newTargets = targetsForModel.get(newModel);
if(!newTargets){
newTargets = [];
targetsForModel.set(newModel, newTargets);
}
newTargets.push({
el: this,
prefix: path
});
this[OLD_MODEL_PREFIX + path] = newModel;
}
}
}
};
Polymer.ShortcutNotifyerBehavior = {
shortcutNotify: function(path, value, model){
let targets = targetsForModel.get(model) || [];
for(let target of targets){
target.el.notifyPath(target.prefix + "." + path, value, true);
}
}
};
})();
</script>