OLD | NEW |
| (Empty) |
1 | |
2 (function() { | |
3 "use strict"; | |
4 /** | |
5 `Polymer.IronJsonpLibraryBehavior` loads a jsonp library. | |
6 Multiple components can request same library, only one copy will load. | |
7 | |
8 Some libraries require a specific global function be defined. | |
9 If this is the case, specify the `callbackName` property. | |
10 | |
11 You should use an HTML Import to load library dependencies | |
12 when possible instead of using this element. | |
13 | |
14 @hero hero.svg | |
15 @polymerBehavior | |
16 */ | |
17 Polymer.IronJsonpLibraryBehavior = { | |
18 | |
19 properties: { | |
20 /** | |
21 * True if library has been successfully loaded | |
22 */ | |
23 libraryLoaded: { | |
24 type: Boolean, | |
25 value: false, | |
26 notify: true, | |
27 readOnly: true | |
28 }, | |
29 /** | |
30 * Not null if library has failed to load | |
31 */ | |
32 libraryErrorMessage: { | |
33 type: String, | |
34 value: null, | |
35 notify: true, | |
36 readOnly: true | |
37 } | |
38 // Following properties are to be set by behavior users | |
39 /** | |
40 * Library url. Must contain string `%%callback_name%%`. | |
41 * | |
42 * `%%callback_name%%` is a placeholder for jsonp wrapper function name | |
43 * | |
44 * Ex: https://maps.googleapis.com/maps/api/js?callback=%%callback%% | |
45 * @property libraryUrl | |
46 */ | |
47 /** | |
48 * Set if library requires specific callback name. | |
49 * Name will be automatically generated if not set. | |
50 * @property callbackName | |
51 */ | |
52 /** | |
53 * name of event to be emitted when library loads. Standard is `api-load` | |
54 * @property notifyEvent | |
55 */ | |
56 /** | |
57 * event with name specified in `notifyEvent` attribute | |
58 * will fire upon successful load2 | |
59 * @event `notifyEvent` | |
60 */ | |
61 }, | |
62 | |
63 _libraryLoadCallback: function(err, result) { | |
64 if (err) { | |
65 console.warn("Library load failed:", err.message); | |
66 this._setLibraryErrorMessage(err.message); | |
67 } | |
68 else { | |
69 this._setLibraryErrorMessage(null); | |
70 this._setLibraryLoaded(true); | |
71 if (this.notifyEvent) | |
72 this.fire( this.notifyEvent, result); | |
73 } | |
74 }, | |
75 | |
76 /** loads the library, and fires this.notifyEvent upon completion */ | |
77 _loadLibrary: function() { | |
78 LoaderMap.require( | |
79 this.libraryUrl, | |
80 this._libraryLoadCallback.bind(this), | |
81 this.callbackName | |
82 ); | |
83 }, | |
84 | |
85 ready: function() { | |
86 this._loadLibrary(); | |
87 } | |
88 }; | |
89 | |
90 /* | |
91 * LoaderMap keeps track of all Loaders | |
92 */ | |
93 var LoaderMap = { | |
94 apiMap: {}, // { hash -> Loader } | |
95 | |
96 /* | |
97 * @param {function} notifyCallback loaded callback fn(result) | |
98 * @param {string} jsonpCallbackName name of jsonpcallback. If API does not
provide it, leave empty. Optional. | |
99 */ | |
100 require: function(url, notifyCallback, jsonpCallbackName) { | |
101 | |
102 // make hashable string form url | |
103 var name = this.nameFromUrl(url); | |
104 | |
105 // create a loader as needed | |
106 if (!this.apiMap[name]) | |
107 this.apiMap[name] = new Loader(name, url, jsonpCallbackName); | |
108 | |
109 // ask for notification | |
110 this.apiMap[name].requestNotify(notifyCallback); | |
111 }, | |
112 | |
113 nameFromUrl: function(url) { | |
114 return url.replace(/[\:\/\%\?\&\.\=\-\,]/g, '_') + '_api'; | |
115 } | |
116 }; | |
117 | |
118 var Loader = function(name, url, callbackName) { | |
119 this.notifiers = []; // array of notifyFn [ notifyFn* ] | |
120 | |
121 // callback is specified either as callback name | |
122 // or computed dynamically if url has callbackMacro in it | |
123 if (!callbackName) { | |
124 if (url.indexOf(this.callbackMacro) >= 0) { | |
125 callbackName = name + '_loaded'; | |
126 url = url.replace(this.callbackMacro, callbackName); | |
127 } else { | |
128 this.error = new Error('IronJsonpLibraryBehavior a %%callback_name%% par
ameter is required in libraryUrl'); | |
129 // TODO(sjmiles): we should probably fallback to listening to script.loa
d | |
130 return; | |
131 } | |
132 } | |
133 this.callbackName = callbackName; | |
134 window[this.callbackName] = this.success.bind(this); | |
135 this.addScript(url); | |
136 }; | |
137 | |
138 Loader.prototype = { | |
139 | |
140 callbackMacro: '%%callback%%', | |
141 loaded: false, | |
142 | |
143 addScript: function(src) { | |
144 var script = document.createElement('script'); | |
145 script.src = src; | |
146 script.onerror = this.handleError.bind(this); | |
147 var s = document.querySelector('script') || document.body; | |
148 s.parentNode.insertBefore(script, s); | |
149 this.script = script; | |
150 }, | |
151 | |
152 removeScript: function() { | |
153 if (this.script.parentNode) { | |
154 this.script.parentNode.removeChild(this.script); | |
155 } | |
156 this.script = null; | |
157 }, | |
158 | |
159 handleError: function(ev) { | |
160 this.error = new Error("Library failed to load"); | |
161 this.notifyAll(); | |
162 this.cleanup(); | |
163 }, | |
164 | |
165 success: function() { | |
166 this.loaded = true; | |
167 this.result = Array.prototype.slice.call(arguments); | |
168 this.notifyAll(); | |
169 this.cleanup(); | |
170 }, | |
171 | |
172 cleanup: function() { | |
173 delete window[this.callbackName]; | |
174 }, | |
175 | |
176 notifyAll: function(notifyCallback) { | |
177 this.notifiers.forEach( function(notifyCallback) { | |
178 notifyCallback(this.error, this.result); | |
179 }.bind(this)); | |
180 this.notifiers = []; | |
181 }, | |
182 | |
183 requestNotify: function(notifyCallback) { | |
184 if (this.loaded || this.error) { | |
185 notifyCallback( this.error, this.result); | |
186 } else { | |
187 this.notifiers.push(notifyCallback); | |
188 } | |
189 } | |
190 }; | |
191 })(); | |
192 | |
193 ; | |
194 Polymer({ | |
195 | |
196 is: 'iron-jsonp-library', | |
197 | |
198 behaviors: [ Polymer.IronJsonpLibraryBehavior ], | |
199 | |
200 properties: { | |
201 /** | |
202 * Library url. Must contain string `%%callback_name%%`. | |
203 * | |
204 * `%%callback_name%%` is a placeholder for jsonp wrapper function name | |
205 * | |
206 * Ex: https://maps.googleapis.com/maps/api/js?callback=%%callback%% | |
207 */ | |
208 libraryUrl: String, | |
209 /** | |
210 * Set if library requires specific callback name. | |
211 * Name will be automatically generated if not set. | |
212 */ | |
213 callbackName: String, | |
214 /** | |
215 * event with name specified in 'notifyEvent' attribute | |
216 * will fire upon successful load | |
217 */ | |
218 notifyEvent: String | |
219 /** | |
220 * event with name specified in 'notifyEvent' attribute | |
221 * will fire upon successful load | |
222 * @event `notifyEvent` | |
223 */ | |
224 | |
225 } | |
226 }); | |
227 | |
OLD | NEW |