OLD | NEW |
| (Empty) |
1 <!-- | |
2 Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
3 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | |
4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | |
5 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | |
6 Code distributed by Google as part of the polymer project is also | |
7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | |
8 --> | |
9 <link rel="import" href="../polymer/polymer.html"> | |
10 | |
11 <!-- | |
12 Supports sharing a JSONP-based JavaScript library. | |
13 | |
14 <core-shared-lib on-core-shared-lib-load="{{load}}" url="https://apis.google
.com/js/plusone.js?onload=%%callback%%"> | |
15 | |
16 Multiple components can request a library using a `core-shared-lib` component an
d only one copy of that library will | |
17 loaded from the network. | |
18 | |
19 Currently, the library must support JSONP to work as a shared-lib. | |
20 | |
21 Some libraries require a specific global function be defined. If this is the cas
e, specify the `callbackName` property. | |
22 | |
23 Where possible, you should use an HTML Import to load library dependencies. Rath
er than using this element, | |
24 create an import (`<link rel="import" href="lib.html">`) that wraps loading the
.js file: | |
25 | |
26 lib.html: | |
27 | |
28 <script src="lib.js"></script> | |
29 | |
30 @group Polymer Core Elements | |
31 @element core-shared-lib | |
32 --> | |
33 <polymer-element name="core-shared-lib" attributes="url notifyEvent callbackName
"> | |
34 <script> | |
35 (function() { | |
36 | |
37 Polymer({ | |
38 | |
39 notifyEvent: 'core-shared-lib-load', | |
40 | |
41 ready: function() { | |
42 if (!this.url && this.defaultUrl) { | |
43 this.url = this.defaultUrl; | |
44 } | |
45 }, | |
46 | |
47 urlChanged: function() { | |
48 require(this.url, this, this.callbackName); | |
49 }, | |
50 | |
51 provide: function() { | |
52 this.async('notify'); | |
53 }, | |
54 | |
55 notify: function() { | |
56 this.fire(this.notifyEvent, arguments); | |
57 } | |
58 | |
59 }); | |
60 | |
61 var apiMap = {}; | |
62 | |
63 function require(url, notifiee, callbackName) { | |
64 // make hashable string form url | |
65 var name = nameFromUrl(url); | |
66 // lookup existing loader instance | |
67 var loader = apiMap[name]; | |
68 // create a loader as needed | |
69 if (!loader) { | |
70 loader = apiMap[name] = new Loader(name, url, callbackName); | |
71 } | |
72 loader.requestNotify(notifiee); | |
73 } | |
74 | |
75 function nameFromUrl(url) { | |
76 return url.replace(/[\:\/\%\?\&\.\=\-\,]/g, '_') + '_api'; | |
77 } | |
78 | |
79 var Loader = function(name, url, callbackName) { | |
80 this.instances = []; | |
81 this.callbackName = callbackName; | |
82 if (this.callbackName) { | |
83 window[this.callbackName] = this.success.bind(this); | |
84 } else { | |
85 if (url.indexOf(this.callbackMacro) >= 0) { | |
86 this.callbackName = name + '_loaded'; | |
87 window[this.callbackName] = this.success.bind(this); | |
88 url = url.replace(this.callbackMacro, this.callbackName); | |
89 } else { | |
90 // TODO(sjmiles): we should probably fallback to listening to script.loa
d | |
91 throw 'core-shared-api: a %%callback%% parameter is required in the API
url'; | |
92 } | |
93 } | |
94 // | |
95 this.addScript(url); | |
96 }; | |
97 | |
98 Loader.prototype = { | |
99 | |
100 callbackMacro: '%%callback%%', | |
101 loaded: false, | |
102 | |
103 addScript: function(src) { | |
104 var script = document.createElement('script'); | |
105 script.src = src; | |
106 script.onerror = this.error.bind(this); | |
107 var s = document.querySelector('script'); | |
108 s.parentNode.insertBefore(script, s); | |
109 this.script = script; | |
110 }, | |
111 | |
112 removeScript: function() { | |
113 if (this.script.parentNode) { | |
114 this.script.parentNode.removeChild(this.script); | |
115 } | |
116 this.script = null; | |
117 }, | |
118 | |
119 error: function() { | |
120 this.cleanup(); | |
121 }, | |
122 | |
123 success: function() { | |
124 this.loaded = true; | |
125 this.cleanup(); | |
126 this.result = Array.prototype.slice.call(arguments); | |
127 this.instances.forEach(this.provide, this); | |
128 this.instances = null; | |
129 }, | |
130 | |
131 cleanup: function() { | |
132 delete window[this.callbackName]; | |
133 }, | |
134 | |
135 provide: function(instance) { | |
136 instance.notify(instance, this.result); | |
137 }, | |
138 | |
139 requestNotify: function(instance) { | |
140 if (this.loaded) { | |
141 this.provide(instance); | |
142 } else { | |
143 this.instances.push(instance); | |
144 } | |
145 } | |
146 | |
147 }; | |
148 | |
149 })(); | |
150 </script> | |
151 </polymer-element> | |
OLD | NEW |