Home | History | Annotate | Download | only in iron-meta
      1 <!--
      2 @license
      3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
      4 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
      5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
      6 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
      7 Code distributed by Google as part of the polymer project is also
      8 subject 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.
     15 It uses [monostate pattern](http://c2.com/cgi/wiki?MonostatePattern) such that any
     16 instance of iron-meta has access to the shared
     17 information. You can use `iron-meta` to share whatever you want (or create an extension
     18 [like x-meta] for enhancements).
     19 
     20 The `iron-meta` instances containing your actual data can be loaded in an import,
     21 or constructed in any way you see fit. The only requirement is that you create them
     22 before you try to access them.
     23 
     24 Examples:
     25 
     26 If I create an instance like this:
     27 
     28     <iron-meta key="info" value="foo/bar"></iron-meta>
     29 
     30 Note that value="foo/bar" is the metadata I've defined. I could define more
     31 attributes or use child nodes to define additional metadata.
     32 
     33 Now I can access that element (and it's metadata) from any iron-meta instance
     34 via the byKey method, e.g.
     35 
     36     meta.byKey('info').getAttribute('value');
     37 
     38 Pure imperative form would be like:
     39 
     40     document.createElement('iron-meta').byKey('info').getAttribute('value');
     41 
     42 Or, 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').getAttribute('value');
     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