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