Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: pkg/shadow_dom/lib/shadow_dom.debug.js

Issue 140853005: update custom elements and shadow dom (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/shadow_dom/REVISIONS ('k') | pkg/shadow_dom/lib/shadow_dom.min.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 if (!HTMLElement.prototype.createShadowRoot 1 if (!HTMLElement.prototype.createShadowRoot
2 || window.__forceShadowDomPolyfill) { 2 || window.__forceShadowDomPolyfill) {
3 3
4 /* 4 /*
5 * Copyright 2013 The Polymer Authors. All rights reserved. 5 * Copyright 2013 The Polymer Authors. All rights reserved.
6 * Use of this source code is governed by a BSD-style 6 * Use of this source code is governed by a BSD-style
7 * license that can be found in the LICENSE file. 7 * license that can be found in the LICENSE file.
8 */ 8 */
9 (function() { 9 (function() {
10 // TODO(jmesserly): fix dart:html to use unprefixed name 10 // TODO(jmesserly): fix dart:html to use unprefixed name
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 this.push(s); 190 this.push(s);
191 return this; 191 return this;
192 } 192 }
193 193
194 s.split(/\s*\.\s*/).filter(function(part) { 194 s.split(/\s*\.\s*/).filter(function(part) {
195 return part; 195 return part;
196 }).forEach(function(part) { 196 }).forEach(function(part) {
197 this.push(part); 197 this.push(part);
198 }, this); 198 }, this);
199 199
200 if (hasEval && !hasObserve && this.length) { 200 if (hasEval && this.length) {
201 this.getValueFrom = this.compiledGetValueFromFn(); 201 this.getValueFrom = this.compiledGetValueFromFn();
202 } 202 }
203 } 203 }
204 204
205 // TODO(rafaelw): Make simple LRU cache 205 // TODO(rafaelw): Make simple LRU cache
206 var pathCache = {}; 206 var pathCache = {};
207 207
208 function getPath(pathString) { 208 function getPath(pathString) {
209 if (pathString instanceof Path) 209 if (pathString instanceof Path)
210 return pathString; 210 return pathString;
(...skipping 17 matching lines...) Expand all
228 Path.get = getPath; 228 Path.get = getPath;
229 229
230 Path.prototype = createObject({ 230 Path.prototype = createObject({
231 __proto__: [], 231 __proto__: [],
232 valid: true, 232 valid: true,
233 233
234 toString: function() { 234 toString: function() {
235 return this.join('.'); 235 return this.join('.');
236 }, 236 },
237 237
238 getValueFrom: function(obj, observedSet) { 238 getValueFrom: function(obj, directObserver) {
239 for (var i = 0; i < this.length; i++) { 239 for (var i = 0; i < this.length; i++) {
240 if (obj == null) 240 if (obj == null)
241 return; 241 return;
242 if (observedSet)
243 observedSet.observe(obj);
244 obj = obj[this[i]]; 242 obj = obj[this[i]];
245 } 243 }
246 return obj; 244 return obj;
247 }, 245 },
248 246
247 iterateObjects: function(obj, observe) {
248 for (var i = 0; i < this.length; i++) {
249 if (i)
250 obj = obj[this[i - 1]];
251 if (!obj)
252 return;
253 observe(obj);
254 }
255 },
256
249 compiledGetValueFromFn: function() { 257 compiledGetValueFromFn: function() {
250 var accessors = this.map(function(ident) { 258 var accessors = this.map(function(ident) {
251 return isIndex(ident) ? '["' + ident + '"]' : '.' + ident; 259 return isIndex(ident) ? '["' + ident + '"]' : '.' + ident;
252 }); 260 });
253 261
254 var str = ''; 262 var str = '';
255 var pathString = 'obj'; 263 var pathString = 'obj';
256 str += 'if (obj != null'; 264 str += 'if (obj != null';
257 var i = 0; 265 var i = 0;
258 for (; i < (this.length - 1); i++) { 266 for (; i < (this.length - 1); i++) {
(...skipping 28 matching lines...) Expand all
287 }); 295 });
288 296
289 var invalidPath = new Path('', constructorIsPrivate); 297 var invalidPath = new Path('', constructorIsPrivate);
290 invalidPath.valid = false; 298 invalidPath.valid = false;
291 invalidPath.getValueFrom = invalidPath.setValueFrom = function() {}; 299 invalidPath.getValueFrom = invalidPath.setValueFrom = function() {};
292 300
293 var MAX_DIRTY_CHECK_CYCLES = 1000; 301 var MAX_DIRTY_CHECK_CYCLES = 1000;
294 302
295 function dirtyCheck(observer) { 303 function dirtyCheck(observer) {
296 var cycles = 0; 304 var cycles = 0;
297 while (cycles < MAX_DIRTY_CHECK_CYCLES && observer.check()) { 305 while (cycles < MAX_DIRTY_CHECK_CYCLES && observer.check_()) {
298 observer.report();
299 cycles++; 306 cycles++;
300 } 307 }
301 if (global.testingExposeCycleCount) 308 if (global.testingExposeCycleCount)
302 global.dirtyCheckCycleCount = cycles; 309 global.dirtyCheckCycleCount = cycles;
310
311 return cycles > 0;
303 } 312 }
304 313
305 function objectIsEmpty(object) { 314 function objectIsEmpty(object) {
306 for (var prop in object) 315 for (var prop in object)
307 return false; 316 return false;
308 return true; 317 return true;
309 } 318 }
310 319
311 function diffIsEmpty(diff) { 320 function diffIsEmpty(diff) {
312 return objectIsEmpty(diff.added) && 321 return objectIsEmpty(diff.added) &&
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 if (Array.isArray(object) && object.length !== oldObject.length) 354 if (Array.isArray(object) && object.length !== oldObject.length)
346 changed.length = object.length; 355 changed.length = object.length;
347 356
348 return { 357 return {
349 added: added, 358 added: added,
350 removed: removed, 359 removed: removed,
351 changed: changed 360 changed: changed
352 }; 361 };
353 } 362 }
354 363
355 function copyObject(object, opt_copy) { 364 var eomTasks = [];
356 var copy = opt_copy || (Array.isArray(object) ? [] : {}); 365 function runEOMTasks() {
357 for (var prop in object) { 366 if (!eomTasks.length)
358 copy[prop] = object[prop]; 367 return false;
359 }; 368
360 if (Array.isArray(object)) 369 for (var i = 0; i < eomTasks.length; i++) {
361 copy.length = object.length; 370 eomTasks[i]();
362 return copy; 371 }
363 } 372 eomTasks.length = 0;
364 373 return true;
365 function Observer(object, callback, target, token) { 374 }
366 this.closed = false; 375
367 this.object = object; 376 var runEOM = hasObserve ? (function(){
368 this.callback = callback; 377 var eomObj = { pingPong: true };
369 // TODO(rafaelw): Hold this.target weakly when WeakRef is available. 378 var eomRunScheduled = false;
370 this.target = target; 379
371 this.token = token; 380 Object.observe(eomObj, function() {
372 this.reporting = true; 381 runEOMTasks();
373 if (hasObserve) { 382 eomRunScheduled = false;
374 var self = this; 383 });
375 this.boundInternalCallback = function(records) { 384
376 self.internalCallback(records); 385 return function(fn) {
377 }; 386 eomTasks.push(fn);
378 } 387 if (!eomRunScheduled) {
379 388 eomRunScheduled = true;
380 addToAll(this); 389 eomObj.pingPong = !eomObj.pingPong;
390 }
391 };
392 })() :
393 (function() {
394 return function(fn) {
395 eomTasks.push(fn);
396 };
397 })();
398
399 var observedObjectCache = [];
400
401 function newObservedObject() {
402 var observer;
403 var object;
404 var discardRecords = false;
405 var first = true;
406
407 function callback(records) {
408 if (observer && observer.state_ === OPENED && !discardRecords)
409 observer.check_(records);
410 }
411
412 return {
413 open: function(obs) {
414 if (observer)
415 throw Error('ObservedObject in use');
416
417 if (!first)
418 Object.deliverChangeRecords(callback);
419
420 observer = obs;
421 first = false;
422 },
423 observe: function(obj, arrayObserve) {
424 object = obj;
425 if (arrayObserve)
426 Array.observe(object, callback);
427 else
428 Object.observe(object, callback);
429 },
430 deliver: function(discard) {
431 discardRecords = discard;
432 Object.deliverChangeRecords(callback);
433 discardRecords = false;
434 },
435 close: function() {
436 observer = undefined;
437 Object.unobserve(object, callback);
438 observedObjectCache.push(this);
439 }
440 };
441 }
442
443 function getObservedObject(observer, object, arrayObserve) {
444 var dir = observedObjectCache.pop() || newObservedObject();
445 dir.open(observer);
446 dir.observe(object, arrayObserve);
447 return dir;
448 }
449
450 var emptyArray = [];
451 var observedSetCache = [];
452
453 function newObservedSet() {
454 var observers = [];
455 var observerCount = 0;
456 var objects = [];
457 var toRemove = emptyArray;
458 var resetNeeded = false;
459 var resetScheduled = false;
460
461 function observe(obj) {
462 if (!isObject(obj))
463 return;
464
465 var index = toRemove.indexOf(obj);
466 if (index >= 0) {
467 toRemove[index] = undefined;
468 objects.push(obj);
469 } else if (objects.indexOf(obj) < 0) {
470 objects.push(obj);
471 Object.observe(obj, callback);
472 }
473
474 observe(Object.getPrototypeOf(obj));
475 }
476
477 function reset() {
478 resetScheduled = false;
479 if (!resetNeeded)
480 return;
481
482 var objs = toRemove === emptyArray ? [] : toRemove;
483 toRemove = objects;
484 objects = objs;
485
486 var observer;
487 for (var id in observers) {
488 observer = observers[id];
489 if (!observer || observer.state_ != OPENED)
490 continue;
491
492 observer.iterateObjects_(observe);
493 }
494
495 for (var i = 0; i < toRemove.length; i++) {
496 var obj = toRemove[i];
497 if (obj)
498 Object.unobserve(obj, callback);
499 }
500
501 toRemove.length = 0;
502 }
503
504 function scheduleReset() {
505 if (resetScheduled)
506 return;
507
508 resetNeeded = true;
509 resetScheduled = true;
510 runEOM(reset);
511 }
512
513 function callback() {
514 var observer;
515
516 for (var id in observers) {
517 observer = observers[id];
518 if (!observer || observer.state_ != OPENED)
519 continue;
520
521 observer.check_();
522 }
523
524 scheduleReset();
525 }
526
527 var record = {
528 object: undefined,
529 objects: objects,
530 open: function(obs) {
531 observers[obs.id_] = obs;
532 observerCount++;
533 obs.iterateObjects_(observe);
534 },
535 close: function(obs) {
536 var anyLeft = false;
537
538 observers[obs.id_] = undefined;
539 observerCount--;
540
541 if (observerCount) {
542 scheduleReset();
543 return;
544 }
545 resetNeeded = false;
546
547 for (var i = 0; i < objects.length; i++) {
548 Object.unobserve(objects[i], callback);
549 Observer.unobservedCount++;
550 }
551
552 observers.length = 0;
553 objects.length = 0;
554 observedSetCache.push(this);
555 },
556 reset: scheduleReset
557 };
558
559 return record;
560 }
561
562 var lastObservedSet;
563
564 function getObservedSet(observer, obj) {
565 if (!lastObservedSet || lastObservedSet.object !== obj) {
566 lastObservedSet = observedSetCache.pop() || newObservedSet();
567 lastObservedSet.object = obj;
568 }
569 lastObservedSet.open(observer);
570 return lastObservedSet;
571 }
572
573 var UNOPENED = 0;
574 var OPENED = 1;
575 var CLOSED = 2;
576 var RESETTING = 3;
577
578 var nextObserverId = 1;
579
580 function Observer() {
581 this.state_ = UNOPENED;
582 this.callback_ = undefined;
583 this.target_ = undefined; // TODO(rafaelw): Should be WeakRef
584 this.directObserver_ = undefined;
585 this.value_ = undefined;
586 this.id_ = nextObserverId++;
381 } 587 }
382 588
383 Observer.prototype = { 589 Observer.prototype = {
384 internalCallback: function(records) { 590 open: function(callback, target) {
385 if (this.closed) 591 if (this.state_ != UNOPENED)
386 return; 592 throw Error('Observer has already been opened.');
387 if (this.reporting && this.check(records)) { 593
388 this.report(); 594 addToAll(this);
389 if (this.testingResults) 595 this.callback_ = callback;
390 this.testingResults.anyChanged = true; 596 this.target_ = target;
391 } 597 this.state_ = OPENED;
598 this.connect_();
599 return this.value_;
392 }, 600 },
393 601
394 close: function() { 602 close: function() {
395 if (this.closed) 603 if (this.state_ != OPENED)
396 return; 604 return;
397 if (this.object && typeof this.object.close === 'function') 605
398 this.object.close(); 606 removeFromAll(this);
399 607 this.state_ = CLOSED;
400 this.disconnect(); 608 this.disconnect_();
401 this.object = undefined; 609 this.value_ = undefined;
402 this.closed = true; 610 this.callback_ = undefined;
403 }, 611 this.target_ = undefined;
404 612 },
405 deliver: function(testingResults) { 613
406 if (this.closed) 614 deliver: function() {
407 return; 615 if (this.state_ != OPENED)
408 if (hasObserve) { 616 return;
409 this.testingResults = testingResults; 617
410 Object.deliverChangeRecords(this.boundInternalCallback); 618 dirtyCheck(this);
411 this.testingResults = undefined; 619 },
412 } else { 620
413 dirtyCheck(this); 621 report_: function(changes) {
414 }
415 },
416
417 report: function() {
418 if (!this.reporting)
419 return;
420
421 this.sync(false);
422 if (this.callback) {
423 this.reportArgs.push(this.token);
424 this.invokeCallback(this.reportArgs);
425 }
426 this.reportArgs = undefined;
427 },
428
429 invokeCallback: function(args) {
430 try { 622 try {
431 this.callback.apply(this.target, args); 623 this.callback_.apply(this.target_, changes);
432 } catch (ex) { 624 } catch (ex) {
433 Observer._errorThrownDuringCallback = true; 625 Observer._errorThrownDuringCallback = true;
434 console.error('Exception caught during observer callback: ' + (ex.stack || ex)); 626 console.error('Exception caught during observer callback: ' +
435 } 627 (ex.stack || ex));
436 }, 628 }
437 629 },
438 reset: function() { 630
439 if (this.closed) 631 discardChanges: function() {
440 return; 632 this.check_(undefined, true);
441 633 return this.value_;
442 if (hasObserve) { 634 }
443 this.reporting = false; 635 }
444 Object.deliverChangeRecords(this.boundInternalCallback); 636
445 this.reporting = true; 637 var collectObservers = !hasObserve;
446 }
447
448 this.sync(true);
449 }
450 }
451
452 var collectObservers = !hasObserve || global.forceCollectObservers;
453 var allObservers; 638 var allObservers;
454 Observer._allObserversCount = 0; 639 Observer._allObserversCount = 0;
455 640
456 if (collectObservers) { 641 if (collectObservers) {
457 allObservers = []; 642 allObservers = [];
458 } 643 }
459 644
460 function addToAll(observer) { 645 function addToAll(observer) {
646 Observer._allObserversCount++;
461 if (!collectObservers) 647 if (!collectObservers)
462 return; 648 return;
463 649
464 allObservers.push(observer); 650 allObservers.push(observer);
465 Observer._allObserversCount++; 651 }
652
653 function removeFromAll(observer) {
654 Observer._allObserversCount--;
466 } 655 }
467 656
468 var runningMicrotaskCheckpoint = false; 657 var runningMicrotaskCheckpoint = false;
469 658
470 var hasDebugForceFullDelivery = typeof Object.deliverAllChangeRecords == 'func tion'; 659 var hasDebugForceFullDelivery = typeof Object.deliverAllChangeRecords == 'func tion';
471 660
472 global.Platform = global.Platform || {}; 661 global.Platform = global.Platform || {};
473 662
474 global.Platform.performMicrotaskCheckpoint = function() { 663 global.Platform.performMicrotaskCheckpoint = function() {
475 if (runningMicrotaskCheckpoint) 664 if (runningMicrotaskCheckpoint)
476 return; 665 return;
477 666
478 if (hasDebugForceFullDelivery) { 667 if (hasDebugForceFullDelivery) {
479 Object.deliverAllChangeRecords(); 668 Object.deliverAllChangeRecords();
480 return; 669 return;
481 } 670 }
482 671
483 if (!collectObservers) 672 if (!collectObservers)
484 return; 673 return;
485 674
486 runningMicrotaskCheckpoint = true; 675 runningMicrotaskCheckpoint = true;
487 676
488 var cycles = 0; 677 var cycles = 0;
489 var results = {}; 678 var anyChanged, toCheck;
490 679
491 do { 680 do {
492 cycles++; 681 cycles++;
493 var toCheck = allObservers; 682 toCheck = allObservers;
494 allObservers = []; 683 allObservers = [];
495 results.anyChanged = false; 684 anyChanged = false;
496 685
497 for (var i = 0; i < toCheck.length; i++) { 686 for (var i = 0; i < toCheck.length; i++) {
498 var observer = toCheck[i]; 687 var observer = toCheck[i];
499 if (observer.closed) 688 if (observer.state_ != OPENED)
500 continue; 689 continue;
501 690
502 if (hasObserve) { 691 if (observer.check_())
503 observer.deliver(results); 692 anyChanged = true;
504 } else if (observer.check()) {
505 results.anyChanged = true;
506 observer.report();
507 }
508 693
509 allObservers.push(observer); 694 allObservers.push(observer);
510 } 695 }
511 } while (cycles < MAX_DIRTY_CHECK_CYCLES && results.anyChanged); 696 if (runEOMTasks())
697 anyChanged = true;
698 } while (cycles < MAX_DIRTY_CHECK_CYCLES && anyChanged);
512 699
513 if (global.testingExposeCycleCount) 700 if (global.testingExposeCycleCount)
514 global.dirtyCheckCycleCount = cycles; 701 global.dirtyCheckCycleCount = cycles;
515 702
516 Observer._allObserversCount = allObservers.length;
517 runningMicrotaskCheckpoint = false; 703 runningMicrotaskCheckpoint = false;
518 }; 704 };
519 705
520 if (collectObservers) { 706 if (collectObservers) {
521 global.Platform.clearObservers = function() { 707 global.Platform.clearObservers = function() {
522 allObservers = []; 708 allObservers = [];
523 }; 709 };
524 } 710 }
525 711
526 function ObjectObserver(object, callback, target, token) { 712 function ObjectObserver(object) {
527 Observer.call(this, object, callback, target, token); 713 Observer.call(this);
528 this.connect(); 714 this.value_ = object;
529 this.sync(true); 715 this.oldObject_ = undefined;
530 } 716 }
531 717
532 ObjectObserver.prototype = createObject({ 718 ObjectObserver.prototype = createObject({
533 __proto__: Observer.prototype, 719 __proto__: Observer.prototype,
534 720
535 connect: function() { 721 arrayObserve: false,
536 if (hasObserve) 722
537 Object.observe(this.object, this.boundInternalCallback); 723 connect_: function(callback, target) {
724 if (hasObserve) {
725 this.directObserver_ = getObservedObject(this, this.value_,
726 this.arrayObserve);
727 } else {
728 this.oldObject_ = this.copyObject(this.value_);
729 }
730
538 }, 731 },
539 732
540 sync: function(hard) { 733 copyObject: function(object) {
541 if (!hasObserve) 734 var copy = Array.isArray(object) ? [] : {};
542 this.oldObject = copyObject(this.object); 735 for (var prop in object) {
736 copy[prop] = object[prop];
737 };
738 if (Array.isArray(object))
739 copy.length = object.length;
740 return copy;
543 }, 741 },
544 742
545 check: function(changeRecords) { 743 check_: function(changeRecords, skipChanges) {
546 var diff; 744 var diff;
547 var oldValues; 745 var oldValues;
548 if (hasObserve) { 746 if (hasObserve) {
549 if (!changeRecords) 747 if (!changeRecords)
550 return false; 748 return false;
551 749
552 oldValues = {}; 750 oldValues = {};
553 diff = diffObjectFromChangeRecords(this.object, changeRecords, 751 diff = diffObjectFromChangeRecords(this.value_, changeRecords,
554 oldValues); 752 oldValues);
555 } else { 753 } else {
556 oldValues = this.oldObject; 754 oldValues = this.oldObject_;
557 diff = diffObjectFromOldObject(this.object, this.oldObject); 755 diff = diffObjectFromOldObject(this.value_, this.oldObject_);
558 } 756 }
559 757
560 if (diffIsEmpty(diff)) 758 if (diffIsEmpty(diff))
561 return false; 759 return false;
562 760
563 this.reportArgs = 761 if (!hasObserve)
564 [diff.added || {}, diff.removed || {}, diff.changed || {}]; 762 this.oldObject_ = this.copyObject(this.value_);
565 this.reportArgs.push(function(property) { 763
566 return oldValues[property]; 764 this.report_([
567 }); 765 diff.added || {},
766 diff.removed || {},
767 diff.changed || {},
768 function(property) {
769 return oldValues[property];
770 }
771 ]);
568 772
569 return true; 773 return true;
570 }, 774 },
571 775
572 disconnect: function() { 776 disconnect_: function() {
573 if (!hasObserve) 777 if (hasObserve) {
574 this.oldObject = undefined; 778 this.directObserver_.close();
575 else if (this.object) 779 this.directObserver_ = undefined;
576 Object.unobserve(this.object, this.boundInternalCallback); 780 } else {
781 this.oldObject_ = undefined;
782 }
783 },
784
785 deliver: function() {
786 if (this.state_ != OPENED)
787 return;
788
789 if (hasObserve)
790 this.directObserver_.deliver(false);
791 else
792 dirtyCheck(this);
793 },
794
795 discardChanges: function() {
796 if (this.directObserver_)
797 this.directObserver_.deliver(true);
798 else
799 this.oldObject_ = this.copyObject(this.value_);
800
801 return this.value_;
577 } 802 }
578 }); 803 });
579 804
580 function ArrayObserver(array, callback, target, token) { 805 function ArrayObserver(array) {
581 if (!Array.isArray(array)) 806 if (!Array.isArray(array))
582 throw Error('Provided object is not an Array'); 807 throw Error('Provided object is not an Array');
583 ObjectObserver.call(this, array, callback, target, token); 808 ObjectObserver.call(this, array);
584 } 809 }
585 810
586 ArrayObserver.prototype = createObject({ 811 ArrayObserver.prototype = createObject({
812
587 __proto__: ObjectObserver.prototype, 813 __proto__: ObjectObserver.prototype,
588 814
589 connect: function() { 815 arrayObserve: true,
590 if (hasObserve) 816
591 Array.observe(this.object, this.boundInternalCallback); 817 copyObject: function(arr) {
818 return arr.slice();
592 }, 819 },
593 820
594 sync: function() { 821 check_: function(changeRecords) {
595 if (!hasObserve)
596 this.oldObject = this.object.slice();
597 },
598
599 check: function(changeRecords) {
600 var splices; 822 var splices;
601 if (hasObserve) { 823 if (hasObserve) {
602 if (!changeRecords) 824 if (!changeRecords)
603 return false; 825 return false;
604 splices = projectArraySplices(this.object, changeRecords); 826 splices = projectArraySplices(this.value_, changeRecords);
605 } else { 827 } else {
606 splices = calcSplices(this.object, 0, this.object.length, 828 splices = calcSplices(this.value_, 0, this.value_.length,
607 this.oldObject, 0, this.oldObject.length); 829 this.oldObject_, 0, this.oldObject_.length);
608 } 830 }
609 831
610 if (!splices || !splices.length) 832 if (!splices || !splices.length)
611 return false; 833 return false;
612 834
613 this.reportArgs = [splices]; 835 if (!hasObserve)
836 this.oldObject_ = this.copyObject(this.value_);
837
838 this.report_([splices]);
614 return true; 839 return true;
615 } 840 }
616 }); 841 });
617 842
618 ArrayObserver.applySplices = function(previous, current, splices) { 843 ArrayObserver.applySplices = function(previous, current, splices) {
619 splices.forEach(function(splice) { 844 splices.forEach(function(splice) {
620 var spliceArgs = [splice.index, splice.removed.length]; 845 var spliceArgs = [splice.index, splice.removed.length];
621 var addIndex = splice.index; 846 var addIndex = splice.index;
622 while (addIndex < splice.index + splice.addedCount) { 847 while (addIndex < splice.index + splice.addedCount) {
623 spliceArgs.push(current[addIndex]); 848 spliceArgs.push(current[addIndex]);
624 addIndex++; 849 addIndex++;
625 } 850 }
626 851
627 Array.prototype.splice.apply(previous, spliceArgs); 852 Array.prototype.splice.apply(previous, spliceArgs);
628 }); 853 });
629 }; 854 };
630 855
631 function ObservedSet(callback) { 856 function PathObserver(object, path) {
632 this.arr = []; 857 Observer.call(this);
633 this.callback = callback; 858
634 this.isObserved = true; 859 this.object_ = object;
635 } 860 this.path_ = path instanceof Path ? path : getPath(path);
636 861 this.directObserver_ = undefined;
637 // TODO(rafaelw): Consider surfacing a way to avoid observing prototype
638 // ancestors which are expected not to change (e.g. Element, Node...).
639 var objProto = Object.getPrototypeOf({});
640 var arrayProto = Object.getPrototypeOf([]);
641 ObservedSet.prototype = {
642 reset: function() {
643 this.isObserved = !this.isObserved;
644 },
645
646 observe: function(obj) {
647 if (!isObject(obj) || obj === objProto || obj === arrayProto)
648 return;
649 var i = this.arr.indexOf(obj);
650 if (i >= 0 && this.arr[i+1] === this.isObserved)
651 return;
652
653 if (i < 0) {
654 i = this.arr.length;
655 this.arr[i] = obj;
656 Object.observe(obj, this.callback);
657 }
658
659 this.arr[i+1] = this.isObserved;
660 this.observe(Object.getPrototypeOf(obj));
661 },
662
663 cleanup: function() {
664 var i = 0, j = 0;
665 var isObserved = this.isObserved;
666 while(j < this.arr.length) {
667 var obj = this.arr[j];
668 if (this.arr[j + 1] == isObserved) {
669 if (i < j) {
670 this.arr[i] = obj;
671 this.arr[i + 1] = isObserved;
672 }
673 i += 2;
674 } else {
675 Object.unobserve(obj, this.callback);
676 }
677 j += 2;
678 }
679
680 this.arr.length = i;
681 }
682 };
683
684 function PathObserver(object, path, callback, target, token, valueFn,
685 setValueFn) {
686 var path = path instanceof Path ? path : getPath(path);
687 if (!path || !path.length || !isObject(object)) {
688 this.value_ = path ? path.getValueFrom(object) : undefined;
689 this.value = valueFn ? valueFn(this.value_) : this.value_;
690 this.closed = true;
691 return;
692 }
693
694 Observer.call(this, object, callback, target, token);
695 this.valueFn = valueFn;
696 this.setValueFn = setValueFn;
697 this.path = path;
698
699 this.connect();
700 this.sync(true);
701 } 862 }
702 863
703 PathObserver.prototype = createObject({ 864 PathObserver.prototype = createObject({
704 __proto__: Observer.prototype, 865 __proto__: Observer.prototype,
705 866
706 connect: function() { 867 connect_: function() {
707 if (hasObserve) 868 if (hasObserve)
708 this.observedSet = new ObservedSet(this.boundInternalCallback); 869 this.directObserver_ = getObservedSet(this, this.object_);
709 }, 870
710 871 this.check_(undefined, true);
711 disconnect: function() { 872 },
712 this.value = undefined; 873
874 disconnect_: function() {
713 this.value_ = undefined; 875 this.value_ = undefined;
714 if (this.observedSet) { 876
715 this.observedSet.reset(); 877 if (this.directObserver_) {
716 this.observedSet.cleanup(); 878 this.directObserver_.close(this);
717 this.observedSet = undefined; 879 this.directObserver_ = undefined;
718 } 880 }
719 }, 881 },
720 882
721 check: function() { 883 iterateObjects_: function(observe) {
722 // Note: Extracting this to a member function for use here and below 884 this.path_.iterateObjects(this.object_, observe);
723 // regresses dirty-checking path perf by about 25% =-(. 885 },
724 if (this.observedSet) 886
725 this.observedSet.reset(); 887 check_: function(changeRecords, skipChanges) {
726 888 var oldValue = this.value_;
727 this.value_ = this.path.getValueFrom(this.object, this.observedSet); 889 this.value_ = this.path_.getValueFrom(this.object_);
728 890 if (skipChanges || areSameValue(this.value_, oldValue))
729 if (this.observedSet)
730 this.observedSet.cleanup();
731
732 if (areSameValue(this.value_, this.oldValue_))
733 return false; 891 return false;
734 892
735 this.value = this.valueFn ? this.valueFn(this.value_) : this.value_; 893 this.report_([this.value_, oldValue]);
736 this.reportArgs = [this.value, this.oldValue];
737 return true; 894 return true;
738 }, 895 },
739 896
740 sync: function(hard) {
741 if (hard) {
742 if (this.observedSet)
743 this.observedSet.reset();
744
745 this.value_ = this.path.getValueFrom(this.object, this.observedSet);
746 this.value = this.valueFn ? this.valueFn(this.value_) : this.value_;
747
748 if (this.observedSet)
749 this.observedSet.cleanup();
750 }
751
752 this.oldValue_ = this.value_;
753 this.oldValue = this.value;
754 },
755
756 setValue: function(newValue) { 897 setValue: function(newValue) {
757 if (!this.path) 898 if (this.path_)
758 return; 899 this.path_.setValueFrom(this.object_, newValue);
759 if (typeof this.setValueFn === 'function')
760 newValue = this.setValueFn(newValue);
761 this.path.setValueFrom(this.object, newValue);
762 } 900 }
763 }); 901 });
764 902
765 function CompoundPathObserver(callback, target, token, valueFn) { 903 function CompoundObserver() {
766 Observer.call(this, undefined, callback, target, token); 904 Observer.call(this);
767 this.valueFn = valueFn; 905
768 906 this.value_ = [];
769 this.observed = []; 907 this.directObserver_ = undefined;
770 this.values = []; 908 this.observed_ = [];
771 this.value = undefined; 909 }
772 this.oldValue = undefined; 910
773 this.oldValues = undefined; 911 var observerSentinel = {};
774 this.changeFlags = undefined; 912
775 this.started = false; 913 CompoundObserver.prototype = createObject({
776 } 914 __proto__: Observer.prototype,
777 915
778 CompoundPathObserver.prototype = createObject({ 916 connect_: function() {
779 __proto__: PathObserver.prototype, 917 this.check_(undefined, true);
780 918
781 // TODO(rafaelw): Consider special-casing when |object| is a PathObserver 919 if (!hasObserve)
782 // and path 'value' to avoid explicit observation. 920 return;
921
922 var object;
923 var needsDirectObserver = false;
924 for (var i = 0; i < this.observed_.length; i += 2) {
925 object = this.observed_[i]
926 if (object !== observerSentinel) {
927 needsDirectObserver = true;
928 break;
929 }
930 }
931
932 if (this.directObserver_) {
933 if (needsDirectObserver) {
934 this.directObserver_.reset();
935 return;
936 }
937 this.directObserver_.close();
938 this.directObserver_ = undefined;
939 return;
940 }
941
942 if (needsDirectObserver)
943 this.directObserver_ = getObservedSet(this, object);
944 },
945
946 closeObservers_: function() {
947 for (var i = 0; i < this.observed_.length; i += 2) {
948 if (this.observed_[i] === observerSentinel)
949 this.observed_[i + 1].close();
950 }
951 this.observed_.length = 0;
952 },
953
954 disconnect_: function() {
955 this.value_ = undefined;
956
957 if (this.directObserver_) {
958 this.directObserver_.close(this);
959 this.directObserver_ = undefined;
960 }
961
962 this.closeObservers_();
963 },
964
783 addPath: function(object, path) { 965 addPath: function(object, path) {
784 if (this.started) 966 if (this.state_ != UNOPENED && this.state_ != RESETTING)
785 throw Error('Cannot add more paths once started.'); 967 throw Error('Cannot add paths once started.');
786 968
787 var path = path instanceof Path ? path : getPath(path); 969 this.observed_.push(object, path instanceof Path ? path : getPath(path));
788 var value = path ? path.getValueFrom(object) : undefined; 970 },
789 971
790 this.observed.push(object, path); 972 addObserver: function(observer) {
791 this.values.push(value); 973 if (this.state_ != UNOPENED && this.state_ != RESETTING)
792 }, 974 throw Error('Cannot add observers once started.');
793 975
794 start: function() { 976 observer.open(this.deliver, this);
795 this.started = true; 977 this.observed_.push(observerSentinel, observer);
796 this.connect(); 978 },
797 this.sync(true); 979
798 }, 980 startReset: function() {
799 981 if (this.state_ != OPENED)
800 getValues: function() { 982 throw Error('Can only reset while open');
801 if (this.observedSet) 983
802 this.observedSet.reset(); 984 this.state_ = RESETTING;
803 985 this.closeObservers_();
804 var anyChanged = false; 986 },
805 for (var i = 0; i < this.observed.length; i = i+2) { 987
806 var path = this.observed[i+1]; 988 finishReset: function() {
807 if (!path) 989 if (this.state_ != RESETTING)
990 throw Error('Can only finishReset after startReset');
991 this.state_ = OPENED;
992 this.connect_();
993
994 return this.value_;
995 },
996
997 iterateObjects_: function(observe) {
998 var object;
999 for (var i = 0; i < this.observed_.length; i += 2) {
1000 object = this.observed_[i]
1001 if (object !== observerSentinel)
1002 this.observed_[i + 1].iterateObjects(object, observe)
1003 }
1004 },
1005
1006 check_: function(changeRecords, skipChanges) {
1007 var oldValues;
1008 for (var i = 0; i < this.observed_.length; i += 2) {
1009 var pathOrObserver = this.observed_[i+1];
1010 var object = this.observed_[i];
1011 var value = object === observerSentinel ?
1012 pathOrObserver.discardChanges() :
1013 pathOrObserver.getValueFrom(object)
1014
1015 if (skipChanges) {
1016 this.value_[i / 2] = value;
808 continue; 1017 continue;
809 var object = this.observed[i];
810 var value = path.getValueFrom(object, this.observedSet);
811 var oldValue = this.values[i/2];
812 if (!areSameValue(value, oldValue)) {
813 if (!anyChanged && !this.valueFn) {
814 this.oldValues = this.oldValues || [];
815 this.changeFlags = this.changeFlags || [];
816 for (var j = 0; j < this.values.length; j++) {
817 this.oldValues[j] = this.values[j];
818 this.changeFlags[j] = false;
819 }
820 }
821
822 if (!this.valueFn)
823 this.changeFlags[i/2] = true;
824
825 this.values[i/2] = value;
826 anyChanged = true;
827 } 1018 }
828 } 1019
829 1020 if (areSameValue(value, this.value_[i / 2]))
830 if (this.observedSet) 1021 continue;
831 this.observedSet.cleanup(); 1022
832 1023 oldValues = oldValues || [];
833 return anyChanged; 1024 oldValues[i / 2] = this.value_[i / 2];
834 }, 1025 this.value_[i / 2] = value;
835 1026 }
836 check: function() { 1027
837 if (!this.getValues()) 1028 if (!oldValues)
838 return; 1029 return false;
839 1030
840 if (this.valueFn) { 1031 // TODO(rafaelw): Having observed_ as the third callback arg here is
841 this.value = this.valueFn(this.values); 1032 // pretty lame API. Fix.
842 1033 this.report_([this.value_, oldValues, this.observed_]);
843 if (areSameValue(this.value, this.oldValue))
844 return false;
845
846 this.reportArgs = [this.value, this.oldValue];
847 } else {
848 this.reportArgs = [this.values, this.oldValues, this.changeFlags,
849 this.observed];
850 }
851
852 return true; 1034 return true;
853 },
854
855 sync: function(hard) {
856 if (hard) {
857 this.getValues();
858 if (this.valueFn)
859 this.value = this.valueFn(this.values);
860 }
861
862 if (this.valueFn)
863 this.oldValue = this.value;
864 },
865
866 close: function() {
867 if (this.observed) {
868 for (var i = 0; i < this.observed.length; i = i + 2) {
869 var object = this.observed[i];
870 if (object && typeof object.close === 'function')
871 object.close();
872 }
873 this.observed = undefined;
874 this.values = undefined;
875 }
876
877 Observer.prototype.close.call(this);
878 } 1035 }
879 }); 1036 });
880 1037
1038 function identFn(value) { return value; }
1039
1040 function ObserverTransform(observable, getValueFn, setValueFn,
1041 dontPassThroughSet) {
1042 this.callback_ = undefined;
1043 this.target_ = undefined;
1044 this.value_ = undefined;
1045 this.observable_ = observable;
1046 this.getValueFn_ = getValueFn || identFn;
1047 this.setValueFn_ = setValueFn || identFn;
1048 // TODO(rafaelw): This is a temporary hack. PolymerExpressions needs this
1049 // at the moment because of a bug in it's dependency tracking.
1050 this.dontPassThroughSet_ = dontPassThroughSet;
1051 }
1052
1053 ObserverTransform.prototype = {
1054 open: function(callback, target) {
1055 this.callback_ = callback;
1056 this.target_ = target;
1057 this.value_ =
1058 this.getValueFn_(this.observable_.open(this.observedCallback_, this));
1059 return this.value_;
1060 },
1061
1062 observedCallback_: function(value) {
1063 value = this.getValueFn_(value);
1064 if (areSameValue(value, this.value_))
1065 return;
1066 var oldValue = this.value_;
1067 this.value_ = value;
1068 this.callback_.call(this.target_, this.value_, oldValue);
1069 },
1070
1071 discardChanges: function() {
1072 this.value_ = this.getValueFn_(this.observable_.discardChanges());
1073 return this.value_;
1074 },
1075
1076 deliver: function() {
1077 return this.observable_.deliver();
1078 },
1079
1080 setValue: function(value) {
1081 value = this.setValueFn_(value);
1082 if (!this.dontPassThroughSet_ && this.observable_.setValue)
1083 return this.observable_.setValue(value);
1084 },
1085
1086 close: function() {
1087 if (this.observable_)
1088 this.observable_.close();
1089 this.callback_ = undefined;
1090 this.target_ = undefined;
1091 this.observable_ = undefined;
1092 this.value_ = undefined;
1093 this.getValueFn_ = undefined;
1094 this.setValueFn_ = undefined;
1095 }
1096 }
1097
881 var expectedRecordTypes = {}; 1098 var expectedRecordTypes = {};
882 expectedRecordTypes[PROP_ADD_TYPE] = true; 1099 expectedRecordTypes[PROP_ADD_TYPE] = true;
883 expectedRecordTypes[PROP_UPDATE_TYPE] = true; 1100 expectedRecordTypes[PROP_UPDATE_TYPE] = true;
884 expectedRecordTypes[PROP_DELETE_TYPE] = true; 1101 expectedRecordTypes[PROP_DELETE_TYPE] = true;
885 1102
886 function notifyFunction(object, name) { 1103 function notifyFunction(object, name) {
887 if (typeof Object.observe !== 'function') 1104 if (typeof Object.observe !== 'function')
888 return; 1105 return;
889 1106
890 var notifier = Object.getNotifier(object); 1107 var notifier = Object.getNotifier(object);
891 return function(type, oldValue) { 1108 return function(type, oldValue) {
892 var changeRecord = { 1109 var changeRecord = {
893 object: object, 1110 object: object,
894 type: type, 1111 type: type,
895 name: name 1112 name: name
896 }; 1113 };
897 if (arguments.length === 2) 1114 if (arguments.length === 2)
898 changeRecord.oldValue = oldValue; 1115 changeRecord.oldValue = oldValue;
899 notifier.notify(changeRecord); 1116 notifier.notify(changeRecord);
900 } 1117 }
901 } 1118 }
902 1119
903 // TODO(rafaelw): It should be possible for the Object.observe case to have 1120 Observer.defineComputedProperty = function(target, name, observable) {
904 // every PathObserver used by defineProperty share a single Object.observe
905 // callback, and thus get() can simply call observer.deliver() and any changes
906 // to any dependent value will be observed.
907 PathObserver.defineProperty = function(target, name, object, path) {
908 // TODO(rafaelw): Validate errors
909 path = getPath(path);
910 var notify = notifyFunction(target, name); 1121 var notify = notifyFunction(target, name);
911 1122 var value = observable.open(function(newValue, oldValue) {
912 var observer = new PathObserver(object, path, 1123 value = newValue;
913 function(newValue, oldValue) { 1124 if (notify)
914 if (notify) 1125 notify(PROP_UPDATE_TYPE, oldValue);
915 notify(PROP_UPDATE_TYPE, oldValue); 1126 });
916 }
917 );
918 1127
919 Object.defineProperty(target, name, { 1128 Object.defineProperty(target, name, {
920 get: function() { 1129 get: function() {
921 return path.getValueFrom(object); 1130 observable.deliver();
1131 return value;
922 }, 1132 },
923 set: function(newValue) { 1133 set: function(newValue) {
924 path.setValueFrom(object, newValue); 1134 observable.setValue(newValue);
1135 return newValue;
925 }, 1136 },
926 configurable: true 1137 configurable: true
927 }); 1138 });
928 1139
929 return { 1140 return {
930 close: function() { 1141 close: function() {
931 var oldValue = path.getValueFrom(object); 1142 observable.close();
932 if (notify)
933 observer.deliver();
934 observer.close();
935 Object.defineProperty(target, name, { 1143 Object.defineProperty(target, name, {
936 value: oldValue, 1144 value: value,
937 writable: true, 1145 writable: true,
938 configurable: true 1146 configurable: true
939 }); 1147 });
940 } 1148 }
941 }; 1149 };
942 } 1150 }
943 1151
944 function diffObjectFromChangeRecords(object, changeRecords, oldValues) { 1152 function diffObjectFromChangeRecords(object, changeRecords, oldValues) {
945 var added = {}; 1153 var added = {};
946 var removed = {}; 1154 var removed = {};
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after
1390 }; 1598 };
1391 1599
1392 splices = splices.concat(calcSplices(array, splice.index, splice.index + s plice.addedCount, 1600 splices = splices.concat(calcSplices(array, splice.index, splice.index + s plice.addedCount,
1393 splice.removed, 0, splice.removed.len gth)); 1601 splice.removed, 0, splice.removed.len gth));
1394 }); 1602 });
1395 1603
1396 return splices; 1604 return splices;
1397 } 1605 }
1398 1606
1399 global.Observer = Observer; 1607 global.Observer = Observer;
1608 global.Observer.runEOM_ = runEOM;
1400 global.Observer.hasObjectObserve = hasObserve; 1609 global.Observer.hasObjectObserve = hasObserve;
1401 global.ArrayObserver = ArrayObserver; 1610 global.ArrayObserver = ArrayObserver;
1402 global.ArrayObserver.calculateSplices = function(current, previous) { 1611 global.ArrayObserver.calculateSplices = function(current, previous) {
1403 return arraySplice.calculateSplices(current, previous); 1612 return arraySplice.calculateSplices(current, previous);
1404 }; 1613 };
1405 1614
1406 global.ArraySplice = ArraySplice; 1615 global.ArraySplice = ArraySplice;
1407 global.ObjectObserver = ObjectObserver; 1616 global.ObjectObserver = ObjectObserver;
1408 global.PathObserver = PathObserver; 1617 global.PathObserver = PathObserver;
1409 global.CompoundPathObserver = CompoundPathObserver; 1618 global.CompoundObserver = CompoundObserver;
1410 global.Path = Path; 1619 global.Path = Path;
1620 global.ObserverTransform = ObserverTransform;
1411 1621
1412 // TODO(rafaelw): Only needed for testing until new change record names 1622 // TODO(rafaelw): Only needed for testing until new change record names
1413 // make it to release. 1623 // make it to release.
1414 global.Observer.changeRecordTypes = { 1624 global.Observer.changeRecordTypes = {
1415 add: PROP_ADD_TYPE, 1625 add: PROP_ADD_TYPE,
1416 update: PROP_UPDATE_TYPE, 1626 update: PROP_UPDATE_TYPE,
1417 reconfigure: PROP_RECONFIGURE_TYPE, 1627 reconfigure: PROP_RECONFIGURE_TYPE,
1418 'delete': PROP_DELETE_TYPE, 1628 'delete': PROP_DELETE_TYPE,
1419 splice: ARRAY_SPLICE_TYPE 1629 splice: ARRAY_SPLICE_TYPE
1420 }; 1630 };
1421 })(typeof global !== 'undefined' && global ? global : this || window); 1631 })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && m odule ? global : this || window);
1422 1632
1423 /* 1633 /*
1424 * Copyright 2012 The Polymer Authors. All rights reserved. 1634 * Copyright 2012 The Polymer Authors. All rights reserved.
1425 * Use of this source code is governed by a BSD-style 1635 * Use of this source code is governed by a BSD-style
1426 * license that can be found in the LICENSE file. 1636 * license that can be found in the LICENSE file.
1427 */ 1637 */
1428 1638
1429 if (typeof WeakMap === 'undefined') { 1639 if (typeof WeakMap === 'undefined') {
1430 (function() { 1640 (function() {
1431 var defineProperty = Object.defineProperty; 1641 var defineProperty = Object.defineProperty;
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after
1701 superWrapperConstructor.call(this, node); 1911 superWrapperConstructor.call(this, node);
1702 } 1912 }
1703 GeneratedWrapper.prototype = 1913 GeneratedWrapper.prototype =
1704 Object.create(superWrapperConstructor.prototype); 1914 Object.create(superWrapperConstructor.prototype);
1705 GeneratedWrapper.prototype.constructor = GeneratedWrapper; 1915 GeneratedWrapper.prototype.constructor = GeneratedWrapper;
1706 1916
1707 return GeneratedWrapper; 1917 return GeneratedWrapper;
1708 } 1918 }
1709 1919
1710 var OriginalDOMImplementation = window.DOMImplementation; 1920 var OriginalDOMImplementation = window.DOMImplementation;
1921 var OriginalEventTarget = window.EventTarget;
1711 var OriginalEvent = window.Event; 1922 var OriginalEvent = window.Event;
1712 var OriginalNode = window.Node; 1923 var OriginalNode = window.Node;
1713 var OriginalWindow = window.Window; 1924 var OriginalWindow = window.Window;
1714 var OriginalRange = window.Range; 1925 var OriginalRange = window.Range;
1715 var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D; 1926 var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D;
1716 var OriginalWebGLRenderingContext = window.WebGLRenderingContext; 1927 var OriginalWebGLRenderingContext = window.WebGLRenderingContext;
1928 var OriginalSVGElementInstance = window.SVGElementInstance;
1717 1929
1718 function isWrapper(object) { 1930 function isWrapper(object) {
1719 return object instanceof wrappers.EventTarget || 1931 return object instanceof wrappers.EventTarget ||
1720 object instanceof wrappers.Event || 1932 object instanceof wrappers.Event ||
1721 object instanceof wrappers.Range || 1933 object instanceof wrappers.Range ||
1722 object instanceof wrappers.DOMImplementation || 1934 object instanceof wrappers.DOMImplementation ||
1723 object instanceof wrappers.CanvasRenderingContext2D || 1935 object instanceof wrappers.CanvasRenderingContext2D ||
1724 wrappers.WebGLRenderingContext && 1936 wrappers.WebGLRenderingContext &&
1725 object instanceof wrappers.WebGLRenderingContext; 1937 object instanceof wrappers.WebGLRenderingContext;
1726 } 1938 }
1727 1939
1728 function isNative(object) { 1940 function isNative(object) {
1729 return object instanceof OriginalNode || 1941 return OriginalEventTarget && object instanceof OriginalEventTarget ||
1942 object instanceof OriginalNode ||
1730 object instanceof OriginalEvent || 1943 object instanceof OriginalEvent ||
1731 object instanceof OriginalWindow || 1944 object instanceof OriginalWindow ||
1732 object instanceof OriginalRange || 1945 object instanceof OriginalRange ||
1733 object instanceof OriginalDOMImplementation || 1946 object instanceof OriginalDOMImplementation ||
1734 object instanceof OriginalCanvasRenderingContext2D || 1947 object instanceof OriginalCanvasRenderingContext2D ||
1735 OriginalWebGLRenderingContext && 1948 OriginalWebGLRenderingContext &&
1736 object instanceof OriginalWebGLRenderingContext; 1949 object instanceof OriginalWebGLRenderingContext ||
1950 OriginalSVGElementInstance &&
1951 object instanceof OriginalSVGElementInstance;
1737 } 1952 }
1738 1953
1739 /** 1954 /**
1740 * Wraps a node in a WrapperNode. If there already exists a wrapper for the 1955 * Wraps a node in a WrapperNode. If there already exists a wrapper for the
1741 * |node| that wrapper is returned instead. 1956 * |node| that wrapper is returned instead.
1742 * @param {Node} node 1957 * @param {Node} node
1743 * @return {WrapperNode} 1958 * @return {WrapperNode}
1744 */ 1959 */
1745 function wrap(impl) { 1960 function wrap(impl) {
1746 if (impl === null) 1961 if (impl === null)
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1825 }; 2040 };
1826 }); 2041 });
1827 }); 2042 });
1828 } 2043 }
1829 2044
1830 scope.assert = assert; 2045 scope.assert = assert;
1831 scope.constructorTable = constructorTable; 2046 scope.constructorTable = constructorTable;
1832 scope.defineGetter = defineGetter; 2047 scope.defineGetter = defineGetter;
1833 scope.defineWrapGetter = defineWrapGetter; 2048 scope.defineWrapGetter = defineWrapGetter;
1834 scope.forwardMethodsToWrapper = forwardMethodsToWrapper; 2049 scope.forwardMethodsToWrapper = forwardMethodsToWrapper;
2050 scope.isWrapper = isWrapper;
1835 scope.isWrapperFor = isWrapperFor; 2051 scope.isWrapperFor = isWrapperFor;
1836 scope.mixin = mixin; 2052 scope.mixin = mixin;
1837 scope.nativePrototypeTable = nativePrototypeTable; 2053 scope.nativePrototypeTable = nativePrototypeTable;
1838 scope.oneOf = oneOf; 2054 scope.oneOf = oneOf;
1839 scope.registerObject = registerObject; 2055 scope.registerObject = registerObject;
1840 scope.registerWrapper = register; 2056 scope.registerWrapper = register;
1841 scope.rewrap = rewrap; 2057 scope.rewrap = rewrap;
1842 scope.unwrap = unwrap; 2058 scope.unwrap = unwrap;
1843 scope.unwrapIfNeeded = unwrapIfNeeded; 2059 scope.unwrapIfNeeded = unwrapIfNeeded;
1844 scope.wrap = wrap; 2060 scope.wrap = wrap;
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after
2280 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper; 2496 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
2281 var mixin = scope.mixin; 2497 var mixin = scope.mixin;
2282 var registerWrapper = scope.registerWrapper; 2498 var registerWrapper = scope.registerWrapper;
2283 var unwrap = scope.unwrap; 2499 var unwrap = scope.unwrap;
2284 var wrap = scope.wrap; 2500 var wrap = scope.wrap;
2285 var wrappers = scope.wrappers; 2501 var wrappers = scope.wrappers;
2286 2502
2287 var wrappedFuns = new WeakMap(); 2503 var wrappedFuns = new WeakMap();
2288 var listenersTable = new WeakMap(); 2504 var listenersTable = new WeakMap();
2289 var handledEventsTable = new WeakMap(); 2505 var handledEventsTable = new WeakMap();
2506 var currentlyDispatchingEvents = new WeakMap();
2290 var targetTable = new WeakMap(); 2507 var targetTable = new WeakMap();
2291 var currentTargetTable = new WeakMap(); 2508 var currentTargetTable = new WeakMap();
2292 var relatedTargetTable = new WeakMap(); 2509 var relatedTargetTable = new WeakMap();
2293 var eventPhaseTable = new WeakMap(); 2510 var eventPhaseTable = new WeakMap();
2294 var stopPropagationTable = new WeakMap(); 2511 var stopPropagationTable = new WeakMap();
2295 var stopImmediatePropagationTable = new WeakMap(); 2512 var stopImmediatePropagationTable = new WeakMap();
2296 var eventHandlersTable = new WeakMap(); 2513 var eventHandlersTable = new WeakMap();
2297 var eventPathTable = new WeakMap(); 2514 var eventPathTable = new WeakMap();
2298 2515
2299 function isShadowRoot(node) { 2516 function isShadowRoot(node) {
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
2451 return false; 2668 return false;
2452 } 2669 }
2453 2670
2454 2671
2455 function dispatchOriginalEvent(originalEvent) { 2672 function dispatchOriginalEvent(originalEvent) {
2456 // Make sure this event is only dispatched once. 2673 // Make sure this event is only dispatched once.
2457 if (handledEventsTable.get(originalEvent)) 2674 if (handledEventsTable.get(originalEvent))
2458 return; 2675 return;
2459 handledEventsTable.set(originalEvent, true); 2676 handledEventsTable.set(originalEvent, true);
2460 2677
2461 // Render before dispatching the event to ensure that the event path is 2678 return dispatchEvent(wrap(originalEvent), wrap(originalEvent.target));
2462 // correct.
2463 scope.renderAllPending();
2464
2465 var target = wrap(originalEvent.target);
2466 var event = wrap(originalEvent);
2467 return dispatchEvent(event, target);
2468 } 2679 }
2469 2680
2470 function dispatchEvent(event, originalWrapperTarget) { 2681 function dispatchEvent(event, originalWrapperTarget) {
2682 if (currentlyDispatchingEvents.get(event))
2683 throw new Error('InvalidStateError')
2684 currentlyDispatchingEvents.set(event, true);
2685
2686 // Render to ensure that the event path is correct.
2687 scope.renderAllPending();
2471 var eventPath = retarget(originalWrapperTarget); 2688 var eventPath = retarget(originalWrapperTarget);
2472 2689
2473 // For window load events the load event is dispatched at the window but 2690 // For window load events the load event is dispatched at the window but
2474 // the target is set to the document. 2691 // the target is set to the document.
2475 // 2692 //
2476 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# the-end 2693 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# the-end
2477 // 2694 //
2478 // TODO(arv): Find a less hacky way to do this. 2695 // TODO(arv): Find a less hacky way to do this.
2479 if (event.type === 'load' && 2696 if (event.type === 'load' &&
2480 eventPath.length === 2 && 2697 eventPath.length === 2 &&
2481 eventPath[0].target instanceof wrappers.Document) { 2698 eventPath[0].target instanceof wrappers.Document) {
2482 eventPath.shift(); 2699 eventPath.shift();
2483 } 2700 }
2484 2701
2485 eventPathTable.set(event, eventPath); 2702 eventPathTable.set(event, eventPath);
2486 2703
2487 if (dispatchCapturing(event, eventPath)) { 2704 if (dispatchCapturing(event, eventPath)) {
2488 if (dispatchAtTarget(event, eventPath)) { 2705 if (dispatchAtTarget(event, eventPath)) {
2489 dispatchBubbling(event, eventPath); 2706 dispatchBubbling(event, eventPath);
2490 } 2707 }
2491 } 2708 }
2492 2709
2493 eventPhaseTable.set(event, Event.NONE); 2710 eventPhaseTable.set(event, Event.NONE);
2494 currentTargetTable.set(event, null); 2711 currentTargetTable.delete(event, null);
2712 currentlyDispatchingEvents.delete(event);
2495 2713
2496 return event.defaultPrevented; 2714 return event.defaultPrevented;
2497 } 2715 }
2498 2716
2499 function dispatchCapturing(event, eventPath) { 2717 function dispatchCapturing(event, eventPath) {
2500 var phase; 2718 var phase;
2501 2719
2502 for (var i = eventPath.length - 1; i > 0; i--) { 2720 for (var i = eventPath.length - 1; i > 0; i--) {
2503 var target = eventPath[i].target; 2721 var target = eventPath[i].target;
2504 var currentTarget = eventPath[i].currentTarget; 2722 var currentTarget = eventPath[i].currentTarget;
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
2623 }, 2841 },
2624 get removed() { 2842 get removed() {
2625 return this.handler === null; 2843 return this.handler === null;
2626 }, 2844 },
2627 remove: function() { 2845 remove: function() {
2628 this.handler = null; 2846 this.handler = null;
2629 } 2847 }
2630 }; 2848 };
2631 2849
2632 var OriginalEvent = window.Event; 2850 var OriginalEvent = window.Event;
2633 OriginalEvent.prototype.polymerBlackList_ = {returnValue: true}; 2851 OriginalEvent.prototype.polymerBlackList_ = {
2852 returnValue: true,
2853 // TODO(arv): keyLocation is part of KeyboardEvent but Firefox does not
2854 // support constructable KeyboardEvent so we keep it here for now.
2855 keyLocation: true
2856 };
2634 2857
2635 /** 2858 /**
2636 * Creates a new Event wrapper or wraps an existin native Event object. 2859 * Creates a new Event wrapper or wraps an existin native Event object.
2637 * @param {string|Event} type 2860 * @param {string|Event} type
2638 * @param {Object=} options 2861 * @param {Object=} options
2639 * @constructor 2862 * @constructor
2640 */ 2863 */
2641 function Event(type, options) { 2864 function Event(type, options) {
2642 if (type instanceof OriginalEvent) 2865 if (type instanceof OriginalEvent)
2643 this.impl = type; 2866 this.impl = type;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
2698 var GenericEvent = function(type, options) { 2921 var GenericEvent = function(type, options) {
2699 if (type instanceof OriginalEvent) 2922 if (type instanceof OriginalEvent)
2700 this.impl = type; 2923 this.impl = type;
2701 else 2924 else
2702 return wrap(constructEvent(OriginalEvent, name, type, options)); 2925 return wrap(constructEvent(OriginalEvent, name, type, options));
2703 }; 2926 };
2704 GenericEvent.prototype = Object.create(SuperEvent.prototype); 2927 GenericEvent.prototype = Object.create(SuperEvent.prototype);
2705 if (prototype) 2928 if (prototype)
2706 mixin(GenericEvent.prototype, prototype); 2929 mixin(GenericEvent.prototype, prototype);
2707 if (OriginalEvent) { 2930 if (OriginalEvent) {
2708 // IE does not support event constructors but FocusEvent can only be 2931 // - Old versions of Safari fails on new FocusEvent (and others?).
2709 // created using new FocusEvent in Firefox. 2932 // - IE does not support event constructors.
2710 // https://bugzilla.mozilla.org/show_bug.cgi?id=882165 2933 // - createEvent('FocusEvent') throws in Firefox.
2711 if (OriginalEvent.prototype['init' + name]) { 2934 // => Try the best practice solution first and fallback to the old way
2935 // if needed.
2936 try {
2937 registerWrapper(OriginalEvent, GenericEvent, new OriginalEvent('temp'));
2938 } catch (ex) {
2712 registerWrapper(OriginalEvent, GenericEvent, 2939 registerWrapper(OriginalEvent, GenericEvent,
2713 document.createEvent(name)); 2940 document.createEvent(name));
2714 } else {
2715 registerWrapper(OriginalEvent, GenericEvent, new OriginalEvent('temp'));
2716 } 2941 }
2717 } 2942 }
2718 return GenericEvent; 2943 return GenericEvent;
2719 } 2944 }
2720 2945
2721 var UIEvent = registerGenericEvent('UIEvent', Event); 2946 var UIEvent = registerGenericEvent('UIEvent', Event);
2722 var CustomEvent = registerGenericEvent('CustomEvent', Event); 2947 var CustomEvent = registerGenericEvent('CustomEvent', Event);
2723 2948
2724 var relatedTargetProto = { 2949 var relatedTargetProto = {
2725 get relatedTarget() { 2950 get relatedTarget() {
(...skipping 20 matching lines...) Expand all
2746 var MouseEvent = registerGenericEvent('MouseEvent', UIEvent, mouseEventProto); 2971 var MouseEvent = registerGenericEvent('MouseEvent', UIEvent, mouseEventProto);
2747 var FocusEvent = registerGenericEvent('FocusEvent', UIEvent, focusEventProto); 2972 var FocusEvent = registerGenericEvent('FocusEvent', UIEvent, focusEventProto);
2748 2973
2749 // In case the browser does not support event constructors we polyfill that 2974 // In case the browser does not support event constructors we polyfill that
2750 // by calling `createEvent('Foo')` and `initFooEvent` where the arguments to 2975 // by calling `createEvent('Foo')` and `initFooEvent` where the arguments to
2751 // `initFooEvent` are derived from the registered default event init dict. 2976 // `initFooEvent` are derived from the registered default event init dict.
2752 var defaultInitDicts = Object.create(null); 2977 var defaultInitDicts = Object.create(null);
2753 2978
2754 var supportsEventConstructors = (function() { 2979 var supportsEventConstructors = (function() {
2755 try { 2980 try {
2756 new window.MouseEvent('click'); 2981 new window.FocusEvent('focus');
2757 } catch (ex) { 2982 } catch (ex) {
2758 return false; 2983 return false;
2759 } 2984 }
2760 return true; 2985 return true;
2761 })(); 2986 })();
2762 2987
2763 /** 2988 /**
2764 * Constructs a new native event. 2989 * Constructs a new native event.
2765 */ 2990 */
2766 function constructEvent(OriginalEvent, name, type, options) { 2991 function constructEvent(OriginalEvent, name, type, options) {
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
2917 } 3142 }
2918 } 3143 }
2919 } 3144 }
2920 3145
2921 if (found && count === 1) { 3146 if (found && count === 1) {
2922 var target = getTargetToListenAt(this); 3147 var target = getTargetToListenAt(this);
2923 target.removeEventListener_(type, dispatchOriginalEvent, true); 3148 target.removeEventListener_(type, dispatchOriginalEvent, true);
2924 } 3149 }
2925 }, 3150 },
2926 dispatchEvent: function(event) { 3151 dispatchEvent: function(event) {
2927 var target = getTargetToListenAt(this); 3152 // We want to use the native dispatchEvent because it triggers the default
3153 // actions (like checking a checkbox). However, if there are no listeners
3154 // in the composed tree then there are no events that will trigger and
3155 // listeners in the non composed tree that are part of the event path are
3156 // not notified.
3157 //
3158 // If we find out that there are no listeners in the composed tree we add
3159 // a temporary listener to the target which makes us get called back even
3160 // in that case.
3161
2928 var nativeEvent = unwrap(event); 3162 var nativeEvent = unwrap(event);
3163 var eventType = nativeEvent.type;
3164
2929 // Allow dispatching the same event again. This is safe because if user 3165 // Allow dispatching the same event again. This is safe because if user
2930 // code calls this during an existing dispatch of the same event the 3166 // code calls this during an existing dispatch of the same event the
2931 // native dispatchEvent throws (that is required by the spec). 3167 // native dispatchEvent throws (that is required by the spec).
2932 handledEventsTable.set(nativeEvent, false); 3168 handledEventsTable.set(nativeEvent, false);
2933 return target.dispatchEvent_(nativeEvent); 3169
3170 // Force rendering since we prefer native dispatch and that works on the
3171 // composed tree.
3172 scope.renderAllPending();
3173
3174 var tempListener;
3175 if (!hasListenerInAncestors(this, eventType)) {
3176 tempListener = function() {};
3177 this.addEventListener(eventType, tempListener, true);
3178 }
3179
3180 try {
3181 return unwrap(this).dispatchEvent_(nativeEvent);
3182 } finally {
3183 if (tempListener)
3184 this.removeEventListener(eventType, tempListener, true);
3185 }
2934 } 3186 }
2935 }; 3187 };
2936 3188
3189 function hasListener(node, type) {
3190 var listeners = listenersTable.get(node);
3191 if (listeners) {
3192 for (var i = 0; i < listeners.length; i++) {
3193 if (!listeners[i].removed && listeners[i].type === type)
3194 return true;
3195 }
3196 }
3197 return false;
3198 }
3199
3200 function hasListenerInAncestors(target, type) {
3201 for (var node = unwrap(target); node; node = node.parentNode) {
3202 if (hasListener(wrap(node), type))
3203 return true;
3204 }
3205 return false;
3206 }
3207
2937 if (OriginalEventTarget) 3208 if (OriginalEventTarget)
2938 registerWrapper(OriginalEventTarget, EventTarget); 3209 registerWrapper(OriginalEventTarget, EventTarget);
2939 3210
2940 function wrapEventTargetMethods(constructors) { 3211 function wrapEventTargetMethods(constructors) {
2941 forwardMethodsToWrapper(constructors, methodNames); 3212 forwardMethodsToWrapper(constructors, methodNames);
2942 } 3213 }
2943 3214
2944 var originalElementFromPoint = document.elementFromPoint; 3215 var originalElementFromPoint = document.elementFromPoint;
2945 3216
2946 function elementFromPoint(self, document, x, y) { 3217 function elementFromPoint(self, document, x, y) {
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
3074 // license that can be found in the LICENSE file. 3345 // license that can be found in the LICENSE file.
3075 3346
3076 (function(scope) { 3347 (function(scope) {
3077 'use strict'; 3348 'use strict';
3078 3349
3079 var EventTarget = scope.wrappers.EventTarget; 3350 var EventTarget = scope.wrappers.EventTarget;
3080 var NodeList = scope.wrappers.NodeList; 3351 var NodeList = scope.wrappers.NodeList;
3081 var assert = scope.assert; 3352 var assert = scope.assert;
3082 var defineWrapGetter = scope.defineWrapGetter; 3353 var defineWrapGetter = scope.defineWrapGetter;
3083 var enqueueMutation = scope.enqueueMutation; 3354 var enqueueMutation = scope.enqueueMutation;
3355 var isWrapper = scope.isWrapper;
3084 var mixin = scope.mixin; 3356 var mixin = scope.mixin;
3085 var registerTransientObservers = scope.registerTransientObservers; 3357 var registerTransientObservers = scope.registerTransientObservers;
3086 var registerWrapper = scope.registerWrapper; 3358 var registerWrapper = scope.registerWrapper;
3087 var unwrap = scope.unwrap; 3359 var unwrap = scope.unwrap;
3088 var wrap = scope.wrap; 3360 var wrap = scope.wrap;
3089 var wrapIfNeeded = scope.wrapIfNeeded; 3361 var wrapIfNeeded = scope.wrapIfNeeded;
3090 3362
3091 function assertIsNodeWrapper(node) { 3363 function assertIsNodeWrapper(node) {
3092 assert(node instanceof Node); 3364 assert(node instanceof Node);
3093 } 3365 }
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
3247 if (length === 1) 3519 if (length === 1)
3248 return unwrap(nodes[0]); 3520 return unwrap(nodes[0]);
3249 3521
3250 var df = unwrap(owner.ownerDocument.createDocumentFragment()); 3522 var df = unwrap(owner.ownerDocument.createDocumentFragment());
3251 for (var i = 0; i < length; i++) { 3523 for (var i = 0; i < length; i++) {
3252 df.appendChild(unwrap(nodes[i])); 3524 df.appendChild(unwrap(nodes[i]));
3253 } 3525 }
3254 return df; 3526 return df;
3255 } 3527 }
3256 3528
3529 function clearChildNodes(wrapper) {
3530 if (wrapper.firstChild_ !== undefined) {
3531 var child = wrapper.firstChild_;
3532 while (child) {
3533 var tmp = child;
3534 child = child.nextSibling_;
3535 tmp.parentNode_ = tmp.previousSibling_ = tmp.nextSibling_ = undefined;
3536 }
3537 }
3538 wrapper.firstChild_ = wrapper.lastChild_ = undefined;
3539 }
3540
3257 function removeAllChildNodes(wrapper) { 3541 function removeAllChildNodes(wrapper) {
3258 if (wrapper.invalidateShadowRenderer()) { 3542 if (wrapper.invalidateShadowRenderer()) {
3259 var childWrapper = wrapper.firstChild; 3543 var childWrapper = wrapper.firstChild;
3260 while (childWrapper) { 3544 while (childWrapper) {
3261 assert(childWrapper.parentNode === wrapper); 3545 assert(childWrapper.parentNode === wrapper);
3262 var nextSibling = childWrapper.nextSibling; 3546 var nextSibling = childWrapper.nextSibling;
3263 var childNode = unwrap(childWrapper); 3547 var childNode = unwrap(childWrapper);
3264 var parentNode = childNode.parentNode; 3548 var parentNode = childNode.parentNode;
3265 if (parentNode) 3549 if (parentNode)
3266 originalRemoveChild.call(parentNode, childNode); 3550 originalRemoveChild.call(parentNode, childNode);
(...skipping 12 matching lines...) Expand all
3279 child = nextSibling; 3563 child = nextSibling;
3280 } 3564 }
3281 } 3565 }
3282 } 3566 }
3283 3567
3284 function invalidateParent(node) { 3568 function invalidateParent(node) {
3285 var p = node.parentNode; 3569 var p = node.parentNode;
3286 return p && p.invalidateShadowRenderer(); 3570 return p && p.invalidateShadowRenderer();
3287 } 3571 }
3288 3572
3573 function cleanupNodes(nodes) {
3574 for (var i = 0, n; i < nodes.length; i++) {
3575 n = nodes[i];
3576 n.parentNode.removeChild(n);
3577 }
3578 }
3579
3289 var OriginalNode = window.Node; 3580 var OriginalNode = window.Node;
3290 3581
3291 /** 3582 /**
3292 * This represents a wrapper of a native DOM node. 3583 * This represents a wrapper of a native DOM node.
3293 * @param {!Node} original The original DOM node, aka, the visual DOM node. 3584 * @param {!Node} original The original DOM node, aka, the visual DOM node.
3294 * @constructor 3585 * @constructor
3295 * @extends {EventTarget} 3586 * @extends {EventTarget}
3296 */ 3587 */
3297 function Node(original) { 3588 function Node(original) {
3298 assert(original instanceof OriginalNode); 3589 assert(original instanceof OriginalNode);
(...skipping 26 matching lines...) Expand all
3325 * @type {Node|undefined} 3616 * @type {Node|undefined}
3326 * @private 3617 * @private
3327 */ 3618 */
3328 this.nextSibling_ = undefined; 3619 this.nextSibling_ = undefined;
3329 3620
3330 /** 3621 /**
3331 * @type {Node|undefined} 3622 * @type {Node|undefined}
3332 * @private 3623 * @private
3333 */ 3624 */
3334 this.previousSibling_ = undefined; 3625 this.previousSibling_ = undefined;
3335 }; 3626 }
3336 3627
3337 var OriginalDocumentFragment = window.DocumentFragment; 3628 var OriginalDocumentFragment = window.DocumentFragment;
3338 var originalAppendChild = OriginalNode.prototype.appendChild; 3629 var originalAppendChild = OriginalNode.prototype.appendChild;
3339 var originalCompareDocumentPosition = 3630 var originalCompareDocumentPosition =
3340 OriginalNode.prototype.compareDocumentPosition; 3631 OriginalNode.prototype.compareDocumentPosition;
3341 var originalInsertBefore = OriginalNode.prototype.insertBefore; 3632 var originalInsertBefore = OriginalNode.prototype.insertBefore;
3342 var originalRemoveChild = OriginalNode.prototype.removeChild; 3633 var originalRemoveChild = OriginalNode.prototype.removeChild;
3343 var originalReplaceChild = OriginalNode.prototype.replaceChild; 3634 var originalReplaceChild = OriginalNode.prototype.replaceChild;
3344 3635
3345 var isIe = /Trident/.test(navigator.userAgent); 3636 var isIe = /Trident/.test(navigator.userAgent);
(...skipping 13 matching lines...) Expand all
3359 3650
3360 Node.prototype = Object.create(EventTarget.prototype); 3651 Node.prototype = Object.create(EventTarget.prototype);
3361 mixin(Node.prototype, { 3652 mixin(Node.prototype, {
3362 appendChild: function(childWrapper) { 3653 appendChild: function(childWrapper) {
3363 return this.insertBefore(childWrapper, null); 3654 return this.insertBefore(childWrapper, null);
3364 }, 3655 },
3365 3656
3366 insertBefore: function(childWrapper, refWrapper) { 3657 insertBefore: function(childWrapper, refWrapper) {
3367 assertIsNodeWrapper(childWrapper); 3658 assertIsNodeWrapper(childWrapper);
3368 3659
3369 refWrapper = refWrapper || null; 3660 var refNode;
3370 refWrapper && assertIsNodeWrapper(refWrapper); 3661 if (refWrapper) {
3662 if (isWrapper(refWrapper)) {
3663 refNode = unwrap(refWrapper);
3664 } else {
3665 refNode = refWrapper;
3666 refWrapper = wrap(refNode);
3667 }
3668 } else {
3669 refWrapper = null;
3670 refNode = null;
3671 }
3672
3371 refWrapper && assert(refWrapper.parentNode === this); 3673 refWrapper && assert(refWrapper.parentNode === this);
3372 3674
3373 var nodes; 3675 var nodes;
3374 var previousNode = 3676 var previousNode =
3375 refWrapper ? refWrapper.previousSibling : this.lastChild; 3677 refWrapper ? refWrapper.previousSibling : this.lastChild;
3376 3678
3377 var useNative = !this.invalidateShadowRenderer() && 3679 var useNative = !this.invalidateShadowRenderer() &&
3378 !invalidateParent(childWrapper); 3680 !invalidateParent(childWrapper);
3379 3681
3380 if (useNative) 3682 if (useNative)
3381 nodes = collectNodesNative(childWrapper); 3683 nodes = collectNodesNative(childWrapper);
3382 else 3684 else
3383 nodes = collectNodes(childWrapper, this, previousNode, refWrapper); 3685 nodes = collectNodes(childWrapper, this, previousNode, refWrapper);
3384 3686
3385 if (useNative) { 3687 if (useNative) {
3386 ensureSameOwnerDocument(this, childWrapper); 3688 ensureSameOwnerDocument(this, childWrapper);
3387 originalInsertBefore.call(this.impl, unwrap(childWrapper), 3689 clearChildNodes(this);
3388 unwrap(refWrapper)); 3690 originalInsertBefore.call(this.impl, unwrap(childWrapper), refNode);
3389 } else { 3691 } else {
3390 if (!previousNode) 3692 if (!previousNode)
3391 this.firstChild_ = nodes[0]; 3693 this.firstChild_ = nodes[0];
3392 if (!refWrapper) 3694 if (!refWrapper)
3393 this.lastChild_ = nodes[nodes.length - 1]; 3695 this.lastChild_ = nodes[nodes.length - 1];
3394 3696
3395 var refNode = unwrap(refWrapper);
3396 var parentNode = refNode ? refNode.parentNode : this.impl; 3697 var parentNode = refNode ? refNode.parentNode : this.impl;
3397 3698
3398 // insertBefore refWrapper no matter what the parent is? 3699 // insertBefore refWrapper no matter what the parent is?
3399 if (parentNode) { 3700 if (parentNode) {
3400 originalInsertBefore.call(parentNode, 3701 originalInsertBefore.call(parentNode,
3401 unwrapNodesForInsertion(this, nodes), refNode); 3702 unwrapNodesForInsertion(this, nodes), refNode);
3402 } else { 3703 } else {
3403 adoptNodesIfNeeded(this, nodes); 3704 adoptNodesIfNeeded(this, nodes);
3404 } 3705 }
3405 } 3706 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
3456 if (childWrapperPreviousSibling) 3757 if (childWrapperPreviousSibling)
3457 childWrapperPreviousSibling.nextSibling_ = childWrapperNextSibling; 3758 childWrapperPreviousSibling.nextSibling_ = childWrapperNextSibling;
3458 if (childWrapperNextSibling) { 3759 if (childWrapperNextSibling) {
3459 childWrapperNextSibling.previousSibling_ = 3760 childWrapperNextSibling.previousSibling_ =
3460 childWrapperPreviousSibling; 3761 childWrapperPreviousSibling;
3461 } 3762 }
3462 3763
3463 childWrapper.previousSibling_ = childWrapper.nextSibling_ = 3764 childWrapper.previousSibling_ = childWrapper.nextSibling_ =
3464 childWrapper.parentNode_ = undefined; 3765 childWrapper.parentNode_ = undefined;
3465 } else { 3766 } else {
3767 clearChildNodes(this);
3466 removeChildOriginalHelper(this.impl, childNode); 3768 removeChildOriginalHelper(this.impl, childNode);
3467 } 3769 }
3468 3770
3469 if (!surpressMutations) { 3771 if (!surpressMutations) {
3470 enqueueMutation(this, 'childList', { 3772 enqueueMutation(this, 'childList', {
3471 removedNodes: createOneElementNodeList(childWrapper), 3773 removedNodes: createOneElementNodeList(childWrapper),
3472 nextSibling: childWrapperNextSibling, 3774 nextSibling: childWrapperNextSibling,
3473 previousSibling: childWrapperPreviousSibling 3775 previousSibling: childWrapperPreviousSibling
3474 }); 3776 });
3475 } 3777 }
3476 3778
3477 registerTransientObservers(this, childWrapper); 3779 registerTransientObservers(this, childWrapper);
3478 3780
3479 return childWrapper; 3781 return childWrapper;
3480 }, 3782 },
3481 3783
3482 replaceChild: function(newChildWrapper, oldChildWrapper) { 3784 replaceChild: function(newChildWrapper, oldChildWrapper) {
3483 assertIsNodeWrapper(newChildWrapper); 3785 assertIsNodeWrapper(newChildWrapper);
3484 assertIsNodeWrapper(oldChildWrapper); 3786
3787 var oldChildNode;
3788 if (isWrapper(oldChildWrapper)) {
3789 oldChildNode = unwrap(oldChildWrapper);
3790 } else {
3791 oldChildNode = oldChildWrapper;
3792 oldChildWrapper = wrap(oldChildNode);
3793 }
3485 3794
3486 if (oldChildWrapper.parentNode !== this) { 3795 if (oldChildWrapper.parentNode !== this) {
3487 // TODO(arv): DOMException 3796 // TODO(arv): DOMException
3488 throw new Error('NotFoundError'); 3797 throw new Error('NotFoundError');
3489 } 3798 }
3490 3799
3491 var oldChildNode = unwrap(oldChildWrapper);
3492 var nextNode = oldChildWrapper.nextSibling; 3800 var nextNode = oldChildWrapper.nextSibling;
3493 var previousNode = oldChildWrapper.previousSibling; 3801 var previousNode = oldChildWrapper.previousSibling;
3494 var nodes; 3802 var nodes;
3495 3803
3496 var useNative = !this.invalidateShadowRenderer() && 3804 var useNative = !this.invalidateShadowRenderer() &&
3497 !invalidateParent(newChildWrapper); 3805 !invalidateParent(newChildWrapper);
3498 3806
3499 if (useNative) { 3807 if (useNative) {
3500 nodes = collectNodesNative(newChildWrapper); 3808 nodes = collectNodesNative(newChildWrapper);
3501 } else { 3809 } else {
(...skipping 13 matching lines...) Expand all
3515 3823
3516 // replaceChild no matter what the parent is? 3824 // replaceChild no matter what the parent is?
3517 if (oldChildNode.parentNode) { 3825 if (oldChildNode.parentNode) {
3518 originalReplaceChild.call( 3826 originalReplaceChild.call(
3519 oldChildNode.parentNode, 3827 oldChildNode.parentNode,
3520 unwrapNodesForInsertion(this, nodes), 3828 unwrapNodesForInsertion(this, nodes),
3521 oldChildNode); 3829 oldChildNode);
3522 } 3830 }
3523 } else { 3831 } else {
3524 ensureSameOwnerDocument(this, newChildWrapper); 3832 ensureSameOwnerDocument(this, newChildWrapper);
3833 clearChildNodes(this);
3525 originalReplaceChild.call(this.impl, unwrap(newChildWrapper), 3834 originalReplaceChild.call(this.impl, unwrap(newChildWrapper),
3526 oldChildNode); 3835 oldChildNode);
3527 } 3836 }
3528 3837
3529 enqueueMutation(this, 'childList', { 3838 enqueueMutation(this, 'childList', {
3530 addedNodes: nodes, 3839 addedNodes: nodes,
3531 removedNodes: createOneElementNodeList(oldChildWrapper), 3840 removedNodes: createOneElementNodeList(oldChildWrapper),
3532 nextSibling: nextNode, 3841 nextSibling: nextNode,
3533 previousSibling: previousNode 3842 previousSibling: previousNode
3534 }); 3843 });
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
3591 p = p.parentNode; 3900 p = p.parentNode;
3592 } 3901 }
3593 return p; 3902 return p;
3594 }, 3903 },
3595 3904
3596 get textContent() { 3905 get textContent() {
3597 // TODO(arv): This should fallback to this.impl.textContent if there 3906 // TODO(arv): This should fallback to this.impl.textContent if there
3598 // are no shadow trees below or above the context node. 3907 // are no shadow trees below or above the context node.
3599 var s = ''; 3908 var s = '';
3600 for (var child = this.firstChild; child; child = child.nextSibling) { 3909 for (var child = this.firstChild; child; child = child.nextSibling) {
3601 s += child.textContent; 3910 if (child.nodeType != Node.COMMENT_NODE) {
3911 s += child.textContent;
3912 }
3602 } 3913 }
3603 return s; 3914 return s;
3604 }, 3915 },
3605 set textContent(textContent) { 3916 set textContent(textContent) {
3606 var removedNodes = snapshotNodeList(this.childNodes); 3917 var removedNodes = snapshotNodeList(this.childNodes);
3607 3918
3608 if (this.invalidateShadowRenderer()) { 3919 if (this.invalidateShadowRenderer()) {
3609 removeAllChildNodes(this); 3920 removeAllChildNodes(this);
3610 if (textContent !== '') { 3921 if (textContent !== '') {
3611 var textNode = this.impl.ownerDocument.createTextNode(textContent); 3922 var textNode = this.impl.ownerDocument.createTextNode(textContent);
3612 this.appendChild(textNode); 3923 this.appendChild(textNode);
3613 } 3924 }
3614 } else { 3925 } else {
3926 clearChildNodes(this);
3615 this.impl.textContent = textContent; 3927 this.impl.textContent = textContent;
3616 } 3928 }
3617 3929
3618 var addedNodes = snapshotNodeList(this.childNodes); 3930 var addedNodes = snapshotNodeList(this.childNodes);
3619 3931
3620 enqueueMutation(this, 'childList', { 3932 enqueueMutation(this, 'childList', {
3621 addedNodes: addedNodes, 3933 addedNodes: addedNodes,
3622 removedNodes: removedNodes 3934 removedNodes: removedNodes
3623 }); 3935 });
3624 3936
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
3659 var parentNode = child.parentNode; 3971 var parentNode = child.parentNode;
3660 if (!parentNode) 3972 if (!parentNode)
3661 return false; 3973 return false;
3662 return this.contains(parentNode); 3974 return this.contains(parentNode);
3663 }, 3975 },
3664 3976
3665 compareDocumentPosition: function(otherNode) { 3977 compareDocumentPosition: function(otherNode) {
3666 // This only wraps, it therefore only operates on the composed DOM and not 3978 // This only wraps, it therefore only operates on the composed DOM and not
3667 // the logical DOM. 3979 // the logical DOM.
3668 return originalCompareDocumentPosition.call(this.impl, unwrap(otherNode)); 3980 return originalCompareDocumentPosition.call(this.impl, unwrap(otherNode));
3981 },
3982
3983 normalize: function() {
3984 var nodes = snapshotNodeList(this.childNodes);
3985 var remNodes = [];
3986 var s = '';
3987 var modNode;
3988
3989 for (var i = 0, n; i < nodes.length; i++) {
3990 n = nodes[i];
3991 if (n.nodeType === Node.TEXT_NODE) {
3992 if (!modNode && !n.data.length)
3993 this.removeNode(n);
3994 else if (!modNode)
3995 modNode = n;
3996 else {
3997 s += n.data;
3998 remNodes.push(n);
3999 }
4000 } else {
4001 if (modNode && remNodes.length) {
4002 modNode.data += s;
4003 cleanUpNodes(remNodes);
4004 }
4005 remNodes = [];
4006 s = '';
4007 modNode = null;
4008 if (n.childNodes.length)
4009 n.normalize();
4010 }
4011 }
4012
4013 // handle case where >1 text nodes are the last children
4014 if (modNode && remNodes.length) {
4015 modNode.data += s;
4016 cleanupNodes(remNodes);
4017 }
3669 } 4018 }
3670 }); 4019 });
3671 4020
3672 defineWrapGetter(Node, 'ownerDocument'); 4021 defineWrapGetter(Node, 'ownerDocument');
3673 4022
3674 // We use a DocumentFragment as a base and then delete the properties of 4023 // We use a DocumentFragment as a base and then delete the properties of
3675 // DocumentFragment.prototype from the wrapper Node. Since delete makes 4024 // DocumentFragment.prototype from the wrapper Node. Since delete makes
3676 // objects slow in some JS engines we recreate the prototype object. 4025 // objects slow in some JS engines we recreate the prototype object.
3677 registerWrapper(OriginalNode, Node, document.createDocumentFragment()); 4026 registerWrapper(OriginalNode, Node, document.createDocumentFragment());
3678 delete Node.prototype.querySelector; 4027 delete Node.prototype.querySelector;
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
3871 }); 4220 });
3872 4221
3873 mixin(CharacterData.prototype, ChildNodeInterface); 4222 mixin(CharacterData.prototype, ChildNodeInterface);
3874 4223
3875 registerWrapper(OriginalCharacterData, CharacterData, 4224 registerWrapper(OriginalCharacterData, CharacterData,
3876 document.createTextNode('')); 4225 document.createTextNode(''));
3877 4226
3878 scope.wrappers.CharacterData = CharacterData; 4227 scope.wrappers.CharacterData = CharacterData;
3879 })(window.ShadowDOMPolyfill); 4228 })(window.ShadowDOMPolyfill);
3880 4229
4230 // Copyright 2014 The Polymer Authors. All rights reserved.
4231 // Use of this source code is goverened by a BSD-style
4232 // license that can be found in the LICENSE file.
4233
4234 (function(scope) {
4235 'use strict';
4236
4237 var CharacterData = scope.wrappers.CharacterData;
4238 var enqueueMutation = scope.enqueueMutation;
4239 var mixin = scope.mixin;
4240 var registerWrapper = scope.registerWrapper;
4241
4242 function toUInt32(x) {
4243 return x >>> 0;
4244 }
4245
4246 var OriginalText = window.Text;
4247
4248 function Text(node) {
4249 CharacterData.call(this, node);
4250 }
4251 Text.prototype = Object.create(CharacterData.prototype);
4252 mixin(Text.prototype, {
4253 splitText: function(offset) {
4254 offset = toUInt32(offset);
4255 var s = this.data;
4256 if (offset > s.length)
4257 throw new Error('IndexSizeError');
4258 var head = s.slice(0, offset);
4259 var tail = s.slice(offset);
4260 this.data = head;
4261 var newTextNode = this.ownerDocument.createTextNode(tail);
4262 if (this.parentNode)
4263 this.parentNode.insertBefore(newTextNode, this.nextSibling);
4264 return newTextNode;
4265 }
4266 });
4267
4268 registerWrapper(OriginalText, Text, document.createTextNode(''));
4269
4270 scope.wrappers.Text = Text;
4271 })(window.ShadowDOMPolyfill);
4272
3881 // Copyright 2013 The Polymer Authors. All rights reserved. 4273 // Copyright 2013 The Polymer Authors. All rights reserved.
3882 // Use of this source code is goverened by a BSD-style 4274 // Use of this source code is goverened by a BSD-style
3883 // license that can be found in the LICENSE file. 4275 // license that can be found in the LICENSE file.
3884 4276
3885 (function(scope) { 4277 (function(scope) {
3886 'use strict'; 4278 'use strict';
3887 4279
3888 var ChildNodeInterface = scope.ChildNodeInterface; 4280 var ChildNodeInterface = scope.ChildNodeInterface;
3889 var GetElementsByInterface = scope.GetElementsByInterface; 4281 var GetElementsByInterface = scope.GetElementsByInterface;
3890 var Node = scope.wrappers.Node; 4282 var Node = scope.wrappers.Node;
3891 var ParentNodeInterface = scope.ParentNodeInterface; 4283 var ParentNodeInterface = scope.ParentNodeInterface;
3892 var SelectorsInterface = scope.SelectorsInterface; 4284 var SelectorsInterface = scope.SelectorsInterface;
3893 var addWrapNodeListMethod = scope.addWrapNodeListMethod; 4285 var addWrapNodeListMethod = scope.addWrapNodeListMethod;
3894 var enqueueMutation = scope.enqueueMutation; 4286 var enqueueMutation = scope.enqueueMutation;
3895 var mixin = scope.mixin; 4287 var mixin = scope.mixin;
3896 var oneOf = scope.oneOf; 4288 var oneOf = scope.oneOf;
3897 var registerWrapper = scope.registerWrapper; 4289 var registerWrapper = scope.registerWrapper;
3898 var wrappers = scope.wrappers; 4290 var wrappers = scope.wrappers;
3899 4291
3900 var OriginalElement = window.Element; 4292 var OriginalElement = window.Element;
3901 4293
3902 var matchesName = oneOf(OriginalElement.prototype, [ 4294 var matchesNames = [
3903 'matches', 4295 'matches', // needs to come first.
3904 'mozMatchesSelector', 4296 'mozMatchesSelector',
3905 'msMatchesSelector', 4297 'msMatchesSelector',
3906 'webkitMatchesSelector', 4298 'webkitMatchesSelector',
3907 ]); 4299 ].filter(function(name) {
4300 return OriginalElement.prototype[name];
4301 });
4302
4303 var matchesName = matchesNames[0];
3908 4304
3909 var originalMatches = OriginalElement.prototype[matchesName]; 4305 var originalMatches = OriginalElement.prototype[matchesName];
3910 4306
3911 function invalidateRendererBasedOnAttribute(element, name) { 4307 function invalidateRendererBasedOnAttribute(element, name) {
3912 // Only invalidate if parent node is a shadow host. 4308 // Only invalidate if parent node is a shadow host.
3913 var p = element.parentNode; 4309 var p = element.parentNode;
3914 if (!p || !p.shadowRoot) 4310 if (!p || !p.shadowRoot)
3915 return; 4311 return;
3916 4312
3917 var renderer = scope.getRendererForHost(p); 4313 var renderer = scope.getRendererForHost(p);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
3961 this.impl.removeAttribute(name); 4357 this.impl.removeAttribute(name);
3962 enqueAttributeChange(this, name, oldValue); 4358 enqueAttributeChange(this, name, oldValue);
3963 invalidateRendererBasedOnAttribute(this, name); 4359 invalidateRendererBasedOnAttribute(this, name);
3964 }, 4360 },
3965 4361
3966 matches: function(selector) { 4362 matches: function(selector) {
3967 return originalMatches.call(this.impl, selector); 4363 return originalMatches.call(this.impl, selector);
3968 } 4364 }
3969 }); 4365 });
3970 4366
3971 Element.prototype[matchesName] = function(selector) { 4367 matchesNames.forEach(function(name) {
3972 return this.matches(selector); 4368 if (name !== 'matches') {
3973 }; 4369 Element.prototype[name] = function(selector) {
4370 return this.matches(selector);
4371 };
4372 }
4373 });
3974 4374
3975 if (OriginalElement.prototype.webkitCreateShadowRoot) { 4375 if (OriginalElement.prototype.webkitCreateShadowRoot) {
3976 Element.prototype.webkitCreateShadowRoot = 4376 Element.prototype.webkitCreateShadowRoot =
3977 Element.prototype.createShadowRoot; 4377 Element.prototype.createShadowRoot;
3978 } 4378 }
3979 4379
3980 /** 4380 /**
3981 * Useful for generating the accessor pair for a property that reflects an 4381 * Useful for generating the accessor pair for a property that reflects an
3982 * attribute. 4382 * attribute.
3983 */ 4383 */
(...skipping 13 matching lines...) Expand all
3997 } 4397 }
3998 4398
3999 setterDirtiesAttribute(Element.prototype, 'id'); 4399 setterDirtiesAttribute(Element.prototype, 'id');
4000 setterDirtiesAttribute(Element.prototype, 'className', 'class'); 4400 setterDirtiesAttribute(Element.prototype, 'className', 'class');
4001 4401
4002 mixin(Element.prototype, ChildNodeInterface); 4402 mixin(Element.prototype, ChildNodeInterface);
4003 mixin(Element.prototype, GetElementsByInterface); 4403 mixin(Element.prototype, GetElementsByInterface);
4004 mixin(Element.prototype, ParentNodeInterface); 4404 mixin(Element.prototype, ParentNodeInterface);
4005 mixin(Element.prototype, SelectorsInterface); 4405 mixin(Element.prototype, SelectorsInterface);
4006 4406
4007 registerWrapper(OriginalElement, Element); 4407 registerWrapper(OriginalElement, Element,
4408 document.createElementNS(null, 'x'));
4008 4409
4009 // TODO(arv): Export setterDirtiesAttribute and apply it to more bindings 4410 // TODO(arv): Export setterDirtiesAttribute and apply it to more bindings
4010 // that reflect attributes. 4411 // that reflect attributes.
4011 scope.matchesName = matchesName; 4412 scope.matchesNames = matchesNames;
4012 scope.wrappers.Element = Element; 4413 scope.wrappers.Element = Element;
4013 })(window.ShadowDOMPolyfill); 4414 })(window.ShadowDOMPolyfill);
4014 4415
4015 // Copyright 2013 The Polymer Authors. All rights reserved. 4416 // Copyright 2013 The Polymer Authors. All rights reserved.
4016 // Use of this source code is goverened by a BSD-style 4417 // Use of this source code is goverened by a BSD-style
4017 // license that can be found in the LICENSE file. 4418 // license that can be found in the LICENSE file.
4018 4419
4019 (function(scope) { 4420 (function(scope) {
4020 'use strict'; 4421 'use strict';
4021 4422
4022 var Element = scope.wrappers.Element; 4423 var Element = scope.wrappers.Element;
4023 var defineGetter = scope.defineGetter; 4424 var defineGetter = scope.defineGetter;
4024 var enqueueMutation = scope.enqueueMutation; 4425 var enqueueMutation = scope.enqueueMutation;
4025 var mixin = scope.mixin; 4426 var mixin = scope.mixin;
4026 var nodesWereAdded = scope.nodesWereAdded; 4427 var nodesWereAdded = scope.nodesWereAdded;
4027 var nodesWereRemoved = scope.nodesWereRemoved; 4428 var nodesWereRemoved = scope.nodesWereRemoved;
4028 var registerWrapper = scope.registerWrapper; 4429 var registerWrapper = scope.registerWrapper;
4029 var snapshotNodeList = scope.snapshotNodeList; 4430 var snapshotNodeList = scope.snapshotNodeList;
4030 var unwrap = scope.unwrap; 4431 var unwrap = scope.unwrap;
4031 var wrap = scope.wrap; 4432 var wrap = scope.wrap;
4032 4433
4033 ///////////////////////////////////////////////////////////////////////////// 4434 /////////////////////////////////////////////////////////////////////////////
4034 // innerHTML and outerHTML 4435 // innerHTML and outerHTML
4035 4436
4036 var escapeRegExp = /&|<|"/g; 4437 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#es capingString
4438 var escapeAttrRegExp = /[&\u00A0"]/g;
4439 var escapeDataRegExp = /[&\u00A0<>]/g;
4037 4440
4038 function escapeReplace(c) { 4441 function escapeReplace(c) {
4039 switch (c) { 4442 switch (c) {
4040 case '&': 4443 case '&':
4041 return '&amp;'; 4444 return '&amp;';
4042 case '<': 4445 case '<':
4043 return '&lt;'; 4446 return '&lt;';
4447 case '>':
4448 return '&gt;';
4044 case '"': 4449 case '"':
4045 return '&quot;' 4450 return '&quot;'
4451 case '\u00A0':
4452 return '&nbsp;';
4046 } 4453 }
4047 } 4454 }
4048 4455
4049 function escape(s) { 4456 function escapeAttr(s) {
4050 return s.replace(escapeRegExp, escapeReplace); 4457 return s.replace(escapeAttrRegExp, escapeReplace);
4458 }
4459
4460 function escapeData(s) {
4461 return s.replace(escapeDataRegExp, escapeReplace);
4462 }
4463
4464 function makeSet(arr) {
4465 var set = {};
4466 for (var i = 0; i < arr.length; i++) {
4467 set[arr[i]] = true;
4468 }
4469 return set;
4051 } 4470 }
4052 4471
4053 // http://www.whatwg.org/specs/web-apps/current-work/#void-elements 4472 // http://www.whatwg.org/specs/web-apps/current-work/#void-elements
4054 var voidElements = { 4473 var voidElements = makeSet([
4055 'area': true, 4474 'area',
4056 'base': true, 4475 'base',
4057 'br': true, 4476 'br',
4058 'col': true, 4477 'col',
4059 'command': true, 4478 'command',
4060 'embed': true, 4479 'embed',
4061 'hr': true, 4480 'hr',
4062 'img': true, 4481 'img',
4063 'input': true, 4482 'input',
4064 'keygen': true, 4483 'keygen',
4065 'link': true, 4484 'link',
4066 'meta': true, 4485 'meta',
4067 'param': true, 4486 'param',
4068 'source': true, 4487 'source',
4069 'track': true, 4488 'track',
4070 'wbr': true 4489 'wbr'
4071 }; 4490 ]);
4072 4491
4073 function getOuterHTML(node) { 4492 var plaintextParents = makeSet([
4493 'style',
4494 'script',
4495 'xmp',
4496 'iframe',
4497 'noembed',
4498 'noframes',
4499 'plaintext',
4500 'noscript'
4501 ]);
4502
4503 function getOuterHTML(node, parentNode) {
4074 switch (node.nodeType) { 4504 switch (node.nodeType) {
4075 case Node.ELEMENT_NODE: 4505 case Node.ELEMENT_NODE:
4076 var tagName = node.tagName.toLowerCase(); 4506 var tagName = node.tagName.toLowerCase();
4077 var s = '<' + tagName; 4507 var s = '<' + tagName;
4078 var attrs = node.attributes; 4508 var attrs = node.attributes;
4079 for (var i = 0, attr; attr = attrs[i]; i++) { 4509 for (var i = 0, attr; attr = attrs[i]; i++) {
4080 s += ' ' + attr.name + '="' + escape(attr.value) + '"'; 4510 s += ' ' + attr.name + '="' + escapeAttr(attr.value) + '"';
4081 } 4511 }
4082 s += '>'; 4512 s += '>';
4083 if (voidElements[tagName]) 4513 if (voidElements[tagName])
4084 return s; 4514 return s;
4085 4515
4086 return s + getInnerHTML(node) + '</' + tagName + '>'; 4516 return s + getInnerHTML(node) + '</' + tagName + '>';
4087 4517
4088 case Node.TEXT_NODE: 4518 case Node.TEXT_NODE:
4089 return escape(node.nodeValue); 4519 var data = node.data;
4520 if (parentNode && plaintextParents[parentNode.localName])
4521 return data;
4522 return escapeData(data);
4090 4523
4091 case Node.COMMENT_NODE: 4524 case Node.COMMENT_NODE:
4092 return '<!--' + escape(node.nodeValue) + '-->'; 4525 return '<!--' + node.data + '-->';
4526
4093 default: 4527 default:
4094 console.error(node); 4528 console.error(node);
4095 throw new Error('not implemented'); 4529 throw new Error('not implemented');
4096 } 4530 }
4097 } 4531 }
4098 4532
4099 function getInnerHTML(node) { 4533 function getInnerHTML(node) {
4100 var s = ''; 4534 var s = '';
4101 for (var child = node.firstChild; child; child = child.nextSibling) { 4535 for (var child = node.firstChild; child; child = child.nextSibling) {
4102 s += getOuterHTML(child); 4536 s += getOuterHTML(child, node);
4103 } 4537 }
4104 return s; 4538 return s;
4105 } 4539 }
4106 4540
4107 function setInnerHTML(node, value, opt_tagName) { 4541 function setInnerHTML(node, value, opt_tagName) {
4108 var tagName = opt_tagName || 'div'; 4542 var tagName = opt_tagName || 'div';
4109 node.textContent = ''; 4543 node.textContent = '';
4110 var tempElement = unwrap(node.ownerDocument.createElement(tagName)); 4544 var tempElement = unwrap(node.ownerDocument.createElement(tagName));
4111 tempElement.innerHTML = value; 4545 tempElement.innerHTML = value;
4112 var firstChild; 4546 var firstChild;
4113 while (firstChild = tempElement.firstChild) { 4547 while (firstChild = tempElement.firstChild) {
4114 node.appendChild(wrap(firstChild)); 4548 node.appendChild(wrap(firstChild));
4115 } 4549 }
4116 } 4550 }
4117 4551
4552 // IE11 does not have MSIE in the user agent string.
4553 var oldIe = /MSIE/.test(navigator.userAgent);
4554
4118 var OriginalHTMLElement = window.HTMLElement; 4555 var OriginalHTMLElement = window.HTMLElement;
4119 4556
4120 function HTMLElement(node) { 4557 function HTMLElement(node) {
4121 Element.call(this, node); 4558 Element.call(this, node);
4122 } 4559 }
4123 HTMLElement.prototype = Object.create(Element.prototype); 4560 HTMLElement.prototype = Object.create(Element.prototype);
4124 mixin(HTMLElement.prototype, { 4561 mixin(HTMLElement.prototype, {
4125 get innerHTML() { 4562 get innerHTML() {
4126 // TODO(arv): This should fallback to this.impl.innerHTML if there 4563 // TODO(arv): This should fallback to this.impl.innerHTML if there
4127 // are no shadow trees below or above the context node. 4564 // are no shadow trees below or above the context node.
4128 return getInnerHTML(this); 4565 return getInnerHTML(this);
4129 }, 4566 },
4130 set innerHTML(value) { 4567 set innerHTML(value) {
4568 // IE9 does not handle set innerHTML correctly on plaintextParents. It
4569 // creates element children. For example
4570 //
4571 // scriptElement.innerHTML = '<a>test</a>'
4572 //
4573 // Creates a single HTMLAnchorElement child.
4574 if (oldIe && plaintextParents[this.localName]) {
4575 this.textContent = value;
4576 return;
4577 }
4578
4131 var removedNodes = snapshotNodeList(this.childNodes); 4579 var removedNodes = snapshotNodeList(this.childNodes);
4132 4580
4133 if (this.invalidateShadowRenderer()) 4581 if (this.invalidateShadowRenderer())
4134 setInnerHTML(this, value, this.tagName); 4582 setInnerHTML(this, value, this.tagName);
4135 else 4583 else
4136 this.impl.innerHTML = value; 4584 this.impl.innerHTML = value;
4137 var addedNodes = snapshotNodeList(this.childNodes); 4585 var addedNodes = snapshotNodeList(this.childNodes);
4138 4586
4139 enqueueMutation(this, 'childList', { 4587 enqueueMutation(this, 'childList', {
4140 addedNodes: addedNodes, 4588 addedNodes: addedNodes,
4141 removedNodes: removedNodes 4589 removedNodes: removedNodes
4142 }); 4590 });
4143 4591
4144 nodesWereRemoved(removedNodes); 4592 nodesWereRemoved(removedNodes);
4145 nodesWereAdded(addedNodes); 4593 nodesWereAdded(addedNodes);
4146 }, 4594 },
4147 4595
4148 get outerHTML() { 4596 get outerHTML() {
4149 // TODO(arv): This should fallback to HTMLElement_prototype.outerHTML if t here 4597 return getOuterHTML(this, this.parentNode);
4150 // are no shadow trees below or above the context node.
4151 return getOuterHTML(this);
4152 }, 4598 },
4153 set outerHTML(value) { 4599 set outerHTML(value) {
4154 var p = this.parentNode; 4600 var p = this.parentNode;
4155 if (p) { 4601 if (p) {
4156 p.invalidateShadowRenderer(); 4602 p.invalidateShadowRenderer();
4157 this.impl.outerHTML = value; 4603 var df = frag(p, value);
4604 p.replaceChild(df, this);
4158 } 4605 }
4606 },
4607
4608 insertAdjacentHTML: function(position, text) {
4609 var contextElement, refNode;
4610 switch (String(position).toLowerCase()) {
4611 case 'beforebegin':
4612 contextElement = this.parentNode;
4613 refNode = this;
4614 break;
4615 case 'afterend':
4616 contextElement = this.parentNode;
4617 refNode = this.nextSibling;
4618 break;
4619 case 'afterbegin':
4620 contextElement = this;
4621 refNode = this.firstChild;
4622 break;
4623 case 'beforeend':
4624 contextElement = this;
4625 refNode = null;
4626 break;
4627 default:
4628 return;
4629 }
4630
4631 var df = frag(contextElement, text);
4632 contextElement.insertBefore(df, refNode);
4159 } 4633 }
4160 }); 4634 });
4161 4635
4636 function frag(contextElement, html) {
4637 // TODO(arv): This does not work with SVG and other non HTML elements.
4638 var p = unwrap(contextElement.cloneNode(false));
4639 p.innerHTML = html;
4640 var df = unwrap(document.createDocumentFragment());
4641 var c;
4642 while (c = p.firstChild) {
4643 df.appendChild(c);
4644 }
4645 return wrap(df);
4646 }
4647
4162 function getter(name) { 4648 function getter(name) {
4163 return function() { 4649 return function() {
4164 scope.renderAllPending(); 4650 scope.renderAllPending();
4165 return this.impl[name]; 4651 return this.impl[name];
4166 }; 4652 };
4167 } 4653 }
4168 4654
4169 function getterRequiresRendering(name) { 4655 function getterRequiresRendering(name) {
4170 defineGetter(HTMLElement, name, getter(name)); 4656 defineGetter(HTMLElement, name, getter(name));
4171 } 4657 }
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after
4609 case 'template': 5095 case 'template':
4610 return new HTMLTemplateElement(node); 5096 return new HTMLTemplateElement(node);
4611 } 5097 }
4612 HTMLElement.call(this, node); 5098 HTMLElement.call(this, node);
4613 } 5099 }
4614 HTMLUnknownElement.prototype = Object.create(HTMLElement.prototype); 5100 HTMLUnknownElement.prototype = Object.create(HTMLElement.prototype);
4615 registerWrapper(OriginalHTMLUnknownElement, HTMLUnknownElement); 5101 registerWrapper(OriginalHTMLUnknownElement, HTMLUnknownElement);
4616 scope.wrappers.HTMLUnknownElement = HTMLUnknownElement; 5102 scope.wrappers.HTMLUnknownElement = HTMLUnknownElement;
4617 })(window.ShadowDOMPolyfill); 5103 })(window.ShadowDOMPolyfill);
4618 5104
5105 // Copyright 2014 The Polymer Authors. All rights reserved.
5106 // Use of this source code is goverened by a BSD-style
5107 // license that can be found in the LICENSE file.
5108
5109 (function(scope) {
5110 'use strict';
5111
5112 var registerObject = scope.registerObject;
5113
5114 var SVG_NS = 'http://www.w3.org/2000/svg';
5115 var svgTitleElement = document.createElementNS(SVG_NS, 'title');
5116 var SVGTitleElement = registerObject(svgTitleElement);
5117 var SVGElement = Object.getPrototypeOf(SVGTitleElement.prototype).constructor;
5118
5119 scope.wrappers.SVGElement = SVGElement;
5120 })(window.ShadowDOMPolyfill);
5121
5122 // Copyright 2014 The Polymer Authors. All rights reserved.
5123 // Use of this source code is goverened by a BSD-style
5124 // license that can be found in the LICENSE file.
5125
5126 (function(scope) {
5127 'use strict';
5128
5129 var mixin = scope.mixin;
5130 var registerWrapper = scope.registerWrapper;
5131 var unwrap = scope.unwrap;
5132 var wrap = scope.wrap;
5133
5134 var OriginalSVGUseElement = window.SVGUseElement;
5135
5136 // IE uses SVGElement as parent interface, SVG2 (Blink & Gecko) uses
5137 // SVGGraphicsElement. Use the <g> element to get the right prototype.
5138
5139 var SVG_NS = 'http://www.w3.org/2000/svg';
5140 var gWrapper = wrap(document.createElementNS(SVG_NS, 'g'));
5141 var useElement = document.createElementNS(SVG_NS, 'use');
5142 var SVGGElement = gWrapper.constructor;
5143 var parentInterfacePrototype = Object.getPrototypeOf(SVGGElement.prototype);
5144 var parentInterface = parentInterfacePrototype.constructor;
5145
5146 function SVGUseElement(impl) {
5147 parentInterface.call(this, impl);
5148 }
5149
5150 SVGUseElement.prototype = Object.create(parentInterfacePrototype);
5151
5152 // Firefox does not expose instanceRoot.
5153 if ('instanceRoot' in useElement) {
5154 mixin(SVGUseElement.prototype, {
5155 get instanceRoot() {
5156 return wrap(unwrap(this).instanceRoot);
5157 },
5158 get animatedInstanceRoot() {
5159 return wrap(unwrap(this).animatedInstanceRoot);
5160 },
5161 });
5162 }
5163
5164 registerWrapper(OriginalSVGUseElement, SVGUseElement, useElement);
5165
5166 scope.wrappers.SVGUseElement = SVGUseElement;
5167 })(window.ShadowDOMPolyfill);
5168
5169 // Copyright 2014 The Polymer Authors. All rights reserved.
5170 // Use of this source code is goverened by a BSD-style
5171 // license that can be found in the LICENSE file.
5172
5173 (function(scope) {
5174 'use strict';
5175
5176 var EventTarget = scope.wrappers.EventTarget;
5177 var mixin = scope.mixin;
5178 var registerWrapper = scope.registerWrapper;
5179 var wrap = scope.wrap;
5180
5181 var OriginalSVGElementInstance = window.SVGElementInstance;
5182 if (!OriginalSVGElementInstance)
5183 return;
5184
5185 function SVGElementInstance(impl) {
5186 EventTarget.call(this, impl);
5187 }
5188
5189 SVGElementInstance.prototype = Object.create(EventTarget.prototype);
5190 mixin(SVGElementInstance.prototype, {
5191 /** @type {SVGElement} */
5192 get correspondingElement() {
5193 return wrap(this.impl.correspondingElement);
5194 },
5195
5196 /** @type {SVGUseElement} */
5197 get correspondingUseElement() {
5198 return wrap(this.impl.correspondingUseElement);
5199 },
5200
5201 /** @type {SVGElementInstance} */
5202 get parentNode() {
5203 return wrap(this.impl.parentNode);
5204 },
5205
5206 /** @type {SVGElementInstanceList} */
5207 get childNodes() {
5208 throw new Error('Not implemented');
5209 },
5210
5211 /** @type {SVGElementInstance} */
5212 get firstChild() {
5213 return wrap(this.impl.firstChild);
5214 },
5215
5216 /** @type {SVGElementInstance} */
5217 get lastChild() {
5218 return wrap(this.impl.lastChild);
5219 },
5220
5221 /** @type {SVGElementInstance} */
5222 get previousSibling() {
5223 return wrap(this.impl.previousSibling);
5224 },
5225
5226 /** @type {SVGElementInstance} */
5227 get nextSibling() {
5228 return wrap(this.impl.nextSibling);
5229 }
5230 });
5231
5232 registerWrapper(OriginalSVGElementInstance, SVGElementInstance);
5233
5234 scope.wrappers.SVGElementInstance = SVGElementInstance;
5235 })(window.ShadowDOMPolyfill);
5236
4619 // Copyright 2013 The Polymer Authors. All rights reserved. 5237 // Copyright 2013 The Polymer Authors. All rights reserved.
4620 // Use of this source code is goverened by a BSD-style 5238 // Use of this source code is goverened by a BSD-style
4621 // license that can be found in the LICENSE file. 5239 // license that can be found in the LICENSE file.
4622 5240
4623 (function(scope) { 5241 (function(scope) {
4624 'use strict'; 5242 'use strict';
4625 5243
4626 var mixin = scope.mixin; 5244 var mixin = scope.mixin;
4627 var registerWrapper = scope.registerWrapper; 5245 var registerWrapper = scope.registerWrapper;
4628 var unwrap = scope.unwrap; 5246 var unwrap = scope.unwrap;
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
4778 return wrap(this.impl.cloneRange()); 5396 return wrap(this.impl.cloneRange());
4779 }, 5397 },
4780 isPointInRange: function(node, offset) { 5398 isPointInRange: function(node, offset) {
4781 return this.impl.isPointInRange(unwrapIfNeeded(node), offset); 5399 return this.impl.isPointInRange(unwrapIfNeeded(node), offset);
4782 }, 5400 },
4783 comparePoint: function(node, offset) { 5401 comparePoint: function(node, offset) {
4784 return this.impl.comparePoint(unwrapIfNeeded(node), offset); 5402 return this.impl.comparePoint(unwrapIfNeeded(node), offset);
4785 }, 5403 },
4786 intersectsNode: function(node) { 5404 intersectsNode: function(node) {
4787 return this.impl.intersectsNode(unwrapIfNeeded(node)); 5405 return this.impl.intersectsNode(unwrapIfNeeded(node));
5406 },
5407 toString: function() {
5408 return this.impl.toString();
4788 } 5409 }
4789 }; 5410 };
4790 5411
4791 // IE9 does not have createContextualFragment. 5412 // IE9 does not have createContextualFragment.
4792 if (OriginalRange.prototype.createContextualFragment) { 5413 if (OriginalRange.prototype.createContextualFragment) {
4793 Range.prototype.createContextualFragment = function(html) { 5414 Range.prototype.createContextualFragment = function(html) {
4794 return wrap(this.impl.createContextualFragment(html)); 5415 return wrap(this.impl.createContextualFragment(html));
4795 }; 5416 };
4796 } 5417 }
4797 5418
(...skipping 14 matching lines...) Expand all
4812 var ParentNodeInterface = scope.ParentNodeInterface; 5433 var ParentNodeInterface = scope.ParentNodeInterface;
4813 var SelectorsInterface = scope.SelectorsInterface; 5434 var SelectorsInterface = scope.SelectorsInterface;
4814 var mixin = scope.mixin; 5435 var mixin = scope.mixin;
4815 var registerObject = scope.registerObject; 5436 var registerObject = scope.registerObject;
4816 5437
4817 var DocumentFragment = registerObject(document.createDocumentFragment()); 5438 var DocumentFragment = registerObject(document.createDocumentFragment());
4818 mixin(DocumentFragment.prototype, ParentNodeInterface); 5439 mixin(DocumentFragment.prototype, ParentNodeInterface);
4819 mixin(DocumentFragment.prototype, SelectorsInterface); 5440 mixin(DocumentFragment.prototype, SelectorsInterface);
4820 mixin(DocumentFragment.prototype, GetElementsByInterface); 5441 mixin(DocumentFragment.prototype, GetElementsByInterface);
4821 5442
4822 var Text = registerObject(document.createTextNode(''));
4823 var Comment = registerObject(document.createComment('')); 5443 var Comment = registerObject(document.createComment(''));
4824 5444
4825 scope.wrappers.Comment = Comment; 5445 scope.wrappers.Comment = Comment;
4826 scope.wrappers.DocumentFragment = DocumentFragment; 5446 scope.wrappers.DocumentFragment = DocumentFragment;
4827 scope.wrappers.Text = Text;
4828 5447
4829 })(window.ShadowDOMPolyfill); 5448 })(window.ShadowDOMPolyfill);
4830 5449
4831 // Copyright 2013 The Polymer Authors. All rights reserved. 5450 // Copyright 2013 The Polymer Authors. All rights reserved.
4832 // Use of this source code is goverened by a BSD-style 5451 // Use of this source code is goverened by a BSD-style
4833 // license that can be found in the LICENSE file. 5452 // license that can be found in the LICENSE file.
4834 5453
4835 (function(scope) { 5454 (function(scope) {
4836 'use strict'; 5455 'use strict';
4837 5456
4838 var DocumentFragment = scope.wrappers.DocumentFragment; 5457 var DocumentFragment = scope.wrappers.DocumentFragment;
4839 var elementFromPoint = scope.elementFromPoint; 5458 var elementFromPoint = scope.elementFromPoint;
4840 var getInnerHTML = scope.getInnerHTML; 5459 var getInnerHTML = scope.getInnerHTML;
4841 var mixin = scope.mixin; 5460 var mixin = scope.mixin;
4842 var rewrap = scope.rewrap; 5461 var rewrap = scope.rewrap;
4843 var setInnerHTML = scope.setInnerHTML; 5462 var setInnerHTML = scope.setInnerHTML;
4844 var unwrap = scope.unwrap; 5463 var unwrap = scope.unwrap;
4845 5464
4846 var shadowHostTable = new WeakMap(); 5465 var shadowHostTable = new WeakMap();
4847 var nextOlderShadowTreeTable = new WeakMap(); 5466 var nextOlderShadowTreeTable = new WeakMap();
4848 5467
5468 var spaceCharRe = /[ \t\n\r\f]/;
5469
4849 function ShadowRoot(hostWrapper) { 5470 function ShadowRoot(hostWrapper) {
4850 var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment()); 5471 var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment());
4851 DocumentFragment.call(this, node); 5472 DocumentFragment.call(this, node);
4852 5473
4853 // createDocumentFragment associates the node with a wrapper 5474 // createDocumentFragment associates the node with a wrapper
4854 // DocumentFragment instance. Override that. 5475 // DocumentFragment instance. Override that.
4855 rewrap(node, this); 5476 rewrap(node, this);
4856 5477
4857 var oldShadowRoot = hostWrapper.shadowRoot; 5478 var oldShadowRoot = hostWrapper.shadowRoot;
4858 nextOlderShadowTreeTable.set(this, oldShadowRoot); 5479 nextOlderShadowTreeTable.set(this, oldShadowRoot);
(...skipping 20 matching lines...) Expand all
4879 5500
4880 invalidateShadowRenderer: function() { 5501 invalidateShadowRenderer: function() {
4881 return shadowHostTable.get(this).invalidateShadowRenderer(); 5502 return shadowHostTable.get(this).invalidateShadowRenderer();
4882 }, 5503 },
4883 5504
4884 elementFromPoint: function(x, y) { 5505 elementFromPoint: function(x, y) {
4885 return elementFromPoint(this, this.ownerDocument, x, y); 5506 return elementFromPoint(this, this.ownerDocument, x, y);
4886 }, 5507 },
4887 5508
4888 getElementById: function(id) { 5509 getElementById: function(id) {
4889 return this.querySelector('#' + id); 5510 if (spaceCharRe.test(id))
5511 return null;
5512 return this.querySelector('[id="' + id + '"]');
4890 } 5513 }
4891 }); 5514 });
4892 5515
4893 scope.wrappers.ShadowRoot = ShadowRoot; 5516 scope.wrappers.ShadowRoot = ShadowRoot;
4894 5517
4895 })(window.ShadowDOMPolyfill); 5518 })(window.ShadowDOMPolyfill);
4896 5519
4897 // Copyright 2013 The Polymer Authors. All rights reserved. 5520 // Copyright 2013 The Polymer Authors. All rights reserved.
4898 // Use of this source code is governed by a BSD-style 5521 // Use of this source code is governed by a BSD-style
4899 // license that can be found in the LICENSE file. 5522 // license that can be found in the LICENSE file.
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
5079 return true; 5702 return true;
5080 5703
5081 // Here we know the select attribute is a non empty string. 5704 // Here we know the select attribute is a non empty string.
5082 select = select.trim(); 5705 select = select.trim();
5083 if (!select) 5706 if (!select)
5084 return true; 5707 return true;
5085 5708
5086 if (!(node instanceof Element)) 5709 if (!(node instanceof Element))
5087 return false; 5710 return false;
5088 5711
5712 // The native matches function in IE9 does not correctly work with elements
5713 // that are not in the document.
5714 // TODO(arv): Implement matching in JS.
5715 // https://github.com/Polymer/ShadowDOM/issues/361
5716 if (select === '*' || select === node.localName)
5717 return true;
5718
5089 // TODO(arv): This does not seem right. Need to check for a simple selector. 5719 // TODO(arv): This does not seem right. Need to check for a simple selector.
5090 if (!selectorMatchRegExp.test(select)) 5720 if (!selectorMatchRegExp.test(select))
5091 return false; 5721 return false;
5092 5722
5723 // TODO(arv): This no longer matches the spec.
5093 if (select[0] === ':' && !allowedPseudoRegExp.test(select)) 5724 if (select[0] === ':' && !allowedPseudoRegExp.test(select))
5094 return false; 5725 return false;
5095 5726
5096 try { 5727 try {
5097 return node.matches(select); 5728 return node.matches(select);
5098 } catch (ex) { 5729 } catch (ex) {
5099 // Invalid selector. 5730 // Invalid selector.
5100 return false; 5731 return false;
5101 } 5732 }
5102 } 5733 }
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after
5599 6230
5600 registerWrapper(window[name], GeneratedWrapper, 6231 registerWrapper(window[name], GeneratedWrapper,
5601 document.createElement(name.slice(4, -7))); 6232 document.createElement(name.slice(4, -7)));
5602 scope.wrappers[name] = GeneratedWrapper; 6233 scope.wrappers[name] = GeneratedWrapper;
5603 } 6234 }
5604 6235
5605 elementsWithFormProperty.forEach(createWrapperConstructor); 6236 elementsWithFormProperty.forEach(createWrapperConstructor);
5606 6237
5607 })(window.ShadowDOMPolyfill); 6238 })(window.ShadowDOMPolyfill);
5608 6239
6240 // Copyright 2014 The Polymer Authors. All rights reserved.
6241 // Use of this source code is goverened by a BSD-style
6242 // license that can be found in the LICENSE file.
6243
6244 (function(scope) {
6245 'use strict';
6246
6247 var registerWrapper = scope.registerWrapper;
6248 var unwrap = scope.unwrap;
6249 var unwrapIfNeeded = scope.unwrapIfNeeded;
6250 var wrap = scope.wrap;
6251
6252 var OriginalSelection = window.Selection;
6253
6254 function Selection(impl) {
6255 this.impl = impl;
6256 }
6257 Selection.prototype = {
6258 get anchorNode() {
6259 return wrap(this.impl.anchorNode);
6260 },
6261 get focusNode() {
6262 return wrap(this.impl.focusNode);
6263 },
6264 addRange: function(range) {
6265 this.impl.addRange(unwrap(range));
6266 },
6267 collapse: function(node, index) {
6268 this.impl.collapse(unwrapIfNeeded(node), index);
6269 },
6270 containsNode: function(node, allowPartial) {
6271 return this.impl.containsNode(unwrapIfNeeded(node), allowPartial);
6272 },
6273 extend: function(node, offset) {
6274 this.impl.extend(unwrapIfNeeded(node), offset);
6275 },
6276 getRangeAt: function(index) {
6277 return wrap(this.impl.getRangeAt(index));
6278 },
6279 removeRange: function(range) {
6280 this.impl.removeRange(unwrap(range));
6281 },
6282 selectAllChildren: function(node) {
6283 this.impl.selectAllChildren(unwrapIfNeeded(node));
6284 },
6285 toString: function() {
6286 return this.impl.toString();
6287 }
6288 };
6289
6290 // WebKit extensions. Not implemented.
6291 // readonly attribute Node baseNode;
6292 // readonly attribute long baseOffset;
6293 // readonly attribute Node extentNode;
6294 // readonly attribute long extentOffset;
6295 // [RaisesException] void setBaseAndExtent([Default=Undefined] optional Node b aseNode,
6296 // [Default=Undefined] optional long baseOffset,
6297 // [Default=Undefined] optional Node extentNode,
6298 // [Default=Undefined] optional long extentOffset);
6299 // [RaisesException, ImplementedAs=collapse] void setPosition([Default=Undefin ed] optional Node node,
6300 // [Default=Undefined] optional long offset);
6301
6302 registerWrapper(window.Selection, Selection, window.getSelection());
6303
6304 scope.wrappers.Selection = Selection;
6305
6306 })(window.ShadowDOMPolyfill);
6307
5609 // Copyright 2013 The Polymer Authors. All rights reserved. 6308 // Copyright 2013 The Polymer Authors. All rights reserved.
5610 // Use of this source code is goverened by a BSD-style 6309 // Use of this source code is goverened by a BSD-style
5611 // license that can be found in the LICENSE file. 6310 // license that can be found in the LICENSE file.
5612 6311
5613 (function(scope) { 6312 (function(scope) {
5614 'use strict'; 6313 'use strict';
5615 6314
5616 var GetElementsByInterface = scope.GetElementsByInterface; 6315 var GetElementsByInterface = scope.GetElementsByInterface;
5617 var Node = scope.wrappers.Node; 6316 var Node = scope.wrappers.Node;
5618 var ParentNodeInterface = scope.ParentNodeInterface; 6317 var ParentNodeInterface = scope.ParentNodeInterface;
6318 var Selection = scope.wrappers.Selection;
5619 var SelectorsInterface = scope.SelectorsInterface; 6319 var SelectorsInterface = scope.SelectorsInterface;
5620 var ShadowRoot = scope.wrappers.ShadowRoot; 6320 var ShadowRoot = scope.wrappers.ShadowRoot;
5621 var defineWrapGetter = scope.defineWrapGetter; 6321 var defineWrapGetter = scope.defineWrapGetter;
5622 var elementFromPoint = scope.elementFromPoint; 6322 var elementFromPoint = scope.elementFromPoint;
5623 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper; 6323 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
5624 var matchesName = scope.matchesName; 6324 var matchesNames = scope.matchesNames;
5625 var mixin = scope.mixin; 6325 var mixin = scope.mixin;
5626 var registerWrapper = scope.registerWrapper; 6326 var registerWrapper = scope.registerWrapper;
6327 var renderAllPending = scope.renderAllPending;
6328 var rewrap = scope.rewrap;
5627 var unwrap = scope.unwrap; 6329 var unwrap = scope.unwrap;
5628 var wrap = scope.wrap; 6330 var wrap = scope.wrap;
5629 var wrapEventTargetMethods = scope.wrapEventTargetMethods; 6331 var wrapEventTargetMethods = scope.wrapEventTargetMethods;
5630 var wrapNodeList = scope.wrapNodeList; 6332 var wrapNodeList = scope.wrapNodeList;
5631 6333
5632 var implementationTable = new WeakMap(); 6334 var implementationTable = new WeakMap();
5633 6335
5634 function Document(node) { 6336 function Document(node) {
5635 Node.call(this, node); 6337 Node.call(this, node);
5636 } 6338 }
(...skipping 18 matching lines...) Expand all
5655 6357
5656 [ 6358 [
5657 'createComment', 6359 'createComment',
5658 'createDocumentFragment', 6360 'createDocumentFragment',
5659 'createElement', 6361 'createElement',
5660 'createElementNS', 6362 'createElementNS',
5661 'createEvent', 6363 'createEvent',
5662 'createEventNS', 6364 'createEventNS',
5663 'createRange', 6365 'createRange',
5664 'createTextNode', 6366 'createTextNode',
5665 'getElementById', 6367 'getElementById'
5666 ].forEach(wrapMethod); 6368 ].forEach(wrapMethod);
5667 6369
5668 var originalAdoptNode = document.adoptNode; 6370 var originalAdoptNode = document.adoptNode;
5669 6371
5670 function adoptNodeNoRemove(node, doc) { 6372 function adoptNodeNoRemove(node, doc) {
5671 originalAdoptNode.call(doc.impl, unwrap(node)); 6373 originalAdoptNode.call(doc.impl, unwrap(node));
5672 adoptSubtree(node, doc); 6374 adoptSubtree(node, doc);
5673 } 6375 }
5674 6376
5675 function adoptSubtree(node, doc) { 6377 function adoptSubtree(node, doc) {
5676 if (node.shadowRoot) 6378 if (node.shadowRoot)
5677 doc.adoptNode(node.shadowRoot); 6379 doc.adoptNode(node.shadowRoot);
5678 if (node instanceof ShadowRoot) 6380 if (node instanceof ShadowRoot)
5679 adoptOlderShadowRoots(node, doc); 6381 adoptOlderShadowRoots(node, doc);
5680 for (var child = node.firstChild; child; child = child.nextSibling) { 6382 for (var child = node.firstChild; child; child = child.nextSibling) {
5681 adoptSubtree(child, doc); 6383 adoptSubtree(child, doc);
5682 } 6384 }
5683 } 6385 }
5684 6386
5685 function adoptOlderShadowRoots(shadowRoot, doc) { 6387 function adoptOlderShadowRoots(shadowRoot, doc) {
5686 var oldShadowRoot = shadowRoot.olderShadowRoot; 6388 var oldShadowRoot = shadowRoot.olderShadowRoot;
5687 if (oldShadowRoot) 6389 if (oldShadowRoot)
5688 doc.adoptNode(oldShadowRoot); 6390 doc.adoptNode(oldShadowRoot);
5689 } 6391 }
5690 6392
5691 var originalImportNode = document.importNode; 6393 var originalImportNode = document.importNode;
6394 var originalGetSelection = document.getSelection;
5692 6395
5693 mixin(Document.prototype, { 6396 mixin(Document.prototype, {
5694 adoptNode: function(node) { 6397 adoptNode: function(node) {
5695 if (node.parentNode) 6398 if (node.parentNode)
5696 node.parentNode.removeChild(node); 6399 node.parentNode.removeChild(node);
5697 adoptNodeNoRemove(node, this); 6400 adoptNodeNoRemove(node, this);
5698 return node; 6401 return node;
5699 }, 6402 },
5700 elementFromPoint: function(x, y) { 6403 elementFromPoint: function(x, y) {
5701 return elementFromPoint(this, this, x, y); 6404 return elementFromPoint(this, this, x, y);
5702 }, 6405 },
5703 importNode: function(node, deep) { 6406 importNode: function(node, deep) {
5704 // We need to manually walk the tree to ensure we do not include rendered 6407 // We need to manually walk the tree to ensure we do not include rendered
5705 // shadow trees. 6408 // shadow trees.
5706 var clone = wrap(originalImportNode.call(this.impl, unwrap(node), false)); 6409 var clone = wrap(originalImportNode.call(this.impl, unwrap(node), false));
5707 if (deep) { 6410 if (deep) {
5708 for (var child = node.firstChild; child; child = child.nextSibling) { 6411 for (var child = node.firstChild; child; child = child.nextSibling) {
5709 clone.appendChild(this.importNode(child, true)); 6412 clone.appendChild(this.importNode(child, true));
5710 } 6413 }
5711 } 6414 }
5712 return clone; 6415 return clone;
6416 },
6417 getSelection: function() {
6418 renderAllPending();
6419 return new Selection(originalGetSelection.call(unwrap(this)));
5713 } 6420 }
5714 }); 6421 });
5715 6422
5716 if (document.register) { 6423 if (document.registerElement) {
5717 var originalRegister = document.register; 6424 var originalRegisterElement = document.registerElement;
5718 Document.prototype.register = function(tagName, object) { 6425 Document.prototype.registerElement = function(tagName, object) {
5719 var prototype = object.prototype; 6426 var prototype = object.prototype;
5720 6427
5721 // If we already used the object as a prototype for another custom 6428 // If we already used the object as a prototype for another custom
5722 // element. 6429 // element.
5723 if (scope.nativePrototypeTable.get(prototype)) { 6430 if (scope.nativePrototypeTable.get(prototype)) {
5724 // TODO(arv): DOMException 6431 // TODO(arv): DOMException
5725 throw new Error('NotSupportedError'); 6432 throw new Error('NotSupportedError');
5726 } 6433 }
5727 6434
5728 // Find first object on the prototype chain that already have a native 6435 // Find first object on the prototype chain that already have a native
(...skipping 23 matching lines...) Expand all
5752 for (var i = prototypes.length - 1; i >= 0; i--) { 6459 for (var i = prototypes.length - 1; i >= 0; i--) {
5753 newPrototype = Object.create(newPrototype); 6460 newPrototype = Object.create(newPrototype);
5754 } 6461 }
5755 6462
5756 // Add callbacks if present. 6463 // Add callbacks if present.
5757 // Names are taken from: 6464 // Names are taken from:
5758 // https://code.google.com/p/chromium/codesearch#chromium/src/third_part y/WebKit/Source/bindings/v8/CustomElementConstructorBuilder.cpp&sq=package:chrom ium&type=cs&l=156 6465 // https://code.google.com/p/chromium/codesearch#chromium/src/third_part y/WebKit/Source/bindings/v8/CustomElementConstructorBuilder.cpp&sq=package:chrom ium&type=cs&l=156
5759 // and not from the spec since the spec is out of date. 6466 // and not from the spec since the spec is out of date.
5760 [ 6467 [
5761 'createdCallback', 6468 'createdCallback',
5762 'enteredViewCallback', 6469 'attachedCallback',
5763 'leftViewCallback', 6470 'detachedCallback',
5764 'attributeChangedCallback', 6471 'attributeChangedCallback',
5765 ].forEach(function(name) { 6472 ].forEach(function(name) {
5766 var f = prototype[name]; 6473 var f = prototype[name];
5767 if (!f) 6474 if (!f)
5768 return; 6475 return;
5769 newPrototype[name] = function() { 6476 newPrototype[name] = function() {
6477 // if this element has been wrapped prior to registration,
6478 // the wrapper is stale; in this case rewrap
6479 if (!(wrap(this) instanceof CustomElementConstructor)) {
6480 rewrap(this);
6481 }
5770 f.apply(wrap(this), arguments); 6482 f.apply(wrap(this), arguments);
5771 }; 6483 };
5772 }); 6484 });
5773 6485
5774 var p = {prototype: newPrototype}; 6486 var p = {prototype: newPrototype};
5775 if (object.extends) 6487 if (object.extends)
5776 p.extends = object.extends; 6488 p.extends = object.extends;
5777 var nativeConstructor = originalRegister.call(unwrap(this), tagName, p);
5778 6489
5779 function GeneratedWrapper(node) { 6490 function CustomElementConstructor(node) {
5780 if (!node) { 6491 if (!node) {
5781 if (object.extends) { 6492 if (object.extends) {
5782 return document.createElement(object.extends, tagName); 6493 return document.createElement(object.extends, tagName);
5783 } else { 6494 } else {
5784 return document.createElement(tagName); 6495 return document.createElement(tagName);
5785 } 6496 }
5786 } 6497 }
5787 this.impl = node; 6498 this.impl = node;
5788 } 6499 }
5789 GeneratedWrapper.prototype = prototype; 6500 CustomElementConstructor.prototype = prototype;
5790 GeneratedWrapper.prototype.constructor = GeneratedWrapper; 6501 CustomElementConstructor.prototype.constructor = CustomElementConstructor;
5791 6502
5792 scope.constructorTable.set(newPrototype, GeneratedWrapper); 6503 scope.constructorTable.set(newPrototype, CustomElementConstructor);
5793 scope.nativePrototypeTable.set(prototype, newPrototype); 6504 scope.nativePrototypeTable.set(prototype, newPrototype);
5794 6505
5795 return GeneratedWrapper; 6506 // registration is synchronous so do it last
6507 var nativeConstructor = originalRegisterElement.call(unwrap(this),
6508 tagName, p);
6509 return CustomElementConstructor;
5796 }; 6510 };
5797 6511
5798 forwardMethodsToWrapper([ 6512 forwardMethodsToWrapper([
5799 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocume nt 6513 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocume nt
5800 ], [ 6514 ], [
5801 'register', 6515 'registerElement',
5802 ]); 6516 ]);
5803 } 6517 }
5804 6518
5805 // We also override some of the methods on document.body and document.head 6519 // We also override some of the methods on document.body and document.head
5806 // for convenience. 6520 // for convenience.
5807 forwardMethodsToWrapper([ 6521 forwardMethodsToWrapper([
5808 window.HTMLBodyElement, 6522 window.HTMLBodyElement,
5809 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument 6523 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
5810 window.HTMLHeadElement, 6524 window.HTMLHeadElement,
5811 window.HTMLHtmlElement, 6525 window.HTMLHtmlElement,
5812 ], [ 6526 ], [
5813 'appendChild', 6527 'appendChild',
5814 'compareDocumentPosition', 6528 'compareDocumentPosition',
5815 'contains', 6529 'contains',
5816 'getElementsByClassName', 6530 'getElementsByClassName',
5817 'getElementsByTagName', 6531 'getElementsByTagName',
5818 'getElementsByTagNameNS', 6532 'getElementsByTagNameNS',
5819 'insertBefore', 6533 'insertBefore',
5820 'querySelector', 6534 'querySelector',
5821 'querySelectorAll', 6535 'querySelectorAll',
5822 'removeChild', 6536 'removeChild',
5823 'replaceChild', 6537 'replaceChild',
5824 matchesName, 6538 ].concat(matchesNames));
5825 ]);
5826 6539
5827 forwardMethodsToWrapper([ 6540 forwardMethodsToWrapper([
5828 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument 6541 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
5829 ], [ 6542 ], [
5830 'adoptNode', 6543 'adoptNode',
5831 'importNode', 6544 'importNode',
5832 'contains', 6545 'contains',
5833 'createComment', 6546 'createComment',
5834 'createDocumentFragment', 6547 'createDocumentFragment',
5835 'createElement', 6548 'createElement',
5836 'createElementNS', 6549 'createElementNS',
5837 'createEvent', 6550 'createEvent',
5838 'createEventNS', 6551 'createEventNS',
5839 'createRange', 6552 'createRange',
5840 'createTextNode', 6553 'createTextNode',
5841 'elementFromPoint', 6554 'elementFromPoint',
5842 'getElementById', 6555 'getElementById',
6556 'getSelection',
5843 ]); 6557 ]);
5844 6558
5845 mixin(Document.prototype, GetElementsByInterface); 6559 mixin(Document.prototype, GetElementsByInterface);
5846 mixin(Document.prototype, ParentNodeInterface); 6560 mixin(Document.prototype, ParentNodeInterface);
5847 mixin(Document.prototype, SelectorsInterface); 6561 mixin(Document.prototype, SelectorsInterface);
5848 6562
5849 mixin(Document.prototype, { 6563 mixin(Document.prototype, {
5850 get implementation() { 6564 get implementation() {
5851 var implementation = implementationTable.get(this); 6565 var implementation = implementationTable.get(this);
5852 if (implementation) 6566 if (implementation)
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
5913 })(window.ShadowDOMPolyfill); 6627 })(window.ShadowDOMPolyfill);
5914 6628
5915 // Copyright 2013 The Polymer Authors. All rights reserved. 6629 // Copyright 2013 The Polymer Authors. All rights reserved.
5916 // Use of this source code is goverened by a BSD-style 6630 // Use of this source code is goverened by a BSD-style
5917 // license that can be found in the LICENSE file. 6631 // license that can be found in the LICENSE file.
5918 6632
5919 (function(scope) { 6633 (function(scope) {
5920 'use strict'; 6634 'use strict';
5921 6635
5922 var EventTarget = scope.wrappers.EventTarget; 6636 var EventTarget = scope.wrappers.EventTarget;
6637 var Selection = scope.wrappers.Selection;
5923 var mixin = scope.mixin; 6638 var mixin = scope.mixin;
5924 var registerWrapper = scope.registerWrapper; 6639 var registerWrapper = scope.registerWrapper;
6640 var renderAllPending = scope.renderAllPending;
5925 var unwrap = scope.unwrap; 6641 var unwrap = scope.unwrap;
5926 var unwrapIfNeeded = scope.unwrapIfNeeded; 6642 var unwrapIfNeeded = scope.unwrapIfNeeded;
5927 var wrap = scope.wrap; 6643 var wrap = scope.wrap;
5928 var renderAllPending = scope.renderAllPending;
5929 6644
5930 var OriginalWindow = window.Window; 6645 var OriginalWindow = window.Window;
6646 var originalGetComputedStyle = window.getComputedStyle;
6647 var originalGetSelection = window.getSelection;
5931 6648
5932 function Window(impl) { 6649 function Window(impl) {
5933 EventTarget.call(this, impl); 6650 EventTarget.call(this, impl);
5934 } 6651 }
5935 Window.prototype = Object.create(EventTarget.prototype); 6652 Window.prototype = Object.create(EventTarget.prototype);
5936 6653
5937 var originalGetComputedStyle = window.getComputedStyle;
5938 OriginalWindow.prototype.getComputedStyle = function(el, pseudo) { 6654 OriginalWindow.prototype.getComputedStyle = function(el, pseudo) {
5939 renderAllPending(); 6655 return wrap(this || window).getComputedStyle(unwrapIfNeeded(el), pseudo);
5940 return originalGetComputedStyle.call(this || window, unwrapIfNeeded(el),
5941 pseudo);
5942 }; 6656 };
5943 6657
6658 OriginalWindow.prototype.getSelection = function() {
6659 return wrap(this || window).getSelection();
6660 };
6661
6662 // Work around for https://bugzilla.mozilla.org/show_bug.cgi?id=943065
6663 delete window.getComputedStyle;
6664 delete window.getSelection;
6665
5944 ['addEventListener', 'removeEventListener', 'dispatchEvent'].forEach( 6666 ['addEventListener', 'removeEventListener', 'dispatchEvent'].forEach(
5945 function(name) { 6667 function(name) {
5946 OriginalWindow.prototype[name] = function() { 6668 OriginalWindow.prototype[name] = function() {
5947 var w = wrap(this || window); 6669 var w = wrap(this || window);
5948 return w[name].apply(w, arguments); 6670 return w[name].apply(w, arguments);
5949 }; 6671 };
6672
6673 // Work around for https://bugzilla.mozilla.org/show_bug.cgi?id=943065
6674 delete window[name];
5950 }); 6675 });
5951 6676
5952 mixin(Window.prototype, { 6677 mixin(Window.prototype, {
5953 getComputedStyle: function(el, pseudo) { 6678 getComputedStyle: function(el, pseudo) {
6679 renderAllPending();
5954 return originalGetComputedStyle.call(unwrap(this), unwrapIfNeeded(el), 6680 return originalGetComputedStyle.call(unwrap(this), unwrapIfNeeded(el),
5955 pseudo); 6681 pseudo);
5956 } 6682 },
6683 getSelection: function() {
6684 renderAllPending();
6685 return new Selection(originalGetSelection.call(unwrap(this)));
6686 },
5957 }); 6687 });
5958 6688
5959 registerWrapper(OriginalWindow, Window); 6689 registerWrapper(OriginalWindow, Window);
5960 6690
5961 scope.wrappers.Window = Window; 6691 scope.wrappers.Window = Window;
5962 6692
5963 })(window.ShadowDOMPolyfill); 6693 })(window.ShadowDOMPolyfill);
5964 6694
5965 // Copyright 2013 The Polymer Authors. All rights reserved. 6695 // Copyright 2013 The Polymer Authors. All rights reserved.
5966 // Use of this source code is goverened by a BSD-style 6696 // Use of this source code is goverened by a BSD-style
5967 // license that can be found in the LICENSE file. 6697 // license that can be found in the LICENSE file.
5968 6698
5969 (function(scope) { 6699 (function(scope) {
5970 'use strict'; 6700 'use strict';
5971 6701
5972 var isWrapperFor = scope.isWrapperFor; 6702 var isWrapperFor = scope.isWrapperFor;
5973 6703
5974 // This is a list of the elements we currently override the global constructor 6704 // This is a list of the elements we currently override the global constructor
5975 // for. 6705 // for.
5976 var elements = { 6706 var elements = {
5977 'a': 'HTMLAnchorElement', 6707 'a': 'HTMLAnchorElement',
5978 'applet': 'HTMLAppletElement', 6708
6709 // Do not create an applet element by default since it shows a warning in
6710 // IE.
6711 // https://github.com/Polymer/polymer/issues/217
6712 // 'applet': 'HTMLAppletElement',
6713
5979 'area': 'HTMLAreaElement', 6714 'area': 'HTMLAreaElement',
5980 'br': 'HTMLBRElement', 6715 'br': 'HTMLBRElement',
5981 'base': 'HTMLBaseElement', 6716 'base': 'HTMLBaseElement',
5982 'body': 'HTMLBodyElement', 6717 'body': 'HTMLBodyElement',
5983 'button': 'HTMLButtonElement', 6718 'button': 'HTMLButtonElement',
5984 // 'command': 'HTMLCommandElement', // Not fully implemented in Gecko. 6719 // 'command': 'HTMLCommandElement', // Not fully implemented in Gecko.
5985 'dl': 'HTMLDListElement', 6720 'dl': 'HTMLDListElement',
5986 'datalist': 'HTMLDataListElement', 6721 'datalist': 'HTMLDataListElement',
5987 'data': 'HTMLDataElement', 6722 'data': 'HTMLDataElement',
5988 'dir': 'HTMLDirectoryElement', 6723 'dir': 'HTMLDirectoryElement',
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
6076 // patch in prefixed name 6811 // patch in prefixed name
6077 Object.defineProperties(HTMLElement.prototype, { 6812 Object.defineProperties(HTMLElement.prototype, {
6078 //TODO(sjmiles): review accessor alias with Arv 6813 //TODO(sjmiles): review accessor alias with Arv
6079 webkitShadowRoot: { 6814 webkitShadowRoot: {
6080 get: function() { 6815 get: function() {
6081 return this.shadowRoot; 6816 return this.shadowRoot;
6082 } 6817 }
6083 } 6818 }
6084 }); 6819 });
6085 6820
6821 // ShadowCSS needs this:
6822 window.wrap = window.ShadowDOMPolyfill.wrap;
6823 window.unwrap = window.ShadowDOMPolyfill.unwrap;
6824
6086 //TODO(sjmiles): review method alias with Arv 6825 //TODO(sjmiles): review method alias with Arv
6087 HTMLElement.prototype.webkitCreateShadowRoot = 6826 HTMLElement.prototype.webkitCreateShadowRoot =
6088 HTMLElement.prototype.createShadowRoot; 6827 HTMLElement.prototype.createShadowRoot;
6089 6828
6090 // TODO(jmesserly): we need to wrap document somehow (a dart:html hook?) 6829 // TODO(jmesserly): we need to wrap document somehow (a dart:html hook?)
6091 window.dartExperimentalFixupGetTag = function(originalGetTag) { 6830 window.dartExperimentalFixupGetTag = function(originalGetTag) {
6092 var NodeList = ShadowDOMPolyfill.wrappers.NodeList; 6831 var NodeList = ShadowDOMPolyfill.wrappers.NodeList;
6093 var ShadowRoot = ShadowDOMPolyfill.wrappers.ShadowRoot; 6832 var ShadowRoot = ShadowDOMPolyfill.wrappers.ShadowRoot;
6094 var unwrapIfNeeded = ShadowDOMPolyfill.unwrapIfNeeded; 6833 var unwrapIfNeeded = ShadowDOMPolyfill.unwrapIfNeeded;
6095 function getTag(obj) { 6834 function getTag(obj) {
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
6283 <div class="content-container"> 7022 <div class="content-container">
6284 <content></content> 7023 <content></content>
6285 </div> 7024 </div>
6286 7025
6287 Note the use of @polyfill in the comment above a ShadowDOM specific style 7026 Note the use of @polyfill in the comment above a ShadowDOM specific style
6288 declaration. This is a directive to the styling shim to use the selector 7027 declaration. This is a directive to the styling shim to use the selector
6289 in comments in lieu of the next selector when running under polyfill. 7028 in comments in lieu of the next selector when running under polyfill.
6290 */ 7029 */
6291 (function(scope) { 7030 (function(scope) {
6292 7031
7032 var loader = scope.loader;
7033
6293 var ShadowCSS = { 7034 var ShadowCSS = {
6294 strictStyling: false, 7035 strictStyling: false,
6295 registry: {}, 7036 registry: {},
6296 // Shim styles for a given root associated with a name and extendsName 7037 // Shim styles for a given root associated with a name and extendsName
6297 // 1. cache root styles by name 7038 // 1. cache root styles by name
6298 // 2. optionally tag root nodes with scope name 7039 // 2. optionally tag root nodes with scope name
6299 // 3. shim polyfill directives /* @polyfill */ and /* @polyfill-rule */ 7040 // 3. shim polyfill directives /* @polyfill */ and /* @polyfill-rule */
6300 // 4. shim @host and scoping 7041 // 4. shim @host and scoping
6301 shimStyling: function(root, name, extendsName) { 7042 shimStyling: function(root, name, extendsName) {
6302 var typeExtension = this.isTypeExtension(extendsName); 7043 var typeExtension = this.isTypeExtension(extendsName);
6303 // use caching to make working with styles nodes easier and to facilitate 7044 // use caching to make working with styles nodes easier and to facilitate
6304 // lookup of extendee 7045 // lookup of extendee
6305 var def = this.registerDefinition(root, name, extendsName); 7046 var def = this.registerDefinition(root, name, extendsName);
6306 // find styles and apply shimming... 7047 // find styles and apply shimming...
6307 if (this.strictStyling) { 7048 if (this.strictStyling) {
6308 this.applyScopeToContent(root, name); 7049 this.applyScopeToContent(root, name);
6309 } 7050 }
6310 // insert @polyfill and @polyfill-rule rules into style elements 7051 var cssText = this.stylesToShimmedCssText(def.rootStyles, def.scopeStyles,
6311 // scoping process takes care of shimming these 7052 name, typeExtension);
6312 this.insertPolyfillDirectives(def.rootStyles);
6313 this.insertPolyfillRules(def.rootStyles);
6314 var cssText = this.stylesToShimmedCssText(def.scopeStyles, name,
6315 typeExtension);
6316 // note: we only need to do rootStyles since these are unscoped.
6317 cssText += this.extractPolyfillUnscopedRules(def.rootStyles);
6318 // provide shimmedStyle for user extensibility 7053 // provide shimmedStyle for user extensibility
6319 def.shimmedStyle = cssTextToStyle(cssText); 7054 def.shimmedStyle = cssTextToStyle(cssText);
6320 if (root) { 7055 if (root) {
6321 root.shimmedStyle = def.shimmedStyle; 7056 root.shimmedStyle = def.shimmedStyle;
6322 } 7057 }
6323 // remove existing style elements 7058 // remove existing style elements
6324 for (var i=0, l=def.rootStyles.length, s; (i<l) && (s=def.rootStyles[i]); 7059 for (var i=0, l=def.rootStyles.length, s; (i<l) && (s=def.rootStyles[i]);
6325 i++) { 7060 i++) {
6326 s.parentNode.removeChild(s); 7061 s.parentNode.removeChild(s);
6327 } 7062 }
6328 // add style to document 7063 // add style to document
6329 addCssToDocument(cssText); 7064 addCssToDocument(cssText);
6330 }, 7065 },
7066 // apply @polyfill rules + @host and scope shimming
7067 stylesToShimmedCssText: function(rootStyles, scopeStyles, name,
7068 typeExtension) {
7069 name = name || '';
7070 // insert @polyfill and @polyfill-rule rules into style elements
7071 // scoping process takes care of shimming these
7072 this.insertPolyfillDirectives(rootStyles);
7073 this.insertPolyfillRules(rootStyles);
7074 var cssText = this.shimAtHost(scopeStyles, name, typeExtension) +
7075 this.shimScoping(scopeStyles, name, typeExtension);
7076 // note: we only need to do rootStyles since these are unscoped.
7077 cssText += this.extractPolyfillUnscopedRules(rootStyles);
7078 return cssText;
7079 },
6331 registerDefinition: function(root, name, extendsName) { 7080 registerDefinition: function(root, name, extendsName) {
6332 var def = this.registry[name] = { 7081 var def = this.registry[name] = {
6333 root: root, 7082 root: root,
6334 name: name, 7083 name: name,
6335 extendsName: extendsName 7084 extendsName: extendsName
6336 } 7085 }
6337 var styles = root ? root.querySelectorAll('style') : []; 7086 var styles = root ? root.querySelectorAll('style') : [];
6338 styles = styles ? Array.prototype.slice.call(styles, 0) : []; 7087 styles = styles ? Array.prototype.slice.call(styles, 0) : [];
6339 def.rootStyles = styles; 7088 def.rootStyles = styles;
6340 def.scopeStyles = def.rootStyles; 7089 def.scopeStyles = def.rootStyles;
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
6439 } 7188 }
6440 return cssText; 7189 return cssText;
6441 }, 7190 },
6442 extractPolyfillUnscopedRulesFromCssText: function(cssText) { 7191 extractPolyfillUnscopedRulesFromCssText: function(cssText) {
6443 var r = '', matches; 7192 var r = '', matches;
6444 while (matches = cssPolyfillUnscopedRuleCommentRe.exec(cssText)) { 7193 while (matches = cssPolyfillUnscopedRuleCommentRe.exec(cssText)) {
6445 r += matches[1].slice(0, -1) + '\n\n'; 7194 r += matches[1].slice(0, -1) + '\n\n';
6446 } 7195 }
6447 return r; 7196 return r;
6448 }, 7197 },
6449 // apply @host and scope shimming
6450 stylesToShimmedCssText: function(styles, name, typeExtension) {
6451 return this.shimAtHost(styles, name, typeExtension) +
6452 this.shimScoping(styles, name, typeExtension);
6453 },
6454 // form: @host { .foo { declarations } } 7198 // form: @host { .foo { declarations } }
6455 // becomes: scopeName.foo { declarations } 7199 // becomes: scopeName.foo { declarations }
6456 shimAtHost: function(styles, name, typeExtension) { 7200 shimAtHost: function(styles, name, typeExtension) {
6457 if (styles) { 7201 if (styles) {
6458 return this.convertAtHostStyles(styles, name, typeExtension); 7202 return this.convertAtHostStyles(styles, name, typeExtension);
6459 } 7203 }
6460 }, 7204 },
6461 convertAtHostStyles: function(styles, name, typeExtension) { 7205 convertAtHostStyles: function(styles, name, typeExtension) {
6462 var cssText = stylesToCssText(styles), self = this; 7206 var cssText = stylesToCssText(styles), self = this;
6463 cssText = cssText.replace(hostRuleRe, function(m, p1) { 7207 cssText = cssText.replace(hostRuleRe, function(m, p1) {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
6512 */ 7256 */
6513 shimScoping: function(styles, name, typeExtension) { 7257 shimScoping: function(styles, name, typeExtension) {
6514 if (styles) { 7258 if (styles) {
6515 return this.convertScopedStyles(styles, name, typeExtension); 7259 return this.convertScopedStyles(styles, name, typeExtension);
6516 } 7260 }
6517 }, 7261 },
6518 convertScopedStyles: function(styles, name, typeExtension) { 7262 convertScopedStyles: function(styles, name, typeExtension) {
6519 var cssText = stylesToCssText(styles).replace(hostRuleRe, ''); 7263 var cssText = stylesToCssText(styles).replace(hostRuleRe, '');
6520 cssText = this.insertPolyfillHostInCssText(cssText); 7264 cssText = this.insertPolyfillHostInCssText(cssText);
6521 cssText = this.convertColonHost(cssText); 7265 cssText = this.convertColonHost(cssText);
7266 cssText = this.convertColonAncestor(cssText);
7267 // TODO(sorvell): deprecated, remove
6522 cssText = this.convertPseudos(cssText); 7268 cssText = this.convertPseudos(cssText);
7269 // TODO(sorvell): deprecated, remove
6523 cssText = this.convertParts(cssText); 7270 cssText = this.convertParts(cssText);
6524 cssText = this.convertCombinators(cssText); 7271 cssText = this.convertCombinators(cssText);
6525 var rules = cssToRules(cssText); 7272 var rules = cssToRules(cssText);
6526 cssText = this.scopeRules(rules, name, typeExtension); 7273 if (name) {
7274 cssText = this.scopeRules(rules, name, typeExtension);
7275 }
6527 return cssText; 7276 return cssText;
6528 }, 7277 },
6529 convertPseudos: function(cssText) { 7278 convertPseudos: function(cssText) {
6530 return cssText.replace(cssPseudoRe, ' [pseudo=$1]'); 7279 return cssText.replace(cssPseudoRe, ' [pseudo=$1]');
6531 }, 7280 },
6532 convertParts: function(cssText) { 7281 convertParts: function(cssText) {
6533 return cssText.replace(cssPartRe, ' [part=$1]'); 7282 return cssText.replace(cssPartRe, ' [part=$1]');
6534 }, 7283 },
6535 /* 7284 /*
6536 * convert a rule like :host(.foo) > .bar { } 7285 * convert a rule like :host(.foo) > .bar { }
6537 * 7286 *
6538 * to 7287 * to
6539 * 7288 *
7289 * scopeName.foo > .bar
7290 */
7291 convertColonHost: function(cssText) {
7292 return this.convertColonRule(cssText, cssColonHostRe,
7293 this.colonHostPartReplacer);
7294 },
7295 /*
7296 * convert a rule like :ancestor(.foo) > .bar { }
7297 *
7298 * to
7299 *
6540 * scopeName.foo > .bar, .foo scopeName > .bar { } 7300 * scopeName.foo > .bar, .foo scopeName > .bar { }
6541 * 7301 *
6542 * and 7302 * and
6543 * 7303 *
6544 * :host(.foo:host) .bar { ... } 7304 * :ancestor(.foo:host) .bar { ... }
6545 * 7305 *
6546 * to 7306 * to
6547 * 7307 *
6548 * scopeName.foo .bar { ... } 7308 * scopeName.foo .bar { ... }
6549 */ 7309 */
6550 convertColonHost: function(cssText) { 7310 convertColonAncestor: function(cssText) {
7311 return this.convertColonRule(cssText, cssColonAncestorRe,
7312 this.colonAncestorPartReplacer);
7313 },
7314 convertColonRule: function(cssText, regExp, partReplacer) {
6551 // p1 = :host, p2 = contents of (), p3 rest of rule 7315 // p1 = :host, p2 = contents of (), p3 rest of rule
6552 return cssText.replace(cssColonHostRe, function(m, p1, p2, p3) { 7316 return cssText.replace(regExp, function(m, p1, p2, p3) {
6553 p1 = polyfillHostNoCombinator; 7317 p1 = polyfillHostNoCombinator;
6554 if (p2) { 7318 if (p2) {
6555 var parts = p2.split(','), r = []; 7319 var parts = p2.split(','), r = [];
6556 for (var i=0, l=parts.length, p; (i<l) && (p=parts[i]); i++) { 7320 for (var i=0, l=parts.length, p; (i<l) && (p=parts[i]); i++) {
6557 p = p.trim(); 7321 p = p.trim();
6558 if (p.match(polyfillHost)) { 7322 r.push(partReplacer(p1, p, p3));
6559 r.push(p1 + p.replace(polyfillHost, '') + p3);
6560 } else {
6561 r.push(p1 + p + p3 + ', ' + p + ' ' + p1 + p3);
6562 }
6563 } 7323 }
6564 return r.join(','); 7324 return r.join(',');
6565 } else { 7325 } else {
6566 return p1 + p3; 7326 return p1 + p3;
6567 } 7327 }
6568 }); 7328 });
6569 }, 7329 },
7330 colonAncestorPartReplacer: function(host, part, suffix) {
7331 if (part.match(polyfillHost)) {
7332 return this.colonHostPartReplacer(host, part, suffix);
7333 } else {
7334 return host + part + suffix + ', ' + part + ' ' + host + suffix;
7335 }
7336 },
7337 colonHostPartReplacer: function(host, part, suffix) {
7338 return host + part.replace(polyfillHost, '') + suffix;
7339 },
6570 /* 7340 /*
6571 * Convert ^ and ^^ combinators by replacing with space. 7341 * Convert ^ and ^^ combinators by replacing with space.
6572 */ 7342 */
6573 convertCombinators: function(cssText) { 7343 convertCombinators: function(cssText) {
6574 return cssText.replace(/\^\^/g, ' ').replace(/\^/g, ' '); 7344 return cssText.replace(/\^\^/g, ' ').replace(/\^/g, ' ');
6575 }, 7345 },
6576 // change a selector like 'div' to 'name div' 7346 // change a selector like 'div' to 'name div'
6577 scopeRules: function(cssRules, name, typeExtension) { 7347 scopeRules: function(cssRules, name, typeExtension) {
6578 var cssText = ''; 7348 var cssText = '';
6579 Array.prototype.forEach.call(cssRules, function(rule) { 7349 Array.prototype.forEach.call(cssRules, function(rule) {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
6636 if (t && (splits.indexOf(t) < 0) && (t.indexOf(attrName) < 0)) { 7406 if (t && (splits.indexOf(t) < 0) && (t.indexOf(attrName) < 0)) {
6637 p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3') 7407 p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3')
6638 } 7408 }
6639 return p; 7409 return p;
6640 }).join(sep); 7410 }).join(sep);
6641 }); 7411 });
6642 return scoped; 7412 return scoped;
6643 }, 7413 },
6644 insertPolyfillHostInCssText: function(selector) { 7414 insertPolyfillHostInCssText: function(selector) {
6645 return selector.replace(hostRe, polyfillHost).replace(colonHostRe, 7415 return selector.replace(hostRe, polyfillHost).replace(colonHostRe,
6646 polyfillHost); 7416 polyfillHost).replace(colonAncestorRe, polyfillAncestor);
6647 }, 7417 },
6648 propertiesFromRule: function(rule) { 7418 propertiesFromRule: function(rule) {
7419 // TODO(sorvell): Safari cssom incorrectly removes quotes from the content
7420 // property. (https://bugs.webkit.org/show_bug.cgi?id=118045)
7421 if (rule.style.content && !rule.style.content.match(/['"]+/)) {
7422 return rule.style.cssText.replace(/content:[^;]*;/g, 'content: \'' +
7423 rule.style.content + '\';');
7424 }
6649 return rule.style.cssText; 7425 return rule.style.cssText;
6650 } 7426 }
6651 }; 7427 };
6652 7428
6653 var hostRuleRe = /@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim, 7429 var hostRuleRe = /@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim,
6654 selectorRe = /([^{]*)({[\s\S]*?})/gim, 7430 selectorRe = /([^{]*)({[\s\S]*?})/gim,
6655 hostElementRe = /(.*)((?:\*)|(?:\:scope))(.*)/, 7431 hostElementRe = /(.*)((?:\*)|(?:\:scope))(.*)/,
6656 hostFixableRe = /^[.\[:]/, 7432 hostFixableRe = /^[.\[:]/,
6657 cssCommentRe = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim, 7433 cssCommentRe = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,
6658 cssPolyfillCommentRe = /\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*? ){/gim, 7434 cssPolyfillCommentRe = /\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*? ){/gim,
6659 cssPolyfillRuleCommentRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\/ /gim, 7435 cssPolyfillRuleCommentRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\/ /gim,
6660 cssPolyfillUnscopedRuleCommentRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([ ^/*][^*]*\*+)*)\//gim, 7436 cssPolyfillUnscopedRuleCommentRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([ ^/*][^*]*\*+)*)\//gim,
6661 cssPseudoRe = /::(x-[^\s{,(]*)/gim, 7437 cssPseudoRe = /::(x-[^\s{,(]*)/gim,
6662 cssPartRe = /::part\(([^)]*)\)/gim, 7438 cssPartRe = /::part\(([^)]*)\)/gim,
6663 // note: :host pre-processed to -shadowcsshost. 7439 // note: :host pre-processed to -shadowcsshost.
6664 polyfillHost = '-shadowcsshost', 7440 polyfillHost = '-shadowcsshost',
6665 cssColonHostRe = new RegExp('(' + polyfillHost + 7441 // note: :ancestor pre-processed to -shadowcssancestor.
6666 ')(?:\\((' + 7442 polyfillAncestor = '-shadowcssancestor',
7443 parenSuffix = ')(?:\\((' +
6667 '(?:\\([^)(]*\\)|[^)(]*)+?' + 7444 '(?:\\([^)(]*\\)|[^)(]*)+?' +
6668 ')\\))?([^,{]*)', 'gim'), 7445 ')\\))?([^,{]*)';
7446 cssColonHostRe = new RegExp('(' + polyfillHost + parenSuffix, 'gim'),
7447 cssColonAncestorRe = new RegExp('(' + polyfillAncestor + parenSuffix, 'gim') ,
6669 selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$', 7448 selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$',
6670 hostRe = /@host/gim, 7449 hostRe = /@host/gim,
6671 colonHostRe = /\:host/gim, 7450 colonHostRe = /\:host/gim,
7451 colonAncestorRe = /\:ancestor/gim,
6672 /* host name without combinator */ 7452 /* host name without combinator */
6673 polyfillHostNoCombinator = polyfillHost + '-no-combinator', 7453 polyfillHostNoCombinator = polyfillHost + '-no-combinator',
6674 polyfillHostRe = new RegExp(polyfillHost, 'gim'); 7454 polyfillHostRe = new RegExp(polyfillHost, 'gim');
7455 polyfillAncestorRe = new RegExp(polyfillAncestor, 'gim');
6675 7456
6676 function stylesToCssText(styles, preserveComments) { 7457 function stylesToCssText(styles, preserveComments) {
6677 var cssText = ''; 7458 var cssText = '';
6678 Array.prototype.forEach.call(styles, function(s) { 7459 Array.prototype.forEach.call(styles, function(s) {
6679 cssText += s.textContent + '\n\n'; 7460 cssText += s.textContent + '\n\n';
6680 }); 7461 });
6681 // strip comments for easier processing 7462 // strip comments for easier processing
6682 if (!preserveComments) { 7463 if (!preserveComments) {
6683 cssText = cssText.replace(cssCommentRe, ''); 7464 cssText = cssText.replace(cssCommentRe, '');
6684 } 7465 }
(...skipping 25 matching lines...) Expand all
6710 if (cssText) { 7491 if (cssText) {
6711 getSheet().appendChild(document.createTextNode(cssText)); 7492 getSheet().appendChild(document.createTextNode(cssText));
6712 } 7493 }
6713 } 7494 }
6714 7495
6715 var sheet; 7496 var sheet;
6716 function getSheet() { 7497 function getSheet() {
6717 if (!sheet) { 7498 if (!sheet) {
6718 sheet = document.createElement("style"); 7499 sheet = document.createElement("style");
6719 sheet.setAttribute('ShadowCSSShim', ''); 7500 sheet.setAttribute('ShadowCSSShim', '');
7501 sheet.shadowCssShim = true;
6720 } 7502 }
6721 return sheet; 7503 return sheet;
6722 } 7504 }
6723 7505
6724 // add polyfill stylesheet to document 7506 // add polyfill stylesheet to document
6725 if (window.ShadowDOMPolyfill) { 7507 if (window.ShadowDOMPolyfill) {
6726 addCssToDocument('style { display: none !important; }\n'); 7508 addCssToDocument('style { display: none !important; }\n');
6727 var head = document.querySelector('head'); 7509 var doc = wrap(document);
7510 var head = doc.querySelector('head');
6728 head.insertBefore(getSheet(), head.childNodes[0]); 7511 head.insertBefore(getSheet(), head.childNodes[0]);
7512
7513 document.addEventListener('DOMContentLoaded', function() {
7514 if (window.HTMLImports && !HTMLImports.useNative) {
7515 HTMLImports.importer.preloadSelectors +=
7516 ', link[rel=stylesheet]:not([nopolyfill])';
7517 HTMLImports.parser.parseGeneric = function(elt) {
7518 if (elt.shadowCssShim) {
7519 return;
7520 }
7521 var style = elt;
7522 if (!elt.hasAttribute('nopolyfill')) {
7523 if (elt.__resource) {
7524 style = elt.ownerDocument.createElement('style');
7525 style.textContent = Platform.loader.resolveUrlsInCssText(
7526 elt.__resource, elt.href);
7527 // remove links from main document
7528 if (elt.ownerDocument === doc) {
7529 elt.parentNode.removeChild(elt);
7530 }
7531 } else {
7532 Platform.loader.resolveUrlsInStyle(style);
7533 }
7534 var styles = [style];
7535 style.textContent = ShadowCSS.stylesToShimmedCssText(styles, styles);
7536 style.shadowCssShim = true;
7537 }
7538 // place in document
7539 if (style.parentNode !== head) {
7540 head.appendChild(style);
7541 }
7542 }
7543 }
7544 });
6729 } 7545 }
6730 7546
6731 // exports 7547 // exports
6732 scope.ShadowCSS = ShadowCSS; 7548 scope.ShadowCSS = ShadowCSS;
6733 7549
6734 })(window.Platform); 7550 })(window.Platform);
6735 } 7551 }
OLDNEW
« no previous file with comments | « pkg/shadow_dom/REVISIONS ('k') | pkg/shadow_dom/lib/shadow_dom.min.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698