• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!--
2@license
3Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7Code distributed by Google as part of the polymer project is also
8subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9-->
10
11<link rel="import" href="../polymer/polymer.html">
12
13<!--
14`iron-meta` is a generic element you can use for sharing information across the DOM tree.
15It uses [monostate pattern](http://c2.com/cgi/wiki?MonostatePattern) such that any
16instance of iron-meta has access to the shared
17information. You can use `iron-meta` to share whatever you want (or create an extension
18[like x-meta] for enhancements).
19
20The `iron-meta` instances containing your actual data can be loaded in an import,
21or constructed in any way you see fit. The only requirement is that you create them
22before you try to access them.
23
24Examples:
25
26If I create an instance like this:
27
28    <iron-meta key="info" value="foo/bar"></iron-meta>
29
30Note that value="foo/bar" is the metadata I've defined. I could define more
31attributes or use child nodes to define additional metadata.
32
33Now I can access that element (and it's metadata) from any iron-meta instance
34via the byKey method, e.g.
35
36    meta.byKey('info');
37
38Pure imperative form would be like:
39
40    document.createElement('iron-meta').byKey('info');
41
42Or, in a Polymer element, you can include a meta in your template:
43
44    <iron-meta id="meta"></iron-meta>
45    ...
46    this.$.meta.byKey('info');
47
48@group Iron Elements
49@demo demo/index.html
50@hero hero.svg
51@element iron-meta
52-->
53
54<script>
55
56  (function() {
57
58    // monostate data
59    var metaDatas = {};
60    var metaArrays = {};
61    var singleton = null;
62
63    Polymer.IronMeta = Polymer({
64
65      is: 'iron-meta',
66
67      properties: {
68
69        /**
70         * The type of meta-data.  All meta-data of the same type is stored
71         * together.
72         */
73        type: {
74          type: String,
75          value: 'default',
76          observer: '_typeChanged'
77        },
78
79        /**
80         * The key used to store `value` under the `type` namespace.
81         */
82        key: {
83          type: String,
84          observer: '_keyChanged'
85        },
86
87        /**
88         * The meta-data to store or retrieve.
89         */
90        value: {
91          type: Object,
92          notify: true,
93          observer: '_valueChanged'
94        },
95
96        /**
97         * If true, `value` is set to the iron-meta instance itself.
98         */
99         self: {
100          type: Boolean,
101          observer: '_selfChanged'
102        },
103
104        /**
105         * Array of all meta-data values for the given type.
106         */
107        list: {
108          type: Array,
109          notify: true
110        }
111
112      },
113
114      hostAttributes: {
115        hidden: true
116      },
117
118      /**
119       * Only runs if someone invokes the factory/constructor directly
120       * e.g. `new Polymer.IronMeta()`
121       *
122       * @param {{type: (string|undefined), key: (string|undefined), value}=} config
123       */
124      factoryImpl: function(config) {
125        if (config) {
126          for (var n in config) {
127            switch(n) {
128              case 'type':
129              case 'key':
130              case 'value':
131                this[n] = config[n];
132                break;
133            }
134          }
135        }
136      },
137
138      created: function() {
139        // TODO(sjmiles): good for debugging?
140        this._metaDatas = metaDatas;
141        this._metaArrays = metaArrays;
142      },
143
144      _keyChanged: function(key, old) {
145        this._resetRegistration(old);
146      },
147
148      _valueChanged: function(value) {
149        this._resetRegistration(this.key);
150      },
151
152      _selfChanged: function(self) {
153        if (self) {
154          this.value = this;
155        }
156      },
157
158      _typeChanged: function(type) {
159        this._unregisterKey(this.key);
160        if (!metaDatas[type]) {
161          metaDatas[type] = {};
162        }
163        this._metaData = metaDatas[type];
164        if (!metaArrays[type]) {
165          metaArrays[type] = [];
166        }
167        this.list = metaArrays[type];
168        this._registerKeyValue(this.key, this.value);
169      },
170
171      /**
172       * Retrieves meta data value by key.
173       *
174       * @method byKey
175       * @param {string} key The key of the meta-data to be returned.
176       * @return {*}
177       */
178      byKey: function(key) {
179        return this._metaData && this._metaData[key];
180      },
181
182      _resetRegistration: function(oldKey) {
183        this._unregisterKey(oldKey);
184        this._registerKeyValue(this.key, this.value);
185      },
186
187      _unregisterKey: function(key) {
188        this._unregister(key, this._metaData, this.list);
189      },
190
191      _registerKeyValue: function(key, value) {
192        this._register(key, value, this._metaData, this.list);
193      },
194
195      _register: function(key, value, data, list) {
196        if (key && data && value !== undefined) {
197          data[key] = value;
198          list.push(value);
199        }
200      },
201
202      _unregister: function(key, data, list) {
203        if (key && data) {
204          if (key in data) {
205            var value = data[key];
206            delete data[key];
207            this.arrayDelete(list, value);
208          }
209        }
210      }
211
212    });
213
214    Polymer.IronMeta.getIronMeta = function getIronMeta() {
215       if (singleton === null) {
216         singleton = new Polymer.IronMeta();
217       }
218       return singleton;
219     };
220
221    /**
222    `iron-meta-query` can be used to access infomation stored in `iron-meta`.
223
224    Examples:
225
226    If I create an instance like this:
227
228        <iron-meta key="info" value="foo/bar"></iron-meta>
229
230    Note that value="foo/bar" is the metadata I've defined. I could define more
231    attributes or use child nodes to define additional metadata.
232
233    Now I can access that element (and it's metadata) from any `iron-meta-query` instance:
234
235         var value = new Polymer.IronMetaQuery({key: 'info'}).value;
236
237    @group Polymer Iron Elements
238    @element iron-meta-query
239    */
240    Polymer.IronMetaQuery = Polymer({
241
242      is: 'iron-meta-query',
243
244      properties: {
245
246        /**
247         * The type of meta-data.  All meta-data of the same type is stored
248         * together.
249         */
250        type: {
251          type: String,
252          value: 'default',
253          observer: '_typeChanged'
254        },
255
256        /**
257         * Specifies a key to use for retrieving `value` from the `type`
258         * namespace.
259         */
260        key: {
261          type: String,
262          observer: '_keyChanged'
263        },
264
265        /**
266         * The meta-data to store or retrieve.
267         */
268        value: {
269          type: Object,
270          notify: true,
271          readOnly: true
272        },
273
274        /**
275         * Array of all meta-data values for the given type.
276         */
277        list: {
278          type: Array,
279          notify: true
280        }
281
282      },
283
284      /**
285       * Actually a factory method, not a true constructor. Only runs if
286       * someone invokes it directly (via `new Polymer.IronMeta()`);
287       *
288       * @param {{type: (string|undefined), key: (string|undefined)}=} config
289       */
290      factoryImpl: function(config) {
291        if (config) {
292          for (var n in config) {
293            switch(n) {
294              case 'type':
295              case 'key':
296                this[n] = config[n];
297                break;
298            }
299          }
300        }
301      },
302
303      created: function() {
304        // TODO(sjmiles): good for debugging?
305        this._metaDatas = metaDatas;
306        this._metaArrays = metaArrays;
307      },
308
309      _keyChanged: function(key) {
310        this._setValue(this._metaData && this._metaData[key]);
311      },
312
313      _typeChanged: function(type) {
314        this._metaData = metaDatas[type];
315        this.list = metaArrays[type];
316        if (this.key) {
317          this._keyChanged(this.key);
318        }
319      },
320
321      /**
322       * Retrieves meta data value by key.
323       * @param {string} key The key of the meta-data to be returned.
324       * @return {*}
325       */
326      byKey: function(key) {
327        return this._metaData && this._metaData[key];
328      }
329
330    });
331
332  })();
333</script>
334