OLD | NEW |
1 /** | 1 /** |
2 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | 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://polyme
r.github.io/LICENSE.txt | 3 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
4 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
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/CON
TRIBUTORS.txt | 5 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
6 * Code distributed by Google as part of the polymer project is also | 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/PA
TENTS.txt | 7 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
8 */ | 8 */ |
9 | 9 |
10 window.Platform = window.Platform || {}; | 10 window.Platform = window.Platform || {}; |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 } | 185 } |
186 | 186 |
187 function toNumber(s) { | 187 function toNumber(s) { |
188 return +s; | 188 return +s; |
189 } | 189 } |
190 | 190 |
191 function isObject(obj) { | 191 function isObject(obj) { |
192 return obj === Object(obj); | 192 return obj === Object(obj); |
193 } | 193 } |
194 | 194 |
195 var numberIsNaN = global.Number.isNaN || function isNaN(value) { | 195 var numberIsNaN = global.Number.isNaN || function(value) { |
196 return typeof value === 'number' && global.isNaN(value); | 196 return typeof value === 'number' && global.isNaN(value); |
197 } | 197 } |
198 | 198 |
199 function areSameValue(left, right) { | 199 function areSameValue(left, right) { |
200 if (left === right) | 200 if (left === right) |
201 return left !== 0 || 1 / left === 1 / right; | 201 return left !== 0 || 1 / left === 1 / right; |
202 if (numberIsNaN(left) && numberIsNaN(right)) | 202 if (numberIsNaN(left) && numberIsNaN(right)) |
203 return true; | 203 return true; |
204 | 204 |
205 return left !== left && right !== right; | 205 return left !== left && right !== right; |
206 } | 206 } |
207 | 207 |
208 var createObject = ('__proto__' in {}) ? | 208 var createObject = ('__proto__' in {}) ? |
209 function(obj) { return obj; } : | 209 function(obj) { return obj; } : |
210 function(obj) { | 210 function(obj) { |
211 var proto = obj.__proto__; | 211 var proto = obj.__proto__; |
212 if (!proto) | 212 if (!proto) |
213 return obj; | 213 return obj; |
214 var newObject = Object.create(proto); | 214 var newObject = Object.create(proto); |
215 Object.getOwnPropertyNames(obj).forEach(function(name) { | 215 Object.getOwnPropertyNames(obj).forEach(function(name) { |
216 Object.defineProperty(newObject, name, | 216 Object.defineProperty(newObject, name, |
217 Object.getOwnPropertyDescriptor(obj, name)); | 217 Object.getOwnPropertyDescriptor(obj, name)); |
218 }); | 218 }); |
219 return newObject; | 219 return newObject; |
220 }; | 220 }; |
221 | 221 |
222 var identStart = '[\$_a-zA-Z]'; | 222 var identStart = '[\$_a-zA-Z]'; |
223 var identPart = '[\$_a-zA-Z0-9]'; | 223 var identPart = '[\$_a-zA-Z0-9]'; |
224 var ident = identStart + '+' + identPart + '*'; | 224 var identRegExp = new RegExp('^' + identStart + '+' + identPart + '*' + '$'); |
225 var elementIndex = '(?:[0-9]|[1-9]+[0-9]+)'; | |
226 var identOrElementIndex = '(?:' + ident + '|' + elementIndex + ')'; | |
227 var path = '(?:' + identOrElementIndex + ')(?:\\s*\\.\\s*' + identOrElementInd
ex + ')*'; | |
228 var pathRegExp = new RegExp('^' + path + '$'); | |
229 | 225 |
230 function isPathValid(s) { | 226 function getPathCharType(char) { |
231 if (typeof s != 'string') | 227 if (char === undefined) |
232 return false; | 228 return 'eof'; |
233 s = s.trim(); | |
234 | 229 |
235 if (s == '') | 230 var code = char.charCodeAt(0); |
236 return true; | |
237 | 231 |
238 if (s[0] == '.') | 232 switch(code) { |
239 return false; | 233 case 0x5B: // [ |
| 234 case 0x5D: // ] |
| 235 case 0x2E: // . |
| 236 case 0x22: // " |
| 237 case 0x27: // ' |
| 238 case 0x30: // 0 |
| 239 return char; |
240 | 240 |
241 return pathRegExp.test(s); | 241 case 0x5F: // _ |
| 242 case 0x24: // $ |
| 243 return 'ident'; |
| 244 |
| 245 case 0x20: // Space |
| 246 case 0x09: // Tab |
| 247 case 0x0A: // Newline |
| 248 case 0x0D: // Return |
| 249 case 0xA0: // No-break space |
| 250 case 0xFEFF: // Byte Order Mark |
| 251 case 0x2028: // Line Separator |
| 252 case 0x2029: // Paragraph Separator |
| 253 return 'ws'; |
| 254 } |
| 255 |
| 256 // a-z, A-Z |
| 257 if ((0x61 <= code && code <= 0x7A) || (0x41 <= code && code <= 0x5A)) |
| 258 return 'ident'; |
| 259 |
| 260 // 1-9 |
| 261 if (0x31 <= code && code <= 0x39) |
| 262 return 'number'; |
| 263 |
| 264 return 'else'; |
| 265 } |
| 266 |
| 267 var pathStateMachine = { |
| 268 'beforePath': { |
| 269 'ws': ['beforePath'], |
| 270 'ident': ['inIdent', 'append'], |
| 271 '[': ['beforeElement'], |
| 272 'eof': ['afterPath'] |
| 273 }, |
| 274 |
| 275 'inPath': { |
| 276 'ws': ['inPath'], |
| 277 '.': ['beforeIdent'], |
| 278 '[': ['beforeElement'], |
| 279 'eof': ['afterPath'] |
| 280 }, |
| 281 |
| 282 'beforeIdent': { |
| 283 'ws': ['beforeIdent'], |
| 284 'ident': ['inIdent', 'append'] |
| 285 }, |
| 286 |
| 287 'inIdent': { |
| 288 'ident': ['inIdent', 'append'], |
| 289 '0': ['inIdent', 'append'], |
| 290 'number': ['inIdent', 'append'], |
| 291 'ws': ['inPath', 'push'], |
| 292 '.': ['beforeIdent', 'push'], |
| 293 '[': ['beforeElement', 'push'], |
| 294 'eof': ['afterPath', 'push'] |
| 295 }, |
| 296 |
| 297 'beforeElement': { |
| 298 'ws': ['beforeElement'], |
| 299 '0': ['afterZero', 'append'], |
| 300 'number': ['inIndex', 'append'], |
| 301 "'": ['inSingleQuote', 'append', ''], |
| 302 '"': ['inDoubleQuote', 'append', ''] |
| 303 }, |
| 304 |
| 305 'afterZero': { |
| 306 'ws': ['afterElement', 'push'], |
| 307 ']': ['inPath', 'push'] |
| 308 }, |
| 309 |
| 310 'inIndex': { |
| 311 '0': ['inIndex', 'append'], |
| 312 'number': ['inIndex', 'append'], |
| 313 'ws': ['afterElement'], |
| 314 ']': ['inPath', 'push'] |
| 315 }, |
| 316 |
| 317 'inSingleQuote': { |
| 318 "'": ['afterElement'], |
| 319 'eof': ['error'], |
| 320 'else': ['inSingleQuote', 'append'] |
| 321 }, |
| 322 |
| 323 'inDoubleQuote': { |
| 324 '"': ['afterElement'], |
| 325 'eof': ['error'], |
| 326 'else': ['inDoubleQuote', 'append'] |
| 327 }, |
| 328 |
| 329 'afterElement': { |
| 330 'ws': ['afterElement'], |
| 331 ']': ['inPath', 'push'] |
| 332 } |
| 333 } |
| 334 |
| 335 function noop() {} |
| 336 |
| 337 function parsePath(path) { |
| 338 var keys = []; |
| 339 var index = -1; |
| 340 var c, newChar, key, type, transition, action, typeMap, mode = 'beforePath'; |
| 341 |
| 342 var actions = { |
| 343 push: function() { |
| 344 if (key === undefined) |
| 345 return; |
| 346 |
| 347 keys.push(key); |
| 348 key = undefined; |
| 349 }, |
| 350 |
| 351 append: function() { |
| 352 if (key === undefined) |
| 353 key = newChar |
| 354 else |
| 355 key += newChar; |
| 356 } |
| 357 }; |
| 358 |
| 359 function maybeUnescapeQuote() { |
| 360 if (index >= path.length) |
| 361 return; |
| 362 |
| 363 var nextChar = path[index + 1]; |
| 364 if ((mode == 'inSingleQuote' && nextChar == "'") || |
| 365 (mode == 'inDoubleQuote' && nextChar == '"')) { |
| 366 index++; |
| 367 newChar = nextChar; |
| 368 actions.append(); |
| 369 return true; |
| 370 } |
| 371 } |
| 372 |
| 373 while (mode) { |
| 374 index++; |
| 375 c = path[index]; |
| 376 |
| 377 if (c == '\\' && maybeUnescapeQuote(mode)) |
| 378 continue; |
| 379 |
| 380 type = getPathCharType(c); |
| 381 typeMap = pathStateMachine[mode]; |
| 382 transition = typeMap[type] || typeMap['else'] || 'error'; |
| 383 |
| 384 if (transition == 'error') |
| 385 return; // parse error; |
| 386 |
| 387 mode = transition[0]; |
| 388 action = actions[transition[1]] || noop; |
| 389 newChar = transition[2] === undefined ? c : transition[2]; |
| 390 action(); |
| 391 |
| 392 if (mode === 'afterPath') { |
| 393 return keys; |
| 394 } |
| 395 } |
| 396 |
| 397 return; // parse error |
| 398 } |
| 399 |
| 400 function isIdent(s) { |
| 401 return identRegExp.test(s); |
242 } | 402 } |
243 | 403 |
244 var constructorIsPrivate = {}; | 404 var constructorIsPrivate = {}; |
245 | 405 |
246 function Path(s, privateToken) { | 406 function Path(parts, privateToken) { |
247 if (privateToken !== constructorIsPrivate) | 407 if (privateToken !== constructorIsPrivate) |
248 throw Error('Use Path.get to retrieve path objects'); | 408 throw Error('Use Path.get to retrieve path objects'); |
249 | 409 |
250 if (s.trim() == '') | 410 if (parts.length) |
251 return this; | 411 Array.prototype.push.apply(this, parts.slice()); |
252 | |
253 if (isIndex(s)) { | |
254 this.push(s); | |
255 return this; | |
256 } | |
257 | |
258 s.split(/\s*\.\s*/).filter(function(part) { | |
259 return part; | |
260 }).forEach(function(part) { | |
261 this.push(part); | |
262 }, this); | |
263 | 412 |
264 if (hasEval && this.length) { | 413 if (hasEval && this.length) { |
265 this.getValueFrom = this.compiledGetValueFromFn(); | 414 this.getValueFrom = this.compiledGetValueFromFn(); |
266 } | 415 } |
267 } | 416 } |
268 | 417 |
269 // TODO(rafaelw): Make simple LRU cache | 418 // TODO(rafaelw): Make simple LRU cache |
270 var pathCache = {}; | 419 var pathCache = {}; |
271 | 420 |
272 function getPath(pathString) { | 421 function getPath(pathString) { |
273 if (pathString instanceof Path) | 422 if (pathString instanceof Path) |
274 return pathString; | 423 return pathString; |
275 | 424 |
276 if (pathString == null) | 425 if (pathString == null || pathString.length == 0) |
277 pathString = ''; | 426 pathString = ''; |
278 | 427 |
279 if (typeof pathString !== 'string') | 428 if (typeof pathString != 'string') { |
| 429 if (isIndex(pathString.length)) { |
| 430 // Constructed with array-like (pre-parsed) keys |
| 431 return new Path(pathString, constructorIsPrivate); |
| 432 } |
| 433 |
280 pathString = String(pathString); | 434 pathString = String(pathString); |
| 435 } |
281 | 436 |
282 var path = pathCache[pathString]; | 437 var path = pathCache[pathString]; |
283 if (path) | 438 if (path) |
284 return path; | 439 return path; |
285 if (!isPathValid(pathString)) | 440 |
| 441 var parts = parsePath(pathString); |
| 442 if (!parts) |
286 return invalidPath; | 443 return invalidPath; |
287 var path = new Path(pathString, constructorIsPrivate); | 444 |
| 445 var path = new Path(parts, constructorIsPrivate); |
288 pathCache[pathString] = path; | 446 pathCache[pathString] = path; |
289 return path; | 447 return path; |
290 } | 448 } |
291 | 449 |
292 Path.get = getPath; | 450 Path.get = getPath; |
293 | 451 |
| 452 function formatAccessor(key) { |
| 453 if (isIndex(key)) { |
| 454 return '[' + key + ']'; |
| 455 } else { |
| 456 return '["' + key.replace(/"/g, '\\"') + '"]'; |
| 457 } |
| 458 } |
| 459 |
294 Path.prototype = createObject({ | 460 Path.prototype = createObject({ |
295 __proto__: [], | 461 __proto__: [], |
296 valid: true, | 462 valid: true, |
297 | 463 |
298 toString: function() { | 464 toString: function() { |
299 return this.join('.'); | 465 var pathString = ''; |
| 466 for (var i = 0; i < this.length; i++) { |
| 467 var key = this[i]; |
| 468 if (isIdent(key)) { |
| 469 pathString += i ? '.' + key : key; |
| 470 } else { |
| 471 pathString += formatAccessor(key); |
| 472 } |
| 473 } |
| 474 |
| 475 return pathString; |
300 }, | 476 }, |
301 | 477 |
302 getValueFrom: function(obj, directObserver) { | 478 getValueFrom: function(obj, directObserver) { |
303 for (var i = 0; i < this.length; i++) { | 479 for (var i = 0; i < this.length; i++) { |
304 if (obj == null) | 480 if (obj == null) |
305 return; | 481 return; |
306 obj = obj[this[i]]; | 482 obj = obj[this[i]]; |
307 } | 483 } |
308 return obj; | 484 return obj; |
309 }, | 485 }, |
310 | 486 |
311 iterateObjects: function(obj, observe) { | 487 iterateObjects: function(obj, observe) { |
312 for (var i = 0; i < this.length; i++) { | 488 for (var i = 0; i < this.length; i++) { |
313 if (i) | 489 if (i) |
314 obj = obj[this[i - 1]]; | 490 obj = obj[this[i - 1]]; |
315 if (!isObject(obj)) | 491 if (!isObject(obj)) |
316 return; | 492 return; |
317 observe(obj, this[0]); | 493 observe(obj, this[0]); |
318 } | 494 } |
319 }, | 495 }, |
320 | 496 |
321 compiledGetValueFromFn: function() { | 497 compiledGetValueFromFn: function() { |
322 var accessors = this.map(function(ident) { | |
323 return isIndex(ident) ? '["' + ident + '"]' : '.' + ident; | |
324 }); | |
325 | |
326 var str = ''; | 498 var str = ''; |
327 var pathString = 'obj'; | 499 var pathString = 'obj'; |
328 str += 'if (obj != null'; | 500 str += 'if (obj != null'; |
329 var i = 0; | 501 var i = 0; |
| 502 var key; |
330 for (; i < (this.length - 1); i++) { | 503 for (; i < (this.length - 1); i++) { |
331 var ident = this[i]; | 504 key = this[i]; |
332 pathString += accessors[i]; | 505 pathString += isIdent(key) ? '.' + key : formatAccessor(key); |
333 str += ' &&\n ' + pathString + ' != null'; | 506 str += ' &&\n ' + pathString + ' != null'; |
334 } | 507 } |
335 str += ')\n'; | 508 str += ')\n'; |
336 | 509 |
337 pathString += accessors[i]; | 510 var key = this[i]; |
| 511 pathString += isIdent(key) ? '.' + key : formatAccessor(key); |
338 | 512 |
339 str += ' return ' + pathString + ';\nelse\n return undefined;'; | 513 str += ' return ' + pathString + ';\nelse\n return undefined;'; |
340 return new Function('obj', str); | 514 return new Function('obj', str); |
341 }, | 515 }, |
342 | 516 |
343 setValueFrom: function(obj, value) { | 517 setValueFrom: function(obj, value) { |
344 if (!this.length) | 518 if (!this.length) |
345 return false; | 519 return false; |
346 | 520 |
347 for (var i = 0; i < this.length - 1; i++) { | 521 for (var i = 0; i < this.length - 1; i++) { |
(...skipping 580 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
928 Observer.call(this); | 1102 Observer.call(this); |
929 | 1103 |
930 this.object_ = object; | 1104 this.object_ = object; |
931 this.path_ = getPath(path); | 1105 this.path_ = getPath(path); |
932 this.directObserver_ = undefined; | 1106 this.directObserver_ = undefined; |
933 } | 1107 } |
934 | 1108 |
935 PathObserver.prototype = createObject({ | 1109 PathObserver.prototype = createObject({ |
936 __proto__: Observer.prototype, | 1110 __proto__: Observer.prototype, |
937 | 1111 |
| 1112 get path() { |
| 1113 return this.path_; |
| 1114 }, |
| 1115 |
938 connect_: function() { | 1116 connect_: function() { |
939 if (hasObserve) | 1117 if (hasObserve) |
940 this.directObserver_ = getObservedSet(this, this.object_); | 1118 this.directObserver_ = getObservedSet(this, this.object_); |
941 | 1119 |
942 this.check_(undefined, true); | 1120 this.check_(undefined, true); |
943 }, | 1121 }, |
944 | 1122 |
945 disconnect_: function() { | 1123 disconnect_: function() { |
946 this.value_ = undefined; | 1124 this.value_ = undefined; |
947 | 1125 |
948 if (this.directObserver_) { | 1126 if (this.directObserver_) { |
949 this.directObserver_.close(this); | 1127 this.directObserver_.close(this); |
950 this.directObserver_ = undefined; | 1128 this.directObserver_ = undefined; |
951 } | 1129 } |
952 }, | 1130 }, |
953 | 1131 |
954 iterateObjects_: function(observe) { | 1132 iterateObjects_: function(observe) { |
955 this.path_.iterateObjects(this.object_, observe); | 1133 this.path_.iterateObjects(this.object_, observe); |
956 }, | 1134 }, |
957 | 1135 |
958 check_: function(changeRecords, skipChanges) { | 1136 check_: function(changeRecords, skipChanges) { |
959 var oldValue = this.value_; | 1137 var oldValue = this.value_; |
960 this.value_ = this.path_.getValueFrom(this.object_); | 1138 this.value_ = this.path_.getValueFrom(this.object_); |
961 if (skipChanges || areSameValue(this.value_, oldValue)) | 1139 if (skipChanges || areSameValue(this.value_, oldValue)) |
962 return false; | 1140 return false; |
963 | 1141 |
964 this.report_([this.value_, oldValue]); | 1142 this.report_([this.value_, oldValue, this]); |
965 return true; | 1143 return true; |
966 }, | 1144 }, |
967 | 1145 |
968 setValue: function(newValue) { | 1146 setValue: function(newValue) { |
969 if (this.path_) | 1147 if (this.path_) |
970 this.path_.setValueFrom(this.object_, newValue); | 1148 this.path_.setValueFrom(this.object_, newValue); |
971 } | 1149 } |
972 }); | 1150 }); |
973 | 1151 |
974 function CompoundObserver(reportChangesOnOpen) { | 1152 function CompoundObserver(reportChangesOnOpen) { |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1164 this.setValueFn_ = undefined; | 1342 this.setValueFn_ = undefined; |
1165 } | 1343 } |
1166 } | 1344 } |
1167 | 1345 |
1168 var expectedRecordTypes = { | 1346 var expectedRecordTypes = { |
1169 add: true, | 1347 add: true, |
1170 update: true, | 1348 update: true, |
1171 delete: true | 1349 delete: true |
1172 }; | 1350 }; |
1173 | 1351 |
1174 var updateRecord = { | |
1175 object: undefined, | |
1176 type: 'update', | |
1177 name: undefined, | |
1178 oldValue: undefined | |
1179 }; | |
1180 | |
1181 function notify(object, name, value, oldValue) { | |
1182 if (areSameValue(value, oldValue)) | |
1183 return; | |
1184 | |
1185 // TODO(rafaelw): Hack hack hack. This entire code really needs to move | |
1186 // out of observe-js into polymer. | |
1187 if (typeof object.propertyChanged_ == 'function') | |
1188 object.propertyChanged_(name, value, oldValue); | |
1189 | |
1190 if (!hasObserve) | |
1191 return; | |
1192 | |
1193 var notifier = object.notifier_; | |
1194 if (!notifier) | |
1195 notifier = object.notifier_ = Object.getNotifier(object); | |
1196 | |
1197 updateRecord.object = object; | |
1198 updateRecord.name = name; | |
1199 updateRecord.oldValue = oldValue; | |
1200 | |
1201 notifier.notify(updateRecord); | |
1202 } | |
1203 | |
1204 Observer.createBindablePrototypeAccessor = function(proto, name) { | |
1205 var privateName = name + '_'; | |
1206 var privateObservable = name + 'Observable_'; | |
1207 | |
1208 proto[privateName] = proto[name]; | |
1209 | |
1210 Object.defineProperty(proto, name, { | |
1211 get: function() { | |
1212 var observable = this[privateObservable]; | |
1213 if (observable) | |
1214 observable.deliver(); | |
1215 | |
1216 return this[privateName]; | |
1217 }, | |
1218 set: function(value) { | |
1219 var observable = this[privateObservable]; | |
1220 if (observable) { | |
1221 observable.setValue(value); | |
1222 return; | |
1223 } | |
1224 | |
1225 var oldValue = this[privateName]; | |
1226 this[privateName] = value; | |
1227 notify(this, name, value, oldValue); | |
1228 | |
1229 return value; | |
1230 }, | |
1231 configurable: true | |
1232 }); | |
1233 } | |
1234 | |
1235 Observer.bindToInstance = function(instance, name, observable, resolveFn) { | |
1236 var privateName = name + '_'; | |
1237 var privateObservable = name + 'Observable_'; | |
1238 | |
1239 instance[privateObservable] = observable; | |
1240 var oldValue = instance[privateName]; | |
1241 var value = observable.open(function(value, oldValue) { | |
1242 instance[privateName] = value; | |
1243 notify(instance, name, value, oldValue); | |
1244 }); | |
1245 | |
1246 if (resolveFn && !areSameValue(oldValue, value)) { | |
1247 var resolvedValue = resolveFn(oldValue, value); | |
1248 if (!areSameValue(value, resolvedValue)) { | |
1249 value = resolvedValue; | |
1250 if (observable.setValue) | |
1251 observable.setValue(value); | |
1252 } | |
1253 } | |
1254 | |
1255 instance[privateName] = value; | |
1256 notify(instance, name, value, oldValue); | |
1257 | |
1258 return { | |
1259 close: function() { | |
1260 observable.close(); | |
1261 instance[privateObservable] = undefined; | |
1262 } | |
1263 }; | |
1264 } | |
1265 | |
1266 function diffObjectFromChangeRecords(object, changeRecords, oldValues) { | 1352 function diffObjectFromChangeRecords(object, changeRecords, oldValues) { |
1267 var added = {}; | 1353 var added = {}; |
1268 var removed = {}; | 1354 var removed = {}; |
1269 | 1355 |
1270 for (var i = 0; i < changeRecords.length; i++) { | 1356 for (var i = 0; i < changeRecords.length; i++) { |
1271 var record = changeRecords[i]; | 1357 var record = changeRecords[i]; |
1272 if (!expectedRecordTypes[record.type]) { | 1358 if (!expectedRecordTypes[record.type]) { |
1273 console.error('Unknown changeRecord type: ' + record.type); | 1359 console.error('Unknown changeRecord type: ' + record.type); |
1274 console.error(record); | 1360 console.error(record); |
1275 continue; | 1361 continue; |
(...skipping 1761 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3037 } | 3123 } |
3038 | 3124 |
3039 eventPhaseTable.set(event, phase); | 3125 eventPhaseTable.set(event, phase); |
3040 var type = event.type; | 3126 var type = event.type; |
3041 | 3127 |
3042 var anyRemoved = false; | 3128 var anyRemoved = false; |
3043 // targetTable.set(event, target); | 3129 // targetTable.set(event, target); |
3044 targetTable.set(event, target); | 3130 targetTable.set(event, target); |
3045 currentTargetTable.set(event, currentTarget); | 3131 currentTargetTable.set(event, currentTarget); |
3046 | 3132 |
3047 for (var i = 0; i < listeners.length; i++) { | 3133 // Keep track of the invoke depth so that we only clean up the removed |
| 3134 // listeners if we are in the outermost invoke. |
| 3135 listeners.depth++; |
| 3136 |
| 3137 for (var i = 0, len = listeners.length; i < len; i++) { |
3048 var listener = listeners[i]; | 3138 var listener = listeners[i]; |
3049 if (listener.removed) { | 3139 if (listener.removed) { |
3050 anyRemoved = true; | 3140 anyRemoved = true; |
3051 continue; | 3141 continue; |
3052 } | 3142 } |
3053 | 3143 |
3054 if (listener.type !== type || | 3144 if (listener.type !== type || |
3055 !listener.capture && phase === CAPTURING_PHASE || | 3145 !listener.capture && phase === CAPTURING_PHASE || |
3056 listener.capture && phase === BUBBLING_PHASE) { | 3146 listener.capture && phase === BUBBLING_PHASE) { |
3057 continue; | 3147 continue; |
3058 } | 3148 } |
3059 | 3149 |
3060 try { | 3150 try { |
3061 if (typeof listener.handler === 'function') | 3151 if (typeof listener.handler === 'function') |
3062 listener.handler.call(currentTarget, event); | 3152 listener.handler.call(currentTarget, event); |
3063 else | 3153 else |
3064 listener.handler.handleEvent(event); | 3154 listener.handler.handleEvent(event); |
3065 | 3155 |
3066 if (stopImmediatePropagationTable.get(event)) | 3156 if (stopImmediatePropagationTable.get(event)) |
3067 return false; | 3157 return false; |
3068 | 3158 |
3069 } catch (ex) { | 3159 } catch (ex) { |
3070 if (!pendingError) | 3160 if (!pendingError) |
3071 pendingError = ex; | 3161 pendingError = ex; |
3072 } | 3162 } |
3073 } | 3163 } |
3074 | 3164 |
3075 if (anyRemoved) { | 3165 listeners.depth--; |
| 3166 |
| 3167 if (anyRemoved && listeners.depth === 0) { |
3076 var copy = listeners.slice(); | 3168 var copy = listeners.slice(); |
3077 listeners.length = 0; | 3169 listeners.length = 0; |
3078 for (var i = 0; i < copy.length; i++) { | 3170 for (var i = 0; i < copy.length; i++) { |
3079 if (!copy[i].removed) | 3171 if (!copy[i].removed) |
3080 listeners.push(copy[i]); | 3172 listeners.push(copy[i]); |
3081 } | 3173 } |
3082 } | 3174 } |
3083 | 3175 |
3084 return !stopPropagationTable.get(event); | 3176 return !stopPropagationTable.get(event); |
3085 } | 3177 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3130 get target() { | 3222 get target() { |
3131 return targetTable.get(this); | 3223 return targetTable.get(this); |
3132 }, | 3224 }, |
3133 get currentTarget() { | 3225 get currentTarget() { |
3134 return currentTargetTable.get(this); | 3226 return currentTargetTable.get(this); |
3135 }, | 3227 }, |
3136 get eventPhase() { | 3228 get eventPhase() { |
3137 return eventPhaseTable.get(this); | 3229 return eventPhaseTable.get(this); |
3138 }, | 3230 }, |
3139 get path() { | 3231 get path() { |
3140 var nodeList = new wrappers.NodeList(); | |
3141 var eventPath = eventPathTable.get(this); | 3232 var eventPath = eventPathTable.get(this); |
3142 if (eventPath) { | 3233 if (!eventPath) |
3143 var index = 0; | 3234 return []; |
3144 var lastIndex = eventPath.length - 1; | 3235 // TODO(arv): Event path should contain window. |
3145 var baseRoot = getTreeScope(currentTargetTable.get(this)); | 3236 return eventPath.slice(); |
3146 | |
3147 for (var i = 0; i <= lastIndex; i++) { | |
3148 var currentTarget = eventPath[i]; | |
3149 var currentRoot = getTreeScope(currentTarget); | |
3150 if (currentRoot.contains(baseRoot) && | |
3151 // Make sure we do not add Window to the path. | |
3152 (i !== lastIndex || currentTarget instanceof wrappers.Node)) { | |
3153 nodeList[index++] = currentTarget; | |
3154 } | |
3155 } | |
3156 nodeList.length = index; | |
3157 } | |
3158 return nodeList; | |
3159 }, | 3237 }, |
3160 stopPropagation: function() { | 3238 stopPropagation: function() { |
3161 stopPropagationTable.set(this, true); | 3239 stopPropagationTable.set(this, true); |
3162 }, | 3240 }, |
3163 stopImmediatePropagation: function() { | 3241 stopImmediatePropagation: function() { |
3164 stopPropagationTable.set(this, true); | 3242 stopPropagationTable.set(this, true); |
3165 stopImmediatePropagationTable.set(this, true); | 3243 stopImmediatePropagationTable.set(this, true); |
3166 } | 3244 } |
3167 }; | 3245 }; |
3168 registerWrapper(OriginalEvent, Event, document.createEvent('Event')); | 3246 registerWrapper(OriginalEvent, Event, document.createEvent('Event')); |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3376 | 3454 |
3377 EventTarget.prototype = { | 3455 EventTarget.prototype = { |
3378 addEventListener: function(type, fun, capture) { | 3456 addEventListener: function(type, fun, capture) { |
3379 if (!isValidListener(fun) || isMutationEvent(type)) | 3457 if (!isValidListener(fun) || isMutationEvent(type)) |
3380 return; | 3458 return; |
3381 | 3459 |
3382 var listener = new Listener(type, fun, capture); | 3460 var listener = new Listener(type, fun, capture); |
3383 var listeners = listenersTable.get(this); | 3461 var listeners = listenersTable.get(this); |
3384 if (!listeners) { | 3462 if (!listeners) { |
3385 listeners = []; | 3463 listeners = []; |
| 3464 listeners.depth = 0; |
3386 listenersTable.set(this, listeners); | 3465 listenersTable.set(this, listeners); |
3387 } else { | 3466 } else { |
3388 // Might have a duplicate. | 3467 // Might have a duplicate. |
3389 for (var i = 0; i < listeners.length; i++) { | 3468 for (var i = 0; i < listeners.length; i++) { |
3390 if (listener.equals(listeners[i])) | 3469 if (listener.equals(listeners[i])) |
3391 return; | 3470 return; |
3392 } | 3471 } |
3393 } | 3472 } |
3394 | 3473 |
3395 listeners.push(listener); | 3474 listeners.push(listener); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3484 | 3563 |
3485 var originalElementFromPoint = document.elementFromPoint; | 3564 var originalElementFromPoint = document.elementFromPoint; |
3486 | 3565 |
3487 function elementFromPoint(self, document, x, y) { | 3566 function elementFromPoint(self, document, x, y) { |
3488 scope.renderAllPending(); | 3567 scope.renderAllPending(); |
3489 | 3568 |
3490 var element = wrap(originalElementFromPoint.call(document.impl, x, y)); | 3569 var element = wrap(originalElementFromPoint.call(document.impl, x, y)); |
3491 if (!element) | 3570 if (!element) |
3492 return null; | 3571 return null; |
3493 var path = getEventPath(element, null); | 3572 var path = getEventPath(element, null); |
| 3573 |
| 3574 // scope the path to this TreeScope |
| 3575 var idx = path.lastIndexOf(self); |
| 3576 if (idx == -1) |
| 3577 return null; |
| 3578 else |
| 3579 path = path.slice(0, idx); |
| 3580 |
| 3581 // TODO(dfreedm): pass idx to eventRetargetting to avoid array copy |
3494 return eventRetargetting(path, self); | 3582 return eventRetargetting(path, self); |
3495 } | 3583 } |
3496 | 3584 |
3497 /** | 3585 /** |
3498 * Returns a function that is to be used as a getter for `onfoo` properties. | 3586 * Returns a function that is to be used as a getter for `onfoo` properties. |
3499 * @param {string} name | 3587 * @param {string} name |
3500 * @return {Function} | 3588 * @return {Function} |
3501 */ | 3589 */ |
3502 function getEventHandlerGetter(name) { | 3590 function getEventHandlerGetter(name) { |
3503 return function() { | 3591 return function() { |
(...skipping 937 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4441 this.removeNode(n); | 4529 this.removeNode(n); |
4442 else if (!modNode) | 4530 else if (!modNode) |
4443 modNode = n; | 4531 modNode = n; |
4444 else { | 4532 else { |
4445 s += n.data; | 4533 s += n.data; |
4446 remNodes.push(n); | 4534 remNodes.push(n); |
4447 } | 4535 } |
4448 } else { | 4536 } else { |
4449 if (modNode && remNodes.length) { | 4537 if (modNode && remNodes.length) { |
4450 modNode.data += s; | 4538 modNode.data += s; |
4451 cleanUpNodes(remNodes); | 4539 cleanupNodes(remNodes); |
4452 } | 4540 } |
4453 remNodes = []; | 4541 remNodes = []; |
4454 s = ''; | 4542 s = ''; |
4455 modNode = null; | 4543 modNode = null; |
4456 if (n.childNodes.length) | 4544 if (n.childNodes.length) |
4457 n.normalize(); | 4545 n.normalize(); |
4458 } | 4546 } |
4459 } | 4547 } |
4460 | 4548 |
4461 // handle case where >1 text nodes are the last children | 4549 // handle case where >1 text nodes are the last children |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4759 this.parentNode.insertBefore(newTextNode, this.nextSibling); | 4847 this.parentNode.insertBefore(newTextNode, this.nextSibling); |
4760 return newTextNode; | 4848 return newTextNode; |
4761 } | 4849 } |
4762 }); | 4850 }); |
4763 | 4851 |
4764 registerWrapper(OriginalText, Text, document.createTextNode('')); | 4852 registerWrapper(OriginalText, Text, document.createTextNode('')); |
4765 | 4853 |
4766 scope.wrappers.Text = Text; | 4854 scope.wrappers.Text = Text; |
4767 })(window.ShadowDOMPolyfill); | 4855 })(window.ShadowDOMPolyfill); |
4768 | 4856 |
| 4857 // Copyright 2014 The Polymer Authors. All rights reserved. |
| 4858 // Use of this source code is goverened by a BSD-style |
| 4859 // license that can be found in the LICENSE file. |
| 4860 |
| 4861 (function(scope) { |
| 4862 'use strict'; |
| 4863 |
| 4864 function invalidateClass(el) { |
| 4865 scope.invalidateRendererBasedOnAttribute(el, 'class'); |
| 4866 } |
| 4867 |
| 4868 function DOMTokenList(impl, ownerElement) { |
| 4869 this.impl = impl; |
| 4870 this.ownerElement_ = ownerElement; |
| 4871 } |
| 4872 |
| 4873 DOMTokenList.prototype = { |
| 4874 get length() { |
| 4875 return this.impl.length; |
| 4876 }, |
| 4877 item: function(index) { |
| 4878 return this.impl.item(index); |
| 4879 }, |
| 4880 contains: function(token) { |
| 4881 return this.impl.contains(token); |
| 4882 }, |
| 4883 add: function() { |
| 4884 this.impl.add.apply(this.impl, arguments); |
| 4885 invalidateClass(this.ownerElement_); |
| 4886 }, |
| 4887 remove: function() { |
| 4888 this.impl.remove.apply(this.impl, arguments); |
| 4889 invalidateClass(this.ownerElement_); |
| 4890 }, |
| 4891 toggle: function(token) { |
| 4892 var rv = this.impl.toggle.apply(this.impl, arguments); |
| 4893 invalidateClass(this.ownerElement_); |
| 4894 return rv; |
| 4895 }, |
| 4896 toString: function() { |
| 4897 return this.impl.toString(); |
| 4898 } |
| 4899 }; |
| 4900 |
| 4901 scope.wrappers.DOMTokenList = DOMTokenList; |
| 4902 })(window.ShadowDOMPolyfill); |
| 4903 |
4769 // Copyright 2013 The Polymer Authors. All rights reserved. | 4904 // Copyright 2013 The Polymer Authors. All rights reserved. |
4770 // Use of this source code is goverened by a BSD-style | 4905 // Use of this source code is goverened by a BSD-style |
4771 // license that can be found in the LICENSE file. | 4906 // license that can be found in the LICENSE file. |
4772 | 4907 |
4773 (function(scope) { | 4908 (function(scope) { |
4774 'use strict'; | 4909 'use strict'; |
4775 | 4910 |
4776 var ChildNodeInterface = scope.ChildNodeInterface; | 4911 var ChildNodeInterface = scope.ChildNodeInterface; |
4777 var GetElementsByInterface = scope.GetElementsByInterface; | 4912 var GetElementsByInterface = scope.GetElementsByInterface; |
4778 var Node = scope.wrappers.Node; | 4913 var Node = scope.wrappers.Node; |
| 4914 var DOMTokenList = scope.wrappers.DOMTokenList; |
4779 var ParentNodeInterface = scope.ParentNodeInterface; | 4915 var ParentNodeInterface = scope.ParentNodeInterface; |
4780 var SelectorsInterface = scope.SelectorsInterface; | 4916 var SelectorsInterface = scope.SelectorsInterface; |
4781 var addWrapNodeListMethod = scope.addWrapNodeListMethod; | 4917 var addWrapNodeListMethod = scope.addWrapNodeListMethod; |
4782 var enqueueMutation = scope.enqueueMutation; | 4918 var enqueueMutation = scope.enqueueMutation; |
4783 var mixin = scope.mixin; | 4919 var mixin = scope.mixin; |
4784 var oneOf = scope.oneOf; | 4920 var oneOf = scope.oneOf; |
4785 var registerWrapper = scope.registerWrapper; | 4921 var registerWrapper = scope.registerWrapper; |
| 4922 var unwrap = scope.unwrap; |
4786 var wrappers = scope.wrappers; | 4923 var wrappers = scope.wrappers; |
4787 | 4924 |
4788 var OriginalElement = window.Element; | 4925 var OriginalElement = window.Element; |
4789 | 4926 |
4790 var matchesNames = [ | 4927 var matchesNames = [ |
4791 'matches', // needs to come first. | 4928 'matches', // needs to come first. |
4792 'mozMatchesSelector', | 4929 'mozMatchesSelector', |
4793 'msMatchesSelector', | 4930 'msMatchesSelector', |
4794 'webkitMatchesSelector', | 4931 'webkitMatchesSelector', |
4795 ].filter(function(name) { | 4932 ].filter(function(name) { |
(...skipping 19 matching lines...) Expand all Loading... |
4815 // This is not fully spec compliant. We should use localName (which might | 4952 // This is not fully spec compliant. We should use localName (which might |
4816 // have a different case than name) and the namespace (which requires us | 4953 // have a different case than name) and the namespace (which requires us |
4817 // to get the Attr object). | 4954 // to get the Attr object). |
4818 enqueueMutation(element, 'attributes', { | 4955 enqueueMutation(element, 'attributes', { |
4819 name: name, | 4956 name: name, |
4820 namespace: null, | 4957 namespace: null, |
4821 oldValue: oldValue | 4958 oldValue: oldValue |
4822 }); | 4959 }); |
4823 } | 4960 } |
4824 | 4961 |
| 4962 var classListTable = new WeakMap(); |
| 4963 |
4825 function Element(node) { | 4964 function Element(node) { |
4826 Node.call(this, node); | 4965 Node.call(this, node); |
4827 } | 4966 } |
4828 Element.prototype = Object.create(Node.prototype); | 4967 Element.prototype = Object.create(Node.prototype); |
4829 mixin(Element.prototype, { | 4968 mixin(Element.prototype, { |
4830 createShadowRoot: function() { | 4969 createShadowRoot: function() { |
4831 var newShadowRoot = new wrappers.ShadowRoot(this); | 4970 var newShadowRoot = new wrappers.ShadowRoot(this); |
4832 this.impl.polymerShadowRoot_ = newShadowRoot; | 4971 this.impl.polymerShadowRoot_ = newShadowRoot; |
4833 | 4972 |
4834 var renderer = scope.getRendererForHost(this); | 4973 var renderer = scope.getRendererForHost(this); |
(...skipping 17 matching lines...) Expand all Loading... |
4852 | 4991 |
4853 removeAttribute: function(name) { | 4992 removeAttribute: function(name) { |
4854 var oldValue = this.impl.getAttribute(name); | 4993 var oldValue = this.impl.getAttribute(name); |
4855 this.impl.removeAttribute(name); | 4994 this.impl.removeAttribute(name); |
4856 enqueAttributeChange(this, name, oldValue); | 4995 enqueAttributeChange(this, name, oldValue); |
4857 invalidateRendererBasedOnAttribute(this, name); | 4996 invalidateRendererBasedOnAttribute(this, name); |
4858 }, | 4997 }, |
4859 | 4998 |
4860 matches: function(selector) { | 4999 matches: function(selector) { |
4861 return originalMatches.call(this.impl, selector); | 5000 return originalMatches.call(this.impl, selector); |
| 5001 }, |
| 5002 |
| 5003 get classList() { |
| 5004 var list = classListTable.get(this); |
| 5005 if (!list) { |
| 5006 classListTable.set(this, |
| 5007 list = new DOMTokenList(unwrap(this).classList, this)); |
| 5008 } |
| 5009 return list; |
| 5010 }, |
| 5011 |
| 5012 get className() { |
| 5013 return unwrap(this).className; |
| 5014 }, |
| 5015 |
| 5016 set className(v) { |
| 5017 this.setAttribute('class', v); |
| 5018 }, |
| 5019 |
| 5020 get id() { |
| 5021 return unwrap(this).id; |
| 5022 }, |
| 5023 |
| 5024 set id(v) { |
| 5025 this.setAttribute('id', v); |
4862 } | 5026 } |
4863 }); | 5027 }); |
4864 | 5028 |
4865 matchesNames.forEach(function(name) { | 5029 matchesNames.forEach(function(name) { |
4866 if (name !== 'matches') { | 5030 if (name !== 'matches') { |
4867 Element.prototype[name] = function(selector) { | 5031 Element.prototype[name] = function(selector) { |
4868 return this.matches(selector); | 5032 return this.matches(selector); |
4869 }; | 5033 }; |
4870 } | 5034 } |
4871 }); | 5035 }); |
4872 | 5036 |
4873 if (OriginalElement.prototype.webkitCreateShadowRoot) { | 5037 if (OriginalElement.prototype.webkitCreateShadowRoot) { |
4874 Element.prototype.webkitCreateShadowRoot = | 5038 Element.prototype.webkitCreateShadowRoot = |
4875 Element.prototype.createShadowRoot; | 5039 Element.prototype.createShadowRoot; |
4876 } | 5040 } |
4877 | 5041 |
4878 /** | |
4879 * Useful for generating the accessor pair for a property that reflects an | |
4880 * attribute. | |
4881 */ | |
4882 function setterDirtiesAttribute(prototype, propertyName, opt_attrName) { | |
4883 var attrName = opt_attrName || propertyName; | |
4884 Object.defineProperty(prototype, propertyName, { | |
4885 get: function() { | |
4886 return this.impl[propertyName]; | |
4887 }, | |
4888 set: function(v) { | |
4889 this.impl[propertyName] = v; | |
4890 invalidateRendererBasedOnAttribute(this, attrName); | |
4891 }, | |
4892 configurable: true, | |
4893 enumerable: true | |
4894 }); | |
4895 } | |
4896 | |
4897 setterDirtiesAttribute(Element.prototype, 'id'); | |
4898 setterDirtiesAttribute(Element.prototype, 'className', 'class'); | |
4899 | |
4900 mixin(Element.prototype, ChildNodeInterface); | 5042 mixin(Element.prototype, ChildNodeInterface); |
4901 mixin(Element.prototype, GetElementsByInterface); | 5043 mixin(Element.prototype, GetElementsByInterface); |
4902 mixin(Element.prototype, ParentNodeInterface); | 5044 mixin(Element.prototype, ParentNodeInterface); |
4903 mixin(Element.prototype, SelectorsInterface); | 5045 mixin(Element.prototype, SelectorsInterface); |
4904 | 5046 |
4905 registerWrapper(OriginalElement, Element, | 5047 registerWrapper(OriginalElement, Element, |
4906 document.createElementNS(null, 'x')); | 5048 document.createElementNS(null, 'x')); |
4907 | 5049 |
4908 // TODO(arv): Export setterDirtiesAttribute and apply it to more bindings | 5050 scope.invalidateRendererBasedOnAttribute = invalidateRendererBasedOnAttribute; |
4909 // that reflect attributes. | |
4910 scope.matchesNames = matchesNames; | 5051 scope.matchesNames = matchesNames; |
4911 scope.wrappers.Element = Element; | 5052 scope.wrappers.Element = Element; |
4912 })(window.ShadowDOMPolyfill); | 5053 })(window.ShadowDOMPolyfill); |
4913 | 5054 |
4914 // Copyright 2013 The Polymer Authors. All rights reserved. | 5055 // Copyright 2013 The Polymer Authors. All rights reserved. |
4915 // Use of this source code is goverened by a BSD-style | 5056 // Use of this source code is goverened by a BSD-style |
4916 // license that can be found in the LICENSE file. | 5057 // license that can be found in the LICENSE file. |
4917 | 5058 |
4918 (function(scope) { | 5059 (function(scope) { |
4919 'use strict'; | 5060 'use strict'; |
(...skipping 875 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5795 scope.wrappers.HTMLUnknownElement = HTMLUnknownElement; | 5936 scope.wrappers.HTMLUnknownElement = HTMLUnknownElement; |
5796 })(window.ShadowDOMPolyfill); | 5937 })(window.ShadowDOMPolyfill); |
5797 | 5938 |
5798 // Copyright 2014 The Polymer Authors. All rights reserved. | 5939 // Copyright 2014 The Polymer Authors. All rights reserved. |
5799 // Use of this source code is goverened by a BSD-style | 5940 // Use of this source code is goverened by a BSD-style |
5800 // license that can be found in the LICENSE file. | 5941 // license that can be found in the LICENSE file. |
5801 | 5942 |
5802 (function(scope) { | 5943 (function(scope) { |
5803 'use strict'; | 5944 'use strict'; |
5804 | 5945 |
| 5946 var Element = scope.wrappers.Element; |
| 5947 var HTMLElement = scope.wrappers.HTMLElement; |
5805 var registerObject = scope.registerObject; | 5948 var registerObject = scope.registerObject; |
5806 | 5949 |
5807 var SVG_NS = 'http://www.w3.org/2000/svg'; | 5950 var SVG_NS = 'http://www.w3.org/2000/svg'; |
5808 var svgTitleElement = document.createElementNS(SVG_NS, 'title'); | 5951 var svgTitleElement = document.createElementNS(SVG_NS, 'title'); |
5809 var SVGTitleElement = registerObject(svgTitleElement); | 5952 var SVGTitleElement = registerObject(svgTitleElement); |
5810 var SVGElement = Object.getPrototypeOf(SVGTitleElement.prototype).constructor; | 5953 var SVGElement = Object.getPrototypeOf(SVGTitleElement.prototype).constructor; |
5811 | 5954 |
| 5955 // IE11 does not have classList for SVG elements. The spec says that classList |
| 5956 // is an accessor on Element, but IE11 puts classList on HTMLElement, leaving |
| 5957 // SVGElement without a classList property. We therefore move the accessor for |
| 5958 // IE11. |
| 5959 if (!('classList' in svgTitleElement)) { |
| 5960 var descr = Object.getOwnPropertyDescriptor(Element.prototype, 'classList'); |
| 5961 Object.defineProperty(HTMLElement.prototype, 'classList', descr); |
| 5962 delete Element.prototype.classList; |
| 5963 } |
| 5964 |
5812 scope.wrappers.SVGElement = SVGElement; | 5965 scope.wrappers.SVGElement = SVGElement; |
5813 })(window.ShadowDOMPolyfill); | 5966 })(window.ShadowDOMPolyfill); |
5814 | 5967 |
5815 // Copyright 2014 The Polymer Authors. All rights reserved. | 5968 // Copyright 2014 The Polymer Authors. All rights reserved. |
5816 // Use of this source code is goverened by a BSD-style | 5969 // Use of this source code is goverened by a BSD-style |
5817 // license that can be found in the LICENSE file. | 5970 // license that can be found in the LICENSE file. |
5818 | 5971 |
5819 (function(scope) { | 5972 (function(scope) { |
5820 'use strict'; | 5973 'use strict'; |
5821 | 5974 |
(...skipping 1271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7093 }, | 7246 }, |
7094 elementFromPoint: function(x, y) { | 7247 elementFromPoint: function(x, y) { |
7095 return elementFromPoint(this, this, x, y); | 7248 return elementFromPoint(this, this, x, y); |
7096 }, | 7249 }, |
7097 importNode: function(node, deep) { | 7250 importNode: function(node, deep) { |
7098 return cloneNode(node, deep, this.impl); | 7251 return cloneNode(node, deep, this.impl); |
7099 }, | 7252 }, |
7100 getSelection: function() { | 7253 getSelection: function() { |
7101 renderAllPending(); | 7254 renderAllPending(); |
7102 return new Selection(originalGetSelection.call(unwrap(this))); | 7255 return new Selection(originalGetSelection.call(unwrap(this))); |
| 7256 }, |
| 7257 getElementsByName: function(name) { |
| 7258 return SelectorsInterface.querySelectorAll.call(this, |
| 7259 '[name=' + JSON.stringify(String(name)) + ']'); |
7103 } | 7260 } |
7104 }); | 7261 }); |
7105 | 7262 |
7106 if (document.registerElement) { | 7263 if (document.registerElement) { |
7107 var originalRegisterElement = document.registerElement; | 7264 var originalRegisterElement = document.registerElement; |
7108 Document.prototype.registerElement = function(tagName, object) { | 7265 Document.prototype.registerElement = function(tagName, object) { |
7109 var prototype, extendsOption; | 7266 var prototype, extendsOption; |
7110 if (object !== undefined) { | 7267 if (object !== undefined) { |
7111 prototype = object.prototype; | 7268 prototype = object.prototype; |
7112 extendsOption = object.extends; | 7269 extendsOption = object.extends; |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7237 'createComment', | 7394 'createComment', |
7238 'createDocumentFragment', | 7395 'createDocumentFragment', |
7239 'createElement', | 7396 'createElement', |
7240 'createElementNS', | 7397 'createElementNS', |
7241 'createEvent', | 7398 'createEvent', |
7242 'createEventNS', | 7399 'createEventNS', |
7243 'createRange', | 7400 'createRange', |
7244 'createTextNode', | 7401 'createTextNode', |
7245 'elementFromPoint', | 7402 'elementFromPoint', |
7246 'getElementById', | 7403 'getElementById', |
| 7404 'getElementsByName', |
7247 'getSelection', | 7405 'getSelection', |
7248 ]); | 7406 ]); |
7249 | 7407 |
7250 mixin(Document.prototype, GetElementsByInterface); | 7408 mixin(Document.prototype, GetElementsByInterface); |
7251 mixin(Document.prototype, ParentNodeInterface); | 7409 mixin(Document.prototype, ParentNodeInterface); |
7252 mixin(Document.prototype, SelectorsInterface); | 7410 mixin(Document.prototype, SelectorsInterface); |
7253 | 7411 |
7254 mixin(Document.prototype, { | 7412 mixin(Document.prototype, { |
7255 get implementation() { | 7413 get implementation() { |
7256 var implementation = implementationTable.get(this); | 7414 var implementation = implementationTable.get(this); |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7527 | 7685 |
7528 /* | 7686 /* |
7529 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | 7687 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
7530 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | 7688 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
7531 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | 7689 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
7532 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | 7690 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
7533 * Code distributed by Google as part of the polymer project is also | 7691 * Code distributed by Google as part of the polymer project is also |
7534 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | 7692 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
7535 */ | 7693 */ |
7536 | 7694 |
7537 (function() { | 7695 (function(scope) { |
7538 | 7696 |
7539 // convenient global | 7697 // convenient global |
7540 window.wrap = ShadowDOMPolyfill.wrapIfNeeded; | 7698 window.wrap = ShadowDOMPolyfill.wrapIfNeeded; |
7541 window.unwrap = ShadowDOMPolyfill.unwrapIfNeeded; | 7699 window.unwrap = ShadowDOMPolyfill.unwrapIfNeeded; |
7542 | 7700 |
7543 // users may want to customize other types | 7701 // users may want to customize other types |
7544 // TODO(sjmiles): 'button' is now supported by ShadowDOMPolyfill, but | 7702 // TODO(sjmiles): 'button' is now supported by ShadowDOMPolyfill, but |
7545 // I've left this code here in case we need to temporarily patch another | 7703 // I've left this code here in case we need to temporarily patch another |
7546 // type | 7704 // type |
7547 /* | 7705 /* |
(...skipping 12 matching lines...) Expand all Loading... |
7560 Object.getOwnPropertyDescriptor(Element.prototype, 'shadowRoot')); | 7718 Object.getOwnPropertyDescriptor(Element.prototype, 'shadowRoot')); |
7561 | 7719 |
7562 var originalCreateShadowRoot = Element.prototype.createShadowRoot; | 7720 var originalCreateShadowRoot = Element.prototype.createShadowRoot; |
7563 Element.prototype.createShadowRoot = function() { | 7721 Element.prototype.createShadowRoot = function() { |
7564 var root = originalCreateShadowRoot.call(this); | 7722 var root = originalCreateShadowRoot.call(this); |
7565 CustomElements.watchShadow(this); | 7723 CustomElements.watchShadow(this); |
7566 return root; | 7724 return root; |
7567 }; | 7725 }; |
7568 | 7726 |
7569 Element.prototype.webkitCreateShadowRoot = Element.prototype.createShadowRoot; | 7727 Element.prototype.webkitCreateShadowRoot = Element.prototype.createShadowRoot; |
7570 })(); | 7728 |
| 7729 function queryShadow(node, selector) { |
| 7730 var m, el = node.firstElementChild; |
| 7731 var shadows, sr, i; |
| 7732 shadows = []; |
| 7733 sr = node.shadowRoot; |
| 7734 while(sr) { |
| 7735 shadows.push(sr); |
| 7736 sr = sr.olderShadowRoot; |
| 7737 } |
| 7738 for(i = shadows.length - 1; i >= 0; i--) { |
| 7739 m = shadows[i].querySelector(selector); |
| 7740 if (m) { |
| 7741 return m; |
| 7742 } |
| 7743 } |
| 7744 while(el) { |
| 7745 m = queryShadow(el, selector); |
| 7746 if (m) { |
| 7747 return m; |
| 7748 } |
| 7749 el = el.nextElementSibling; |
| 7750 } |
| 7751 return null; |
| 7752 } |
| 7753 |
| 7754 function queryAllShadows(node, selector, results) { |
| 7755 var el = node.firstElementChild; |
| 7756 var temp, sr, shadows, i, j; |
| 7757 shadows = []; |
| 7758 sr = node.shadowRoot; |
| 7759 while(sr) { |
| 7760 shadows.push(sr); |
| 7761 sr = sr.olderShadowRoot; |
| 7762 } |
| 7763 for (i = shadows.length - 1; i >= 0; i--) { |
| 7764 temp = shadows[i].querySelectorAll(selector); |
| 7765 for(j = 0; j < temp.length; j++) { |
| 7766 results.push(temp[j]); |
| 7767 } |
| 7768 } |
| 7769 while (el) { |
| 7770 queryAllShadows(el, selector, results); |
| 7771 el = el.nextElementSibling; |
| 7772 } |
| 7773 return results; |
| 7774 } |
| 7775 |
| 7776 scope.queryAllShadows = function(node, selector, all) { |
| 7777 if (all) { |
| 7778 return queryAllShadows(node, selector, []); |
| 7779 } else { |
| 7780 return queryShadow(node, selector); |
| 7781 } |
| 7782 }; |
| 7783 })(window.Platform); |
7571 | 7784 |
7572 /* | 7785 /* |
7573 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | 7786 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
7574 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | 7787 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
7575 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | 7788 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
7576 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | 7789 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
7577 * Code distributed by Google as part of the polymer project is also | 7790 * Code distributed by Google as part of the polymer project is also |
7578 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | 7791 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
7579 */ | 7792 */ |
7580 | 7793 |
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7962 for (var i=0; i < combinatorsRe.length; i++) { | 8175 for (var i=0; i < combinatorsRe.length; i++) { |
7963 cssText = cssText.replace(combinatorsRe[i], ' '); | 8176 cssText = cssText.replace(combinatorsRe[i], ' '); |
7964 } | 8177 } |
7965 return cssText; | 8178 return cssText; |
7966 }, | 8179 }, |
7967 // change a selector like 'div' to 'name div' | 8180 // change a selector like 'div' to 'name div' |
7968 scopeRules: function(cssRules, scopeSelector) { | 8181 scopeRules: function(cssRules, scopeSelector) { |
7969 var cssText = ''; | 8182 var cssText = ''; |
7970 if (cssRules) { | 8183 if (cssRules) { |
7971 Array.prototype.forEach.call(cssRules, function(rule) { | 8184 Array.prototype.forEach.call(cssRules, function(rule) { |
7972 if (rule.selectorText && (rule.style && rule.style.cssText)) { | 8185 if (rule.selectorText && (rule.style && rule.style.cssText !== undefined
)) { |
7973 cssText += this.scopeSelector(rule.selectorText, scopeSelector, | 8186 cssText += this.scopeSelector(rule.selectorText, scopeSelector, |
7974 this.strictStyling) + ' {\n\t'; | 8187 this.strictStyling) + ' {\n\t'; |
7975 cssText += this.propertiesFromRule(rule) + '\n}\n\n'; | 8188 cssText += this.propertiesFromRule(rule) + '\n}\n\n'; |
7976 } else if (rule.type === CSSRule.MEDIA_RULE) { | 8189 } else if (rule.type === CSSRule.MEDIA_RULE) { |
7977 cssText += '@media ' + rule.media.mediaText + ' {\n'; | 8190 cssText += '@media ' + rule.media.mediaText + ' {\n'; |
7978 cssText += this.scopeRules(rule.cssRules, scopeSelector); | 8191 cssText += this.scopeRules(rule.cssRules, scopeSelector); |
7979 cssText += '\n}\n\n'; | 8192 cssText += '\n}\n\n'; |
7980 } else if (rule.cssText) { | 8193 } else { |
7981 cssText += rule.cssText + '\n\n'; | 8194 // TODO(sjmiles): KEYFRAMES_RULE in IE11 throws when we query cssText |
| 8195 // 'cssText' in rule returns true, but rule.cssText throws anyway |
| 8196 // We can test the rule type, e.g. |
| 8197 // else if (rule.type !== CSSRule.KEYFRAMES_RULE && rule.cssText) { |
| 8198 // but this will prevent cssText propagation in other browsers which |
| 8199 // support it. |
| 8200 // KEYFRAMES_RULE has a CSSRuleSet, so the text can probably be recons
tructed |
| 8201 // from that collection; this would be a proper fix. |
| 8202 // For now, I'm trapping the exception so IE11 is unblocked in other a
reas. |
| 8203 try { |
| 8204 if (rule.cssText) { |
| 8205 cssText += rule.cssText + '\n\n'; |
| 8206 } |
| 8207 } catch(x) { |
| 8208 // squelch |
| 8209 } |
7982 } | 8210 } |
7983 }, this); | 8211 }, this); |
7984 } | 8212 } |
7985 return cssText; | 8213 return cssText; |
7986 }, | 8214 }, |
7987 scopeSelector: function(selector, scopeSelector, strict) { | 8215 scopeSelector: function(selector, scopeSelector, strict) { |
7988 var r = [], parts = selector.split(','); | 8216 var r = [], parts = selector.split(','); |
7989 parts.forEach(function(p) { | 8217 parts.forEach(function(p) { |
7990 p = p.trim(); | 8218 p = p.trim(); |
7991 if (this.selectorNeedsScoping(p, scopeSelector)) { | 8219 if (this.selectorNeedsScoping(p, scopeSelector)) { |
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8299 if (style.parentNode !== head) { | 8527 if (style.parentNode !== head) { |
8300 // replace links in head | 8528 // replace links in head |
8301 if (elt.parentNode === head) { | 8529 if (elt.parentNode === head) { |
8302 head.replaceChild(style, elt); | 8530 head.replaceChild(style, elt); |
8303 } else { | 8531 } else { |
8304 head.appendChild(style); | 8532 head.appendChild(style); |
8305 } | 8533 } |
8306 } | 8534 } |
8307 style.__importParsed = true; | 8535 style.__importParsed = true; |
8308 this.markParsingComplete(elt); | 8536 this.markParsingComplete(elt); |
| 8537 this.parseNext(); |
8309 } | 8538 } |
8310 | 8539 |
8311 var hasResource = HTMLImports.parser.hasResource; | 8540 var hasResource = HTMLImports.parser.hasResource; |
8312 HTMLImports.parser.hasResource = function(node) { | 8541 HTMLImports.parser.hasResource = function(node) { |
8313 if (node.localName === 'link' && node.rel === 'stylesheet' && | 8542 if (node.localName === 'link' && node.rel === 'stylesheet' && |
8314 node.hasAttribute(SHIM_ATTRIBUTE)) { | 8543 node.hasAttribute(SHIM_ATTRIBUTE)) { |
8315 return (node.__resource); | 8544 return (node.__resource); |
8316 } else { | 8545 } else { |
8317 return hasResource.call(this, node); | 8546 return hasResource.call(this, node); |
8318 } | 8547 } |
(...skipping 1094 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9413 | 9642 |
9414 function module(name, dependsOrFactory, moduleFactory) { | 9643 function module(name, dependsOrFactory, moduleFactory) { |
9415 var module; | 9644 var module; |
9416 switch (arguments.length) { | 9645 switch (arguments.length) { |
9417 case 0: | 9646 case 0: |
9418 return; | 9647 return; |
9419 case 1: | 9648 case 1: |
9420 module = null; | 9649 module = null; |
9421 break; | 9650 break; |
9422 case 2: | 9651 case 2: |
| 9652 // dependsOrFactory is `factory` in this case |
9423 module = dependsOrFactory.apply(this); | 9653 module = dependsOrFactory.apply(this); |
9424 break; | 9654 break; |
9425 default: | 9655 default: |
| 9656 // dependsOrFactory is `depends` in this case |
9426 module = withDependencies(moduleFactory, dependsOrFactory); | 9657 module = withDependencies(moduleFactory, dependsOrFactory); |
9427 break; | 9658 break; |
9428 } | 9659 } |
9429 modules[name] = module; | 9660 modules[name] = module; |
9430 }; | 9661 }; |
9431 | 9662 |
9432 function marshal(name) { | 9663 function marshal(name) { |
9433 return modules[name]; | 9664 return modules[name]; |
9434 } | 9665 } |
9435 | 9666 |
9436 var modules = {}; | 9667 var modules = {}; |
9437 | 9668 |
9438 function using(depends, task) { | 9669 function using(depends, task) { |
9439 HTMLImports.whenImportsReady(function() { | 9670 HTMLImports.whenImportsReady(function() { |
9440 withDependencies(task, depends); | 9671 withDependencies(task, depends); |
9441 }); | 9672 }); |
9442 }; | 9673 }; |
9443 | 9674 |
9444 // exports | 9675 // exports |
9445 | 9676 |
9446 scope.marshal = marshal; | 9677 scope.marshal = marshal; |
9447 scope.module = module; | 9678 // `module` confuses commonjs detectors |
| 9679 scope.modularize = module; |
9448 scope.using = using; | 9680 scope.using = using; |
9449 | 9681 |
9450 })(window); | 9682 })(window); |
9451 | 9683 |
9452 /* | 9684 /* |
9453 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | 9685 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
9454 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | 9686 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
9455 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | 9687 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
9456 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | 9688 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
9457 * Code distributed by Google as part of the polymer project is also | 9689 * Code distributed by Google as part of the polymer project is also |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9544 } | 9776 } |
9545 }, | 9777 }, |
9546 resolveElementAttributes: function(node, url) { | 9778 resolveElementAttributes: function(node, url) { |
9547 url = url || node.ownerDocument.baseURI; | 9779 url = url || node.ownerDocument.baseURI; |
9548 URL_ATTRS.forEach(function(v) { | 9780 URL_ATTRS.forEach(function(v) { |
9549 var attr = node.attributes[v]; | 9781 var attr = node.attributes[v]; |
9550 var value = attr && attr.value; | 9782 var value = attr && attr.value; |
9551 var replacement; | 9783 var replacement; |
9552 if (value && value.search(URL_TEMPLATE_SEARCH) < 0) { | 9784 if (value && value.search(URL_TEMPLATE_SEARCH) < 0) { |
9553 if (v === 'style') { | 9785 if (v === 'style') { |
9554 replacement = replaceUrlsInCssText(value, url, CSS_URL_REGEXP); | 9786 replacement = replaceUrlsInCssText(value, url, false, CSS_URL_REGEXP); |
9555 } else { | 9787 } else { |
9556 replacement = resolveRelativeUrl(url, value); | 9788 replacement = resolveRelativeUrl(url, value); |
9557 } | 9789 } |
9558 attr.value = replacement; | 9790 attr.value = replacement; |
9559 } | 9791 } |
9560 }); | 9792 }); |
9561 } | 9793 } |
9562 }; | 9794 }; |
9563 | 9795 |
9564 var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g; | 9796 var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g; |
9565 var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g; | 9797 var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g; |
9566 var URL_ATTRS = ['href', 'src', 'action', 'style']; | 9798 var URL_ATTRS = ['href', 'src', 'action', 'style', 'url']; |
9567 var URL_ATTRS_SELECTOR = '[' + URL_ATTRS.join('],[') + ']'; | 9799 var URL_ATTRS_SELECTOR = '[' + URL_ATTRS.join('],[') + ']'; |
9568 var URL_TEMPLATE_SEARCH = '{{.*}}'; | 9800 var URL_TEMPLATE_SEARCH = '{{.*}}'; |
9569 | 9801 |
9570 function replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, regexp) { | 9802 function replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, regexp) { |
9571 return cssText.replace(regexp, function(m, pre, url, post) { | 9803 return cssText.replace(regexp, function(m, pre, url, post) { |
9572 var urlPath = url.replace(/["']/g, ''); | 9804 var urlPath = url.replace(/["']/g, ''); |
9573 urlPath = resolveRelativeUrl(baseUrl, urlPath, keepAbsolute); | 9805 urlPath = resolveRelativeUrl(baseUrl, urlPath, keepAbsolute); |
9574 return pre + '\'' + urlPath + '\'' + post; | 9806 return pre + '\'' + urlPath + '\'' + post; |
9575 }); | 9807 }); |
9576 } | 9808 } |
(...skipping 677 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10254 var body = pieces[1]; | 10486 var body = pieces[1]; |
10255 if(header.indexOf(';base64') > -1) { | 10487 if(header.indexOf(';base64') > -1) { |
10256 body = atob(body); | 10488 body = atob(body); |
10257 } else { | 10489 } else { |
10258 body = decodeURIComponent(body); | 10490 body = decodeURIComponent(body); |
10259 } | 10491 } |
10260 setTimeout(function() { | 10492 setTimeout(function() { |
10261 this.receive(url, elt, null, body); | 10493 this.receive(url, elt, null, body); |
10262 }.bind(this), 0); | 10494 }.bind(this), 0); |
10263 } else { | 10495 } else { |
10264 var receiveXhr = function(err, resource) { | 10496 var receiveXhr = function(err, resource, redirectedUrl) { |
10265 this.receive(url, elt, err, resource); | 10497 this.receive(url, elt, err, resource, redirectedUrl); |
10266 }.bind(this); | 10498 }.bind(this); |
10267 xhr.load(url, receiveXhr); | 10499 xhr.load(url, receiveXhr); |
10268 // TODO(sorvell): blocked on) | 10500 // TODO(sorvell): blocked on) |
10269 // https://code.google.com/p/chromium/issues/detail?id=257221 | 10501 // https://code.google.com/p/chromium/issues/detail?id=257221 |
10270 // xhr'ing for a document makes scripts in imports runnable; otherwise | 10502 // xhr'ing for a document makes scripts in imports runnable; otherwise |
10271 // they are not; however, it requires that we have doctype=html in | 10503 // they are not; however, it requires that we have doctype=html in |
10272 // the import which is unacceptable. This is only needed on Chrome | 10504 // the import which is unacceptable. This is only needed on Chrome |
10273 // to avoid the bug above. | 10505 // to avoid the bug above. |
10274 /* | 10506 /* |
10275 if (isDocumentLink(elt)) { | 10507 if (isDocumentLink(elt)) { |
10276 xhr.loadDocument(url, receiveXhr); | 10508 xhr.loadDocument(url, receiveXhr); |
10277 } else { | 10509 } else { |
10278 xhr.load(url, receiveXhr); | 10510 xhr.load(url, receiveXhr); |
10279 } | 10511 } |
10280 */ | 10512 */ |
10281 } | 10513 } |
10282 }, | 10514 }, |
10283 receive: function(url, elt, err, resource) { | 10515 receive: function(url, elt, err, resource, redirectedUrl) { |
10284 this.cache[url] = resource; | 10516 this.cache[url] = resource; |
10285 var $p = this.pending[url]; | 10517 var $p = this.pending[url]; |
| 10518 if ( redirectedUrl && redirectedUrl !== url ) { |
| 10519 this.cache[redirectedUrl] = resource; |
| 10520 $p = $p.concat(this.pending[redirectedUrl]); |
| 10521 } |
10286 for (var i=0, l=$p.length, p; (i<l) && (p=$p[i]); i++) { | 10522 for (var i=0, l=$p.length, p; (i<l) && (p=$p[i]); i++) { |
10287 //if (!err) { | 10523 //if (!err) { |
10288 this.onload(url, p, resource); | 10524 // If url was redirected, use the redirected location so paths are |
| 10525 // calculated relative to that. |
| 10526 this.onload(redirectedUrl || url, p, resource); |
10289 //} | 10527 //} |
10290 this.tail(); | 10528 this.tail(); |
10291 } | 10529 } |
10292 this.pending[url] = null; | 10530 this.pending[url] = null; |
| 10531 if ( redirectedUrl && redirectedUrl !== url ) { |
| 10532 this.pending[redirectedUrl] = null; |
| 10533 } |
10293 }, | 10534 }, |
10294 tail: function() { | 10535 tail: function() { |
10295 --this.inflight; | 10536 --this.inflight; |
10296 this.checkDone(); | 10537 this.checkDone(); |
10297 }, | 10538 }, |
10298 checkDone: function() { | 10539 checkDone: function() { |
10299 if (!this.inflight) { | 10540 if (!this.inflight) { |
10300 this.oncomplete(); | 10541 this.oncomplete(); |
10301 } | 10542 } |
10302 } | 10543 } |
10303 }; | 10544 }; |
10304 | 10545 |
10305 xhr = xhr || { | 10546 xhr = xhr || { |
10306 async: true, | 10547 async: true, |
10307 ok: function(request) { | 10548 ok: function(request) { |
10308 return (request.status >= 200 && request.status < 300) | 10549 return (request.status >= 200 && request.status < 300) |
10309 || (request.status === 304) | 10550 || (request.status === 304) |
10310 || (request.status === 0); | 10551 || (request.status === 0); |
10311 }, | 10552 }, |
10312 load: function(url, next, nextContext) { | 10553 load: function(url, next, nextContext) { |
10313 var request = new XMLHttpRequest(); | 10554 var request = new XMLHttpRequest(); |
10314 if (scope.flags.debug || scope.flags.bust) { | 10555 if (scope.flags.debug || scope.flags.bust) { |
10315 url += '?' + Math.random(); | 10556 url += '?' + Math.random(); |
10316 } | 10557 } |
10317 request.open('GET', url, xhr.async); | 10558 request.open('GET', url, xhr.async); |
10318 request.addEventListener('readystatechange', function(e) { | 10559 request.addEventListener('readystatechange', function(e) { |
10319 if (request.readyState === 4) { | 10560 if (request.readyState === 4) { |
| 10561 // Servers redirecting an import can add a Location header to help us |
| 10562 // polyfill correctly. |
| 10563 var locationHeader = request.getResponseHeader("Location"); |
| 10564 var redirectedUrl = null; |
| 10565 if (locationHeader) { |
| 10566 var redirectedUrl = (locationHeader.substr( 0, 1 ) === "/") |
| 10567 ? location.origin + locationHeader // Location is a relative path |
| 10568 : redirectedUrl; // Full path |
| 10569 } |
10320 next.call(nextContext, !xhr.ok(request) && request, | 10570 next.call(nextContext, !xhr.ok(request) && request, |
10321 request.response || request.responseText, url); | 10571 request.response || request.responseText, redirectedUrl); |
10322 } | 10572 } |
10323 }); | 10573 }); |
10324 request.send(); | 10574 request.send(); |
10325 return request; | 10575 return request; |
10326 }, | 10576 }, |
10327 loadDocument: function(url, next, nextContext) { | 10577 loadDocument: function(url, next, nextContext) { |
10328 this.load(url, next, nextContext).responseType = 'document'; | 10578 this.load(url, next, nextContext).responseType = 'document'; |
10329 } | 10579 } |
10330 }; | 10580 }; |
10331 | 10581 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10385 if (this.isParsed(elt)) { | 10635 if (this.isParsed(elt)) { |
10386 flags.parse && console.log('[%s] is already parsed', elt.localName); | 10636 flags.parse && console.log('[%s] is already parsed', elt.localName); |
10387 return; | 10637 return; |
10388 } | 10638 } |
10389 var fn = this[this.map[elt.localName]]; | 10639 var fn = this[this.map[elt.localName]]; |
10390 if (fn) { | 10640 if (fn) { |
10391 this.markParsing(elt); | 10641 this.markParsing(elt); |
10392 fn.call(this, elt); | 10642 fn.call(this, elt); |
10393 } | 10643 } |
10394 }, | 10644 }, |
10395 // only 1 element may be parsed at a time; parsing is async so, each | 10645 // only 1 element may be parsed at a time; parsing is async so each |
10396 // parsing implementation must inform the system that parsing is complete | 10646 // parsing implementation must inform the system that parsing is complete |
10397 // via markParsingComplete. | 10647 // via markParsingComplete. |
| 10648 // To prompt the system to parse the next element, parseNext should then be |
| 10649 // called. |
| 10650 // Note, parseNext used to be included at the end of markParsingComplete, but |
| 10651 // we must not do this so that, for example, we can (1) mark parsing complete |
| 10652 // then (2) fire an import load event, and then (3) parse the next resource. |
10398 markParsing: function(elt) { | 10653 markParsing: function(elt) { |
10399 flags.parse && console.log('parsing', elt); | 10654 flags.parse && console.log('parsing', elt); |
10400 this.parsingElement = elt; | 10655 this.parsingElement = elt; |
10401 }, | 10656 }, |
10402 markParsingComplete: function(elt) { | 10657 markParsingComplete: function(elt) { |
10403 elt.__importParsed = true; | 10658 elt.__importParsed = true; |
10404 if (elt.__importElement) { | 10659 if (elt.__importElement) { |
10405 elt.__importElement.__importParsed = true; | 10660 elt.__importElement.__importParsed = true; |
10406 } | 10661 } |
10407 this.parsingElement = null; | 10662 this.parsingElement = null; |
10408 flags.parse && console.log('completed', elt); | 10663 flags.parse && console.log('completed', elt); |
10409 this.parseNext(); | 10664 }, |
| 10665 invalidateParse: function(doc) { |
| 10666 if (doc && doc.__importLink) { |
| 10667 doc.__importParsed = doc.__importLink.__importParsed = false; |
| 10668 this.parseSoon(); |
| 10669 } |
| 10670 }, |
| 10671 parseSoon: function() { |
| 10672 if (this._parseSoon) { |
| 10673 cancelAnimationFrame(this._parseDelay); |
| 10674 } |
| 10675 var parser = this; |
| 10676 this._parseSoon = requestAnimationFrame(function() { |
| 10677 parser.parseNext(); |
| 10678 }); |
10410 }, | 10679 }, |
10411 parseImport: function(elt) { | 10680 parseImport: function(elt) { |
10412 elt.import.__importParsed = true; | |
10413 // TODO(sorvell): consider if there's a better way to do this; | 10681 // TODO(sorvell): consider if there's a better way to do this; |
10414 // expose an imports parsing hook; this is needed, for example, by the | 10682 // expose an imports parsing hook; this is needed, for example, by the |
10415 // CustomElements polyfill. | 10683 // CustomElements polyfill. |
10416 if (HTMLImports.__importsParsingHook) { | 10684 if (HTMLImports.__importsParsingHook) { |
10417 HTMLImports.__importsParsingHook(elt); | 10685 HTMLImports.__importsParsingHook(elt); |
10418 } | 10686 } |
| 10687 elt.import.__importParsed = true; |
| 10688 this.markParsingComplete(elt); |
10419 // fire load event | 10689 // fire load event |
10420 if (elt.__resource) { | 10690 if (elt.__resource) { |
10421 elt.dispatchEvent(new CustomEvent('load', {bubbles: false})); | 10691 elt.dispatchEvent(new CustomEvent('load', {bubbles: false})); |
10422 } else { | 10692 } else { |
10423 elt.dispatchEvent(new CustomEvent('error', {bubbles: false})); | 10693 elt.dispatchEvent(new CustomEvent('error', {bubbles: false})); |
10424 } | 10694 } |
10425 // TODO(sorvell): workaround for Safari addEventListener not working | 10695 // TODO(sorvell): workaround for Safari addEventListener not working |
10426 // for elements not in the main document. | 10696 // for elements not in the main document. |
10427 if (elt.__pending) { | 10697 if (elt.__pending) { |
10428 var fn; | 10698 var fn; |
10429 while (elt.__pending.length) { | 10699 while (elt.__pending.length) { |
10430 fn = elt.__pending.shift(); | 10700 fn = elt.__pending.shift(); |
10431 if (fn) { | 10701 if (fn) { |
10432 fn({target: elt}); | 10702 fn({target: elt}); |
10433 } | 10703 } |
10434 } | 10704 } |
10435 } | 10705 } |
10436 this.markParsingComplete(elt); | 10706 this.parseNext(); |
10437 }, | 10707 }, |
10438 parseLink: function(linkElt) { | 10708 parseLink: function(linkElt) { |
10439 if (nodeIsImport(linkElt)) { | 10709 if (nodeIsImport(linkElt)) { |
10440 this.parseImport(linkElt); | 10710 this.parseImport(linkElt); |
10441 } else { | 10711 } else { |
10442 // make href absolute | 10712 // make href absolute |
10443 linkElt.href = linkElt.href; | 10713 linkElt.href = linkElt.href; |
10444 this.parseGeneric(linkElt); | 10714 this.parseGeneric(linkElt); |
10445 } | 10715 } |
10446 }, | 10716 }, |
10447 parseStyle: function(elt) { | 10717 parseStyle: function(elt) { |
10448 // TODO(sorvell): style element load event can just not fire so clone styles | 10718 // TODO(sorvell): style element load event can just not fire so clone styles |
10449 var src = elt; | 10719 var src = elt; |
10450 elt = cloneStyle(elt); | 10720 elt = cloneStyle(elt); |
10451 elt.__importElement = src; | 10721 elt.__importElement = src; |
10452 this.parseGeneric(elt); | 10722 this.parseGeneric(elt); |
10453 }, | 10723 }, |
10454 parseGeneric: function(elt) { | 10724 parseGeneric: function(elt) { |
10455 this.trackElement(elt); | 10725 this.trackElement(elt); |
10456 document.head.appendChild(elt); | 10726 document.head.appendChild(elt); |
10457 }, | 10727 }, |
10458 // tracks when a loadable element has loaded | 10728 // tracks when a loadable element has loaded |
10459 trackElement: function(elt, callback) { | 10729 trackElement: function(elt, callback) { |
10460 var self = this; | 10730 var self = this; |
10461 var done = function(e) { | 10731 var done = function(e) { |
10462 if (callback) { | 10732 if (callback) { |
10463 callback(e); | 10733 callback(e); |
10464 } | 10734 } |
10465 self.markParsingComplete(elt); | 10735 self.markParsingComplete(elt); |
| 10736 self.parseNext(); |
10466 }; | 10737 }; |
10467 elt.addEventListener('load', done); | 10738 elt.addEventListener('load', done); |
10468 elt.addEventListener('error', done); | 10739 elt.addEventListener('error', done); |
10469 | 10740 |
10470 // NOTE: IE does not fire "load" event for styles that have already loaded | 10741 // NOTE: IE does not fire "load" event for styles that have already loaded |
10471 // This is in violation of the spec, so we try our hardest to work around it | 10742 // This is in violation of the spec, so we try our hardest to work around it |
10472 if (isIe && elt.localName === 'style') { | 10743 if (isIe && elt.localName === 'style') { |
10473 var fakeLoad = false; | 10744 var fakeLoad = false; |
10474 // If there's not @import in the textContent, assume it has loaded | 10745 // If there's not @import in the textContent, assume it has loaded |
10475 if (elt.textContent.indexOf('@import') == -1) { | 10746 if (elt.textContent.indexOf('@import') == -1) { |
(...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10927 Copyright 2013 The Polymer Authors. All rights reserved. | 11198 Copyright 2013 The Polymer Authors. All rights reserved. |
10928 Use of this source code is governed by a BSD-style | 11199 Use of this source code is governed by a BSD-style |
10929 license that can be found in the LICENSE file. | 11200 license that can be found in the LICENSE file. |
10930 */ | 11201 */ |
10931 | 11202 |
10932 (function(scope){ | 11203 (function(scope){ |
10933 | 11204 |
10934 var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE; | 11205 var IMPORT_LINK_TYPE = scope.IMPORT_LINK_TYPE; |
10935 var importSelector = 'link[rel=' + IMPORT_LINK_TYPE + ']'; | 11206 var importSelector = 'link[rel=' + IMPORT_LINK_TYPE + ']'; |
10936 var importer = scope.importer; | 11207 var importer = scope.importer; |
| 11208 var parser = scope.parser; |
10937 | 11209 |
10938 // we track mutations for addedNodes, looking for imports | 11210 // we track mutations for addedNodes, looking for imports |
10939 function handler(mutations) { | 11211 function handler(mutations) { |
10940 for (var i=0, l=mutations.length, m; (i<l) && (m=mutations[i]); i++) { | 11212 for (var i=0, l=mutations.length, m; (i<l) && (m=mutations[i]); i++) { |
10941 if (m.type === 'childList' && m.addedNodes.length) { | 11213 if (m.type === 'childList' && m.addedNodes.length) { |
10942 addedNodes(m.addedNodes); | 11214 addedNodes(m.addedNodes); |
10943 } | 11215 } |
10944 } | 11216 } |
10945 } | 11217 } |
10946 | 11218 |
10947 // find loadable elements and add them to the importer | 11219 // find loadable elements and add them to the importer |
10948 function addedNodes(nodes) { | 11220 function addedNodes(nodes) { |
| 11221 var owner; |
10949 for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) { | 11222 for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) { |
| 11223 owner = owner || n.ownerDocument; |
10950 if (shouldLoadNode(n)) { | 11224 if (shouldLoadNode(n)) { |
10951 importer.loadNode(n); | 11225 importer.loadNode(n); |
10952 } | 11226 } |
10953 if (n.children && n.children.length) { | 11227 if (n.children && n.children.length) { |
10954 addedNodes(n.children); | 11228 addedNodes(n.children); |
10955 } | 11229 } |
10956 } | 11230 } |
| 11231 // TODO(sorvell): This is not the right approach here. We shouldn't need to |
| 11232 // invalidate parsing when an element is added. Disabling this code |
| 11233 // until a better approach is found. |
| 11234 /* |
| 11235 if (owner) { |
| 11236 parser.invalidateParse(owner); |
| 11237 } |
| 11238 */ |
10957 } | 11239 } |
10958 | 11240 |
10959 function shouldLoadNode(node) { | 11241 function shouldLoadNode(node) { |
10960 return (node.nodeType === 1) && matches.call(node, | 11242 return (node.nodeType === 1) && matches.call(node, |
10961 importer.loadSelectorsForNode(node)); | 11243 importer.loadSelectorsForNode(node)); |
10962 } | 11244 } |
10963 | 11245 |
10964 // x-plat matches | 11246 // x-plat matches |
10965 var matches = HTMLElement.prototype.matches || | 11247 var matches = HTMLElement.prototype.matches || |
10966 HTMLElement.prototype.matchesSelector || | 11248 HTMLElement.prototype.matchesSelector || |
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11411 // imports | 11693 // imports |
11412 | 11694 |
11413 if (!scope) { | 11695 if (!scope) { |
11414 scope = window.CustomElements = {flags:{}}; | 11696 scope = window.CustomElements = {flags:{}}; |
11415 } | 11697 } |
11416 var flags = scope.flags; | 11698 var flags = scope.flags; |
11417 | 11699 |
11418 // native document.registerElement? | 11700 // native document.registerElement? |
11419 | 11701 |
11420 var hasNative = Boolean(document.registerElement); | 11702 var hasNative = Boolean(document.registerElement); |
11421 // TODO(sorvell): See https://github.com/Polymer/polymer/issues/399 | 11703 // For consistent timing, use native custom elements only when not polyfilling |
11422 // we'll address this by defaulting to CE polyfill in the presence of the SD | 11704 // other key related web components features. |
11423 // polyfill. This will avoid spamming excess attached/detached callbacks. | 11705 var useNative = !flags.register && hasNative && !window.ShadowDOMPolyfill && (!w
indow.HTMLImports || HTMLImports.useNative); |
11424 // If there is a compelling need to run CE native with SD polyfill, | |
11425 // we'll need to fix this issue. | |
11426 var useNative = !flags.register && hasNative && !window.ShadowDOMPolyfill; | |
11427 | 11706 |
11428 if (useNative) { | 11707 if (useNative) { |
11429 | 11708 |
11430 // stub | 11709 // stub |
11431 var nop = function() {}; | 11710 var nop = function() {}; |
11432 | 11711 |
11433 // exports | 11712 // exports |
11434 scope.registry = {}; | 11713 scope.registry = {}; |
11435 scope.upgradeElement = nop; | 11714 scope.upgradeElement = nop; |
11436 | 11715 |
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11706 var removeAttribute = prototype.removeAttribute; | 11985 var removeAttribute = prototype.removeAttribute; |
11707 prototype.removeAttribute = function(name) { | 11986 prototype.removeAttribute = function(name) { |
11708 changeAttribute.call(this, name, null, removeAttribute); | 11987 changeAttribute.call(this, name, null, removeAttribute); |
11709 } | 11988 } |
11710 prototype.setAttribute._polyfilled = true; | 11989 prototype.setAttribute._polyfilled = true; |
11711 } | 11990 } |
11712 | 11991 |
11713 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/ | 11992 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/ |
11714 // index.html#dfn-attribute-changed-callback | 11993 // index.html#dfn-attribute-changed-callback |
11715 function changeAttribute(name, value, operation) { | 11994 function changeAttribute(name, value, operation) { |
| 11995 name = name.toLowerCase(); |
11716 var oldValue = this.getAttribute(name); | 11996 var oldValue = this.getAttribute(name); |
11717 operation.apply(this, arguments); | 11997 operation.apply(this, arguments); |
11718 var newValue = this.getAttribute(name); | 11998 var newValue = this.getAttribute(name); |
11719 if (this.attributeChangedCallback | 11999 if (this.attributeChangedCallback |
11720 && (newValue !== oldValue)) { | 12000 && (newValue !== oldValue)) { |
11721 this.attributeChangedCallback(name, oldValue, newValue); | 12001 this.attributeChangedCallback(name, oldValue, newValue); |
11722 } | 12002 } |
11723 } | 12003 } |
11724 | 12004 |
11725 // element registry (maps tag names to definitions) | 12005 // element registry (maps tag names to definitions) |
(...skipping 1460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13186 return { | 13466 return { |
13187 bindingMaps: {}, | 13467 bindingMaps: {}, |
13188 raw: bindingDelegate, | 13468 raw: bindingDelegate, |
13189 prepareBinding: delegateFn('prepareBinding'), | 13469 prepareBinding: delegateFn('prepareBinding'), |
13190 prepareInstanceModel: delegateFn('prepareInstanceModel'), | 13470 prepareInstanceModel: delegateFn('prepareInstanceModel'), |
13191 prepareInstancePositionChanged: | 13471 prepareInstancePositionChanged: |
13192 delegateFn('prepareInstancePositionChanged') | 13472 delegateFn('prepareInstancePositionChanged') |
13193 }; | 13473 }; |
13194 }, | 13474 }, |
13195 | 13475 |
13196 // TODO(rafaelw): Assigning .bindingDelegate always succeeds. It may | |
13197 // make sense to issue a warning or even throw if the template is already | |
13198 // "activated", since this would be a strange thing to do. | |
13199 set bindingDelegate(bindingDelegate) { | 13476 set bindingDelegate(bindingDelegate) { |
13200 if (this.delegate_) { | 13477 if (this.delegate_) { |
13201 throw Error('Template must be cleared before a new bindingDelegate ' + | 13478 throw Error('Template must be cleared before a new bindingDelegate ' + |
13202 'can be assigned'); | 13479 'can be assigned'); |
13203 } | 13480 } |
13204 | 13481 |
13205 this.setDelegate_(this.newDelegate_(bindingDelegate)); | 13482 this.setDelegate_(this.newDelegate_(bindingDelegate)); |
13206 }, | 13483 }, |
13207 | 13484 |
13208 get ref_() { | 13485 get ref_() { |
(...skipping 670 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13879 } | 14156 } |
13880 } | 14157 } |
13881 | 14158 |
13882 // exports | 14159 // exports |
13883 scope.flush = flush; | 14160 scope.flush = flush; |
13884 | 14161 |
13885 })(window.Platform); | 14162 })(window.Platform); |
13886 | 14163 |
13887 | 14164 |
13888 //# sourceMappingURL=platform.concat.js.map | 14165 //# sourceMappingURL=platform.concat.js.map |
OLD | NEW |