This repository has been archived by the owner on Mar 13, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 38
/
mdv.js
123 lines (109 loc) · 3.79 KB
/
mdv.js
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
/*
* Copyright 2013 The Polymer Authors. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
(function(scope) {
// imports
var log = window.logFlags || 0;
var events = scope.api.instance.events;
// expressionista
// TODO(sorvell): we're patching the syntax while evaluating
// event bindings. we'll move this to a better spot when that's done.
var _prepareBinding = PolymerExpressions.prototype.prepareBinding;
// <[node] [name] = {{path}}>
PolymerExpressions.prototype.prepareBinding = function(path, name, node) {
// if not an event, delegate to the standard syntax
return events.prepareBinding(path, name, node)
|| _prepareBinding.call(this, path, name, node);
};
var syntax = new PolymerExpressions();
// element api supporting mdv
var mdv = {
syntax: syntax,
instanceTemplate: function(template) {
return template.createInstance(this, this.syntax);
},
bind: function(name, observable) {
// note: binding is a prepare signal. This allows us to be sure that any
// property changes that occur as a result of binding will be observed.
if (!this._elementPrepared) {
this.prepareElement();
}
var property = this.propertyForAttribute(name);
if (!property) {
// TODO(sjmiles): this mixin method must use the special form
// of `super` installed by `mixinMethod` in declaration/prototype.js
return this.mixinSuper(arguments);
} else {
// clean out the closets
this.unbind(name);
// use n-way Polymer binding
var observer = this.bindProperty(property, observable);
// stick path on observer so it's available via this.bindings
observer.path = observable.path_;
// reflect bound property to attribute when binding
// to ensure binding is not left on attribute if property
// does not update due to not changing.
this.reflectPropertyToAttribute(property);
return this.bindings[name] = observer;
}
},
asyncUnbindAll: function() {
if (!this._unbound) {
log.unbind && console.log('[%s] asyncUnbindAll', this.localName);
this._unbindAllJob = this.job(this._unbindAllJob, this.unbindAll, 0);
}
},
unbindAll: function() {
if (!this._unbound) {
this.unbindAllProperties();
this.super();
// unbind shadowRoot
var root = this.shadowRoot;
while (root) {
unbindNodeTree(root);
root = root.olderShadowRoot;
}
this._unbound = true;
}
},
cancelUnbindAll: function(preventCascade) {
if (this._unbound) {
log.unbind && console.warn('[%s] already unbound, cannot cancel unbindAll', this.localName);
return;
}
log.unbind && console.log('[%s] cancelUnbindAll', this.localName);
if (this._unbindAllJob) {
this._unbindAllJob = this._unbindAllJob.stop();
}
// cancel unbinding our shadow tree iff we're not in the process of
// cascading our tree (as we do, for example, when the element is inserted).
if (!preventCascade) {
forNodeTree(this.shadowRoot, function(n) {
if (n.cancelUnbindAll) {
n.cancelUnbindAll();
}
});
}
}
};
function unbindNodeTree(node) {
forNodeTree(node, _nodeUnbindAll);
}
function _nodeUnbindAll(node) {
node.unbindAll();
}
function forNodeTree(node, callback) {
if (node) {
callback(node);
for (var child = node.firstChild; child; child = child.nextSibling) {
forNodeTree(child, callback);
}
}
}
var mustachePattern = /\{\{([^{}]*)}}/;
// exports
scope.bindPattern = mustachePattern;
scope.api.instance.mdv = mdv;
})(Polymer);