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

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
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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
3325 * @type {Node|undefined} 3609 * @type {Node|undefined}
3326 * @private 3610 * @private
3327 */ 3611 */
3328 this.nextSibling_ = undefined; 3612 this.nextSibling_ = undefined;
3329 3613
3330 /** 3614 /**
3331 * @type {Node|undefined} 3615 * @type {Node|undefined}
3332 * @private 3616 * @private
3333 */ 3617 */
3334 this.previousSibling_ = undefined; 3618 this.previousSibling_ = undefined;
3335 }; 3619 }
3336 3620
3337 var OriginalDocumentFragment = window.DocumentFragment; 3621 var OriginalDocumentFragment = window.DocumentFragment;
3338 var originalAppendChild = OriginalNode.prototype.appendChild; 3622 var originalAppendChild = OriginalNode.prototype.appendChild;
3339 var originalCompareDocumentPosition = 3623 var originalCompareDocumentPosition =
3340 OriginalNode.prototype.compareDocumentPosition; 3624 OriginalNode.prototype.compareDocumentPosition;
3341 var originalInsertBefore = OriginalNode.prototype.insertBefore; 3625 var originalInsertBefore = OriginalNode.prototype.insertBefore;
3342 var originalRemoveChild = OriginalNode.prototype.removeChild; 3626 var originalRemoveChild = OriginalNode.prototype.removeChild;
3343 var originalReplaceChild = OriginalNode.prototype.replaceChild; 3627 var originalReplaceChild = OriginalNode.prototype.replaceChild;
3344 3628
3345 var isIe = /Trident/.test(navigator.userAgent); 3629 var isIe = /Trident/.test(navigator.userAgent);
(...skipping 13 matching lines...) Expand all
3359 3643
3360 Node.prototype = Object.create(EventTarget.prototype); 3644 Node.prototype = Object.create(EventTarget.prototype);
3361 mixin(Node.prototype, { 3645 mixin(Node.prototype, {
3362 appendChild: function(childWrapper) { 3646 appendChild: function(childWrapper) {
3363 return this.insertBefore(childWrapper, null); 3647 return this.insertBefore(childWrapper, null);
3364 }, 3648 },
3365 3649
3366 insertBefore: function(childWrapper, refWrapper) { 3650 insertBefore: function(childWrapper, refWrapper) {
3367 assertIsNodeWrapper(childWrapper); 3651 assertIsNodeWrapper(childWrapper);
3368 3652
3369 refWrapper = refWrapper || null; 3653 var refNode;
3370 refWrapper && assertIsNodeWrapper(refWrapper); 3654 if (refWrapper) {
3655 if (isWrapper(refWrapper)) {
3656 refNode = unwrap(refWrapper);
3657 } else {
3658 refNode = refWrapper;
3659 refWrapper = wrap(refNode);
3660 }
3661 } else {
3662 refWrapper = null;
3663 refNode = null;
3664 }
3665
3371 refWrapper && assert(refWrapper.parentNode === this); 3666 refWrapper && assert(refWrapper.parentNode === this);
3372 3667
3373 var nodes; 3668 var nodes;
3374 var previousNode = 3669 var previousNode =
3375 refWrapper ? refWrapper.previousSibling : this.lastChild; 3670 refWrapper ? refWrapper.previousSibling : this.lastChild;
3376 3671
3377 var useNative = !this.invalidateShadowRenderer() && 3672 var useNative = !this.invalidateShadowRenderer() &&
3378 !invalidateParent(childWrapper); 3673 !invalidateParent(childWrapper);
3379 3674
3380 if (useNative) 3675 if (useNative)
3381 nodes = collectNodesNative(childWrapper); 3676 nodes = collectNodesNative(childWrapper);
3382 else 3677 else
3383 nodes = collectNodes(childWrapper, this, previousNode, refWrapper); 3678 nodes = collectNodes(childWrapper, this, previousNode, refWrapper);
3384 3679
3385 if (useNative) { 3680 if (useNative) {
3386 ensureSameOwnerDocument(this, childWrapper); 3681 ensureSameOwnerDocument(this, childWrapper);
3387 originalInsertBefore.call(this.impl, unwrap(childWrapper), 3682 clearChildNodes(this);
3388 unwrap(refWrapper)); 3683 originalInsertBefore.call(this.impl, unwrap(childWrapper), refNode);
3389 } else { 3684 } else {
3390 if (!previousNode) 3685 if (!previousNode)
3391 this.firstChild_ = nodes[0]; 3686 this.firstChild_ = nodes[0];
3392 if (!refWrapper) 3687 if (!refWrapper)
3393 this.lastChild_ = nodes[nodes.length - 1]; 3688 this.lastChild_ = nodes[nodes.length - 1];
3394 3689
3395 var refNode = unwrap(refWrapper);
3396 var parentNode = refNode ? refNode.parentNode : this.impl; 3690 var parentNode = refNode ? refNode.parentNode : this.impl;
3397 3691
3398 // insertBefore refWrapper no matter what the parent is? 3692 // insertBefore refWrapper no matter what the parent is?
3399 if (parentNode) { 3693 if (parentNode) {
3400 originalInsertBefore.call(parentNode, 3694 originalInsertBefore.call(parentNode,
3401 unwrapNodesForInsertion(this, nodes), refNode); 3695 unwrapNodesForInsertion(this, nodes), refNode);
3402 } else { 3696 } else {
3403 adoptNodesIfNeeded(this, nodes); 3697 adoptNodesIfNeeded(this, nodes);
3404 } 3698 }
3405 } 3699 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
3456 if (childWrapperPreviousSibling) 3750 if (childWrapperPreviousSibling)
3457 childWrapperPreviousSibling.nextSibling_ = childWrapperNextSibling; 3751 childWrapperPreviousSibling.nextSibling_ = childWrapperNextSibling;
3458 if (childWrapperNextSibling) { 3752 if (childWrapperNextSibling) {
3459 childWrapperNextSibling.previousSibling_ = 3753 childWrapperNextSibling.previousSibling_ =
3460 childWrapperPreviousSibling; 3754 childWrapperPreviousSibling;
3461 } 3755 }
3462 3756
3463 childWrapper.previousSibling_ = childWrapper.nextSibling_ = 3757 childWrapper.previousSibling_ = childWrapper.nextSibling_ =
3464 childWrapper.parentNode_ = undefined; 3758 childWrapper.parentNode_ = undefined;
3465 } else { 3759 } else {
3760 clearChildNodes(this);
3466 removeChildOriginalHelper(this.impl, childNode); 3761 removeChildOriginalHelper(this.impl, childNode);
3467 } 3762 }
3468 3763
3469 if (!surpressMutations) { 3764 if (!surpressMutations) {
3470 enqueueMutation(this, 'childList', { 3765 enqueueMutation(this, 'childList', {
3471 removedNodes: createOneElementNodeList(childWrapper), 3766 removedNodes: createOneElementNodeList(childWrapper),
3472 nextSibling: childWrapperNextSibling, 3767 nextSibling: childWrapperNextSibling,
3473 previousSibling: childWrapperPreviousSibling 3768 previousSibling: childWrapperPreviousSibling
3474 }); 3769 });
3475 } 3770 }
3476 3771
3477 registerTransientObservers(this, childWrapper); 3772 registerTransientObservers(this, childWrapper);
3478 3773
3479 return childWrapper; 3774 return childWrapper;
3480 }, 3775 },
3481 3776
3482 replaceChild: function(newChildWrapper, oldChildWrapper) { 3777 replaceChild: function(newChildWrapper, oldChildWrapper) {
3483 assertIsNodeWrapper(newChildWrapper); 3778 assertIsNodeWrapper(newChildWrapper);
3484 assertIsNodeWrapper(oldChildWrapper); 3779
3780 var oldChildNode;
3781 if (isWrapper(oldChildWrapper)) {
3782 oldChildNode = unwrap(oldChildWrapper);
3783 } else {
3784 oldChildNode = oldChildWrapper;
3785 oldChildWrapper = wrap(oldChildNode);
3786 }
3485 3787
3486 if (oldChildWrapper.parentNode !== this) { 3788 if (oldChildWrapper.parentNode !== this) {
3487 // TODO(arv): DOMException 3789 // TODO(arv): DOMException
3488 throw new Error('NotFoundError'); 3790 throw new Error('NotFoundError');
3489 } 3791 }
3490 3792
3491 var oldChildNode = unwrap(oldChildWrapper);
3492 var nextNode = oldChildWrapper.nextSibling; 3793 var nextNode = oldChildWrapper.nextSibling;
3493 var previousNode = oldChildWrapper.previousSibling; 3794 var previousNode = oldChildWrapper.previousSibling;
3494 var nodes; 3795 var nodes;
3495 3796
3496 var useNative = !this.invalidateShadowRenderer() && 3797 var useNative = !this.invalidateShadowRenderer() &&
3497 !invalidateParent(newChildWrapper); 3798 !invalidateParent(newChildWrapper);
3498 3799
3499 if (useNative) { 3800 if (useNative) {
3500 nodes = collectNodesNative(newChildWrapper); 3801 nodes = collectNodesNative(newChildWrapper);
3501 } else { 3802 } else {
(...skipping 13 matching lines...) Expand all
3515 3816
3516 // replaceChild no matter what the parent is? 3817 // replaceChild no matter what the parent is?
3517 if (oldChildNode.parentNode) { 3818 if (oldChildNode.parentNode) {
3518 originalReplaceChild.call( 3819 originalReplaceChild.call(
3519 oldChildNode.parentNode, 3820 oldChildNode.parentNode,
3520 unwrapNodesForInsertion(this, nodes), 3821 unwrapNodesForInsertion(this, nodes),
3521 oldChildNode); 3822 oldChildNode);
3522 } 3823 }
3523 } else { 3824 } else {
3524 ensureSameOwnerDocument(this, newChildWrapper); 3825 ensureSameOwnerDocument(this, newChildWrapper);
3826 clearChildNodes(this);
3525 originalReplaceChild.call(this.impl, unwrap(newChildWrapper), 3827 originalReplaceChild.call(this.impl, unwrap(newChildWrapper),
3526 oldChildNode); 3828 oldChildNode);
3527 } 3829 }
3528 3830
3529 enqueueMutation(this, 'childList', { 3831 enqueueMutation(this, 'childList', {
3530 addedNodes: nodes, 3832 addedNodes: nodes,
3531 removedNodes: createOneElementNodeList(oldChildWrapper), 3833 removedNodes: createOneElementNodeList(oldChildWrapper),
3532 nextSibling: nextNode, 3834 nextSibling: nextNode,
3533 previousSibling: previousNode 3835 previousSibling: previousNode
3534 }); 3836 });
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
3591 p = p.parentNode; 3893 p = p.parentNode;
3592 } 3894 }
3593 return p; 3895 return p;
3594 }, 3896 },
3595 3897
3596 get textContent() { 3898 get textContent() {
3597 // TODO(arv): This should fallback to this.impl.textContent if there 3899 // TODO(arv): This should fallback to this.impl.textContent if there
3598 // are no shadow trees below or above the context node. 3900 // are no shadow trees below or above the context node.
3599 var s = ''; 3901 var s = '';
3600 for (var child = this.firstChild; child; child = child.nextSibling) { 3902 for (var child = this.firstChild; child; child = child.nextSibling) {
3601 s += child.textContent; 3903 if (child.nodeType != Node.COMMENT_NODE) {
3904 s += child.textContent;
3905 }
3602 } 3906 }
3603 return s; 3907 return s;
3604 }, 3908 },
3605 set textContent(textContent) { 3909 set textContent(textContent) {
3606 var removedNodes = snapshotNodeList(this.childNodes); 3910 var removedNodes = snapshotNodeList(this.childNodes);
3607 3911
3608 if (this.invalidateShadowRenderer()) { 3912 if (this.invalidateShadowRenderer()) {
3609 removeAllChildNodes(this); 3913 removeAllChildNodes(this);
3610 if (textContent !== '') { 3914 if (textContent !== '') {
3611 var textNode = this.impl.ownerDocument.createTextNode(textContent); 3915 var textNode = this.impl.ownerDocument.createTextNode(textContent);
3612 this.appendChild(textNode); 3916 this.appendChild(textNode);
3613 } 3917 }
3614 } else { 3918 } else {
3919 clearChildNodes(this);
3615 this.impl.textContent = textContent; 3920 this.impl.textContent = textContent;
3616 } 3921 }
3617 3922
3618 var addedNodes = snapshotNodeList(this.childNodes); 3923 var addedNodes = snapshotNodeList(this.childNodes);
3619 3924
3620 enqueueMutation(this, 'childList', { 3925 enqueueMutation(this, 'childList', {
3621 addedNodes: addedNodes, 3926 addedNodes: addedNodes,
3622 removedNodes: removedNodes 3927 removedNodes: removedNodes
3623 }); 3928 });
3624 3929
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
3871 }); 4176 });
3872 4177
3873 mixin(CharacterData.prototype, ChildNodeInterface); 4178 mixin(CharacterData.prototype, ChildNodeInterface);
3874 4179
3875 registerWrapper(OriginalCharacterData, CharacterData, 4180 registerWrapper(OriginalCharacterData, CharacterData,
3876 document.createTextNode('')); 4181 document.createTextNode(''));
3877 4182
3878 scope.wrappers.CharacterData = CharacterData; 4183 scope.wrappers.CharacterData = CharacterData;
3879 })(window.ShadowDOMPolyfill); 4184 })(window.ShadowDOMPolyfill);
3880 4185
4186 // Copyright 2014 The Polymer Authors. All rights reserved.
4187 // Use of this source code is goverened by a BSD-style
4188 // license that can be found in the LICENSE file.
4189
4190 (function(scope) {
4191 'use strict';
4192
4193 var CharacterData = scope.wrappers.CharacterData;
4194 var enqueueMutation = scope.enqueueMutation;
4195 var mixin = scope.mixin;
4196 var registerWrapper = scope.registerWrapper;
4197
4198 function toUInt32(x) {
4199 return x >>> 0;
4200 }
4201
4202 var OriginalText = window.Text;
4203
4204 function Text(node) {
4205 CharacterData.call(this, node);
4206 }
4207 Text.prototype = Object.create(CharacterData.prototype);
4208 mixin(Text.prototype, {
4209 splitText: function(offset) {
4210 offset = toUInt32(offset);
4211 var s = this.data;
4212 if (offset > s.length)
4213 throw new Error('IndexSizeError');
4214 var head = s.slice(0, offset);
4215 var tail = s.slice(offset);
4216 this.data = head;
4217 var newTextNode = this.ownerDocument.createTextNode(tail);
4218 if (this.parentNode)
4219 this.parentNode.insertBefore(newTextNode, this.nextSibling);
4220 return newTextNode;
4221 }
4222 });
4223
4224 registerWrapper(OriginalText, Text, document.createTextNode(''));
4225
4226 scope.wrappers.Text = Text;
4227 })(window.ShadowDOMPolyfill);
4228
3881 // Copyright 2013 The Polymer Authors. All rights reserved. 4229 // Copyright 2013 The Polymer Authors. All rights reserved.
3882 // Use of this source code is goverened by a BSD-style 4230 // Use of this source code is goverened by a BSD-style
3883 // license that can be found in the LICENSE file. 4231 // license that can be found in the LICENSE file.
3884 4232
3885 (function(scope) { 4233 (function(scope) {
3886 'use strict'; 4234 'use strict';
3887 4235
3888 var ChildNodeInterface = scope.ChildNodeInterface; 4236 var ChildNodeInterface = scope.ChildNodeInterface;
3889 var GetElementsByInterface = scope.GetElementsByInterface; 4237 var GetElementsByInterface = scope.GetElementsByInterface;
3890 var Node = scope.wrappers.Node; 4238 var Node = scope.wrappers.Node;
3891 var ParentNodeInterface = scope.ParentNodeInterface; 4239 var ParentNodeInterface = scope.ParentNodeInterface;
3892 var SelectorsInterface = scope.SelectorsInterface; 4240 var SelectorsInterface = scope.SelectorsInterface;
3893 var addWrapNodeListMethod = scope.addWrapNodeListMethod; 4241 var addWrapNodeListMethod = scope.addWrapNodeListMethod;
3894 var enqueueMutation = scope.enqueueMutation; 4242 var enqueueMutation = scope.enqueueMutation;
3895 var mixin = scope.mixin; 4243 var mixin = scope.mixin;
3896 var oneOf = scope.oneOf; 4244 var oneOf = scope.oneOf;
3897 var registerWrapper = scope.registerWrapper; 4245 var registerWrapper = scope.registerWrapper;
3898 var wrappers = scope.wrappers; 4246 var wrappers = scope.wrappers;
3899 4247
3900 var OriginalElement = window.Element; 4248 var OriginalElement = window.Element;
3901 4249
3902 var matchesName = oneOf(OriginalElement.prototype, [ 4250 var matchesNames = [
3903 'matches', 4251 'matches', // needs to come first.
3904 'mozMatchesSelector', 4252 'mozMatchesSelector',
3905 'msMatchesSelector', 4253 'msMatchesSelector',
3906 'webkitMatchesSelector', 4254 'webkitMatchesSelector',
3907 ]); 4255 ].filter(function(name) {
4256 return OriginalElement.prototype[name];
4257 });
4258
4259 var matchesName = matchesNames[0];
3908 4260
3909 var originalMatches = OriginalElement.prototype[matchesName]; 4261 var originalMatches = OriginalElement.prototype[matchesName];
3910 4262
3911 function invalidateRendererBasedOnAttribute(element, name) { 4263 function invalidateRendererBasedOnAttribute(element, name) {
3912 // Only invalidate if parent node is a shadow host. 4264 // Only invalidate if parent node is a shadow host.
3913 var p = element.parentNode; 4265 var p = element.parentNode;
3914 if (!p || !p.shadowRoot) 4266 if (!p || !p.shadowRoot)
3915 return; 4267 return;
3916 4268
3917 var renderer = scope.getRendererForHost(p); 4269 var renderer = scope.getRendererForHost(p);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
3961 this.impl.removeAttribute(name); 4313 this.impl.removeAttribute(name);
3962 enqueAttributeChange(this, name, oldValue); 4314 enqueAttributeChange(this, name, oldValue);
3963 invalidateRendererBasedOnAttribute(this, name); 4315 invalidateRendererBasedOnAttribute(this, name);
3964 }, 4316 },
3965 4317
3966 matches: function(selector) { 4318 matches: function(selector) {
3967 return originalMatches.call(this.impl, selector); 4319 return originalMatches.call(this.impl, selector);
3968 } 4320 }
3969 }); 4321 });
3970 4322
3971 Element.prototype[matchesName] = function(selector) { 4323 matchesNames.forEach(function(name) {
3972 return this.matches(selector); 4324 if (name !== 'matches') {
3973 }; 4325 Element.prototype[name] = function(selector) {
4326 return this.matches(selector);
4327 };
4328 }
4329 });
3974 4330
3975 if (OriginalElement.prototype.webkitCreateShadowRoot) { 4331 if (OriginalElement.prototype.webkitCreateShadowRoot) {
3976 Element.prototype.webkitCreateShadowRoot = 4332 Element.prototype.webkitCreateShadowRoot =
3977 Element.prototype.createShadowRoot; 4333 Element.prototype.createShadowRoot;
3978 } 4334 }
3979 4335
3980 /** 4336 /**
3981 * Useful for generating the accessor pair for a property that reflects an 4337 * Useful for generating the accessor pair for a property that reflects an
3982 * attribute. 4338 * attribute.
3983 */ 4339 */
(...skipping 13 matching lines...) Expand all
3997 } 4353 }
3998 4354
3999 setterDirtiesAttribute(Element.prototype, 'id'); 4355 setterDirtiesAttribute(Element.prototype, 'id');
4000 setterDirtiesAttribute(Element.prototype, 'className', 'class'); 4356 setterDirtiesAttribute(Element.prototype, 'className', 'class');
4001 4357
4002 mixin(Element.prototype, ChildNodeInterface); 4358 mixin(Element.prototype, ChildNodeInterface);
4003 mixin(Element.prototype, GetElementsByInterface); 4359 mixin(Element.prototype, GetElementsByInterface);
4004 mixin(Element.prototype, ParentNodeInterface); 4360 mixin(Element.prototype, ParentNodeInterface);
4005 mixin(Element.prototype, SelectorsInterface); 4361 mixin(Element.prototype, SelectorsInterface);
4006 4362
4007 registerWrapper(OriginalElement, Element); 4363 registerWrapper(OriginalElement, Element,
4364 document.createElementNS(null, 'x'));
4008 4365
4009 // TODO(arv): Export setterDirtiesAttribute and apply it to more bindings 4366 // TODO(arv): Export setterDirtiesAttribute and apply it to more bindings
4010 // that reflect attributes. 4367 // that reflect attributes.
4011 scope.matchesName = matchesName; 4368 scope.matchesNames = matchesNames;
4012 scope.wrappers.Element = Element; 4369 scope.wrappers.Element = Element;
4013 })(window.ShadowDOMPolyfill); 4370 })(window.ShadowDOMPolyfill);
4014 4371
4015 // Copyright 2013 The Polymer Authors. All rights reserved. 4372 // Copyright 2013 The Polymer Authors. All rights reserved.
4016 // Use of this source code is goverened by a BSD-style 4373 // Use of this source code is goverened by a BSD-style
4017 // license that can be found in the LICENSE file. 4374 // license that can be found in the LICENSE file.
4018 4375
4019 (function(scope) { 4376 (function(scope) {
4020 'use strict'; 4377 'use strict';
4021 4378
4022 var Element = scope.wrappers.Element; 4379 var Element = scope.wrappers.Element;
4023 var defineGetter = scope.defineGetter; 4380 var defineGetter = scope.defineGetter;
4024 var enqueueMutation = scope.enqueueMutation; 4381 var enqueueMutation = scope.enqueueMutation;
4025 var mixin = scope.mixin; 4382 var mixin = scope.mixin;
4026 var nodesWereAdded = scope.nodesWereAdded; 4383 var nodesWereAdded = scope.nodesWereAdded;
4027 var nodesWereRemoved = scope.nodesWereRemoved; 4384 var nodesWereRemoved = scope.nodesWereRemoved;
4028 var registerWrapper = scope.registerWrapper; 4385 var registerWrapper = scope.registerWrapper;
4029 var snapshotNodeList = scope.snapshotNodeList; 4386 var snapshotNodeList = scope.snapshotNodeList;
4030 var unwrap = scope.unwrap; 4387 var unwrap = scope.unwrap;
4031 var wrap = scope.wrap; 4388 var wrap = scope.wrap;
4032 4389
4033 ///////////////////////////////////////////////////////////////////////////// 4390 /////////////////////////////////////////////////////////////////////////////
4034 // innerHTML and outerHTML 4391 // innerHTML and outerHTML
4035 4392
4036 var escapeRegExp = /&|<|"/g; 4393 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#es capingString
4394 var escapeAttrRegExp = /[&\u00A0"]/g;
4395 var escapeDataRegExp = /[&\u00A0<>]/g;
4037 4396
4038 function escapeReplace(c) { 4397 function escapeReplace(c) {
4039 switch (c) { 4398 switch (c) {
4040 case '&': 4399 case '&':
4041 return '&amp;'; 4400 return '&amp;';
4042 case '<': 4401 case '<':
4043 return '&lt;'; 4402 return '&lt;';
4403 case '>':
4404 return '&gt;';
4044 case '"': 4405 case '"':
4045 return '&quot;' 4406 return '&quot;'
4407 case '\u00A0':
4408 return '&nbsp;';
4046 } 4409 }
4047 } 4410 }
4048 4411
4049 function escape(s) { 4412 function escapeAttr(s) {
4050 return s.replace(escapeRegExp, escapeReplace); 4413 return s.replace(escapeAttrRegExp, escapeReplace);
4414 }
4415
4416 function escapeData(s) {
4417 return s.replace(escapeDataRegExp, escapeReplace);
4418 }
4419
4420 function makeSet(arr) {
4421 var set = {};
4422 for (var i = 0; i < arr.length; i++) {
4423 set[arr[i]] = true;
4424 }
4425 return set;
4051 } 4426 }
4052 4427
4053 // http://www.whatwg.org/specs/web-apps/current-work/#void-elements 4428 // http://www.whatwg.org/specs/web-apps/current-work/#void-elements
4054 var voidElements = { 4429 var voidElements = makeSet([
4055 'area': true, 4430 'area',
4056 'base': true, 4431 'base',
4057 'br': true, 4432 'br',
4058 'col': true, 4433 'col',
4059 'command': true, 4434 'command',
4060 'embed': true, 4435 'embed',
4061 'hr': true, 4436 'hr',
4062 'img': true, 4437 'img',
4063 'input': true, 4438 'input',
4064 'keygen': true, 4439 'keygen',
4065 'link': true, 4440 'link',
4066 'meta': true, 4441 'meta',
4067 'param': true, 4442 'param',
4068 'source': true, 4443 'source',
4069 'track': true, 4444 'track',
4070 'wbr': true 4445 'wbr'
4071 }; 4446 ]);
4072 4447
4073 function getOuterHTML(node) { 4448 var plaintextParents = makeSet([
4449 'style',
4450 'script',
4451 'xmp',
4452 'iframe',
4453 'noembed',
4454 'noframes',
4455 'plaintext',
4456 'noscript'
4457 ]);
4458
4459 function getOuterHTML(node, parentNode) {
4074 switch (node.nodeType) { 4460 switch (node.nodeType) {
4075 case Node.ELEMENT_NODE: 4461 case Node.ELEMENT_NODE:
4076 var tagName = node.tagName.toLowerCase(); 4462 var tagName = node.tagName.toLowerCase();
4077 var s = '<' + tagName; 4463 var s = '<' + tagName;
4078 var attrs = node.attributes; 4464 var attrs = node.attributes;
4079 for (var i = 0, attr; attr = attrs[i]; i++) { 4465 for (var i = 0, attr; attr = attrs[i]; i++) {
4080 s += ' ' + attr.name + '="' + escape(attr.value) + '"'; 4466 s += ' ' + attr.name + '="' + escapeAttr(attr.value) + '"';
4081 } 4467 }
4082 s += '>'; 4468 s += '>';
4083 if (voidElements[tagName]) 4469 if (voidElements[tagName])
4084 return s; 4470 return s;
4085 4471
4086 return s + getInnerHTML(node) + '</' + tagName + '>'; 4472 return s + getInnerHTML(node) + '</' + tagName + '>';
4087 4473
4088 case Node.TEXT_NODE: 4474 case Node.TEXT_NODE:
4089 return escape(node.nodeValue); 4475 var data = node.data;
4476 if (parentNode && plaintextParents[parentNode.localName])
4477 return data;
4478 return escapeData(data);
4090 4479
4091 case Node.COMMENT_NODE: 4480 case Node.COMMENT_NODE:
4092 return '<!--' + escape(node.nodeValue) + '-->'; 4481 return '<!--' + node.data + '-->';
4482
4093 default: 4483 default:
4094 console.error(node); 4484 console.error(node);
4095 throw new Error('not implemented'); 4485 throw new Error('not implemented');
4096 } 4486 }
4097 } 4487 }
4098 4488
4099 function getInnerHTML(node) { 4489 function getInnerHTML(node) {
4100 var s = ''; 4490 var s = '';
4101 for (var child = node.firstChild; child; child = child.nextSibling) { 4491 for (var child = node.firstChild; child; child = child.nextSibling) {
4102 s += getOuterHTML(child); 4492 s += getOuterHTML(child, node);
4103 } 4493 }
4104 return s; 4494 return s;
4105 } 4495 }
4106 4496
4107 function setInnerHTML(node, value, opt_tagName) { 4497 function setInnerHTML(node, value, opt_tagName) {
4108 var tagName = opt_tagName || 'div'; 4498 var tagName = opt_tagName || 'div';
4109 node.textContent = ''; 4499 node.textContent = '';
4110 var tempElement = unwrap(node.ownerDocument.createElement(tagName)); 4500 var tempElement = unwrap(node.ownerDocument.createElement(tagName));
4111 tempElement.innerHTML = value; 4501 tempElement.innerHTML = value;
4112 var firstChild; 4502 var firstChild;
4113 while (firstChild = tempElement.firstChild) { 4503 while (firstChild = tempElement.firstChild) {
4114 node.appendChild(wrap(firstChild)); 4504 node.appendChild(wrap(firstChild));
4115 } 4505 }
4116 } 4506 }
4117 4507
4508 // IE11 does not have MSIE in the user agent string.
4509 var oldIe = /MSIE/.test(navigator.userAgent);
4510
4118 var OriginalHTMLElement = window.HTMLElement; 4511 var OriginalHTMLElement = window.HTMLElement;
4119 4512
4120 function HTMLElement(node) { 4513 function HTMLElement(node) {
4121 Element.call(this, node); 4514 Element.call(this, node);
4122 } 4515 }
4123 HTMLElement.prototype = Object.create(Element.prototype); 4516 HTMLElement.prototype = Object.create(Element.prototype);
4124 mixin(HTMLElement.prototype, { 4517 mixin(HTMLElement.prototype, {
4125 get innerHTML() { 4518 get innerHTML() {
4126 // TODO(arv): This should fallback to this.impl.innerHTML if there 4519 // TODO(arv): This should fallback to this.impl.innerHTML if there
4127 // are no shadow trees below or above the context node. 4520 // are no shadow trees below or above the context node.
4128 return getInnerHTML(this); 4521 return getInnerHTML(this);
4129 }, 4522 },
4130 set innerHTML(value) { 4523 set innerHTML(value) {
4524 // IE9 does not handle set innerHTML correctly on plaintextParents. It
4525 // creates element children. For example
4526 //
4527 // scriptElement.innerHTML = '<a>test</a>'
4528 //
4529 // Creates a single HTMLAnchorElement child.
4530 if (oldIe && plaintextParents[this.localName]) {
4531 this.textContent = value;
4532 return;
4533 }
4534
4131 var removedNodes = snapshotNodeList(this.childNodes); 4535 var removedNodes = snapshotNodeList(this.childNodes);
4132 4536
4133 if (this.invalidateShadowRenderer()) 4537 if (this.invalidateShadowRenderer())
4134 setInnerHTML(this, value, this.tagName); 4538 setInnerHTML(this, value, this.tagName);
4135 else 4539 else
4136 this.impl.innerHTML = value; 4540 this.impl.innerHTML = value;
4137 var addedNodes = snapshotNodeList(this.childNodes); 4541 var addedNodes = snapshotNodeList(this.childNodes);
4138 4542
4139 enqueueMutation(this, 'childList', { 4543 enqueueMutation(this, 'childList', {
4140 addedNodes: addedNodes, 4544 addedNodes: addedNodes,
4141 removedNodes: removedNodes 4545 removedNodes: removedNodes
4142 }); 4546 });
4143 4547
4144 nodesWereRemoved(removedNodes); 4548 nodesWereRemoved(removedNodes);
4145 nodesWereAdded(addedNodes); 4549 nodesWereAdded(addedNodes);
4146 }, 4550 },
4147 4551
4148 get outerHTML() { 4552 get outerHTML() {
4149 // TODO(arv): This should fallback to HTMLElement_prototype.outerHTML if t here 4553 return getOuterHTML(this, this.parentNode);
4150 // are no shadow trees below or above the context node.
4151 return getOuterHTML(this);
4152 }, 4554 },
4153 set outerHTML(value) { 4555 set outerHTML(value) {
4154 var p = this.parentNode; 4556 var p = this.parentNode;
4155 if (p) { 4557 if (p) {
4156 p.invalidateShadowRenderer(); 4558 p.invalidateShadowRenderer();
4157 this.impl.outerHTML = value; 4559 var df = frag(p, value);
4560 p.replaceChild(df, this);
4158 } 4561 }
4562 },
4563
4564 insertAdjacentHTML: function(position, text) {
4565 var contextElement, refNode;
4566 switch (String(position).toLowerCase()) {
4567 case 'beforebegin':
4568 contextElement = this.parentNode;
4569 refNode = this;
4570 break;
4571 case 'afterend':
4572 contextElement = this.parentNode;
4573 refNode = this.nextSibling;
4574 break;
4575 case 'afterbegin':
4576 contextElement = this;
4577 refNode = this.firstChild;
4578 break;
4579 case 'beforeend':
4580 contextElement = this;
4581 refNode = null;
4582 break;
4583 default:
4584 return;
4585 }
4586
4587 var df = frag(contextElement, text);
4588 contextElement.insertBefore(df, refNode);
4159 } 4589 }
4160 }); 4590 });
4161 4591
4592 function frag(contextElement, html) {
4593 // TODO(arv): This does not work with SVG and other non HTML elements.
4594 var p = unwrap(contextElement.cloneNode(false));
4595 p.innerHTML = html;
4596 var df = unwrap(document.createDocumentFragment());
4597 var c;
4598 while (c = p.firstChild) {
4599 df.appendChild(c);
4600 }
4601 return wrap(df);
4602 }
4603
4162 function getter(name) { 4604 function getter(name) {
4163 return function() { 4605 return function() {
4164 scope.renderAllPending(); 4606 scope.renderAllPending();
4165 return this.impl[name]; 4607 return this.impl[name];
4166 }; 4608 };
4167 } 4609 }
4168 4610
4169 function getterRequiresRendering(name) { 4611 function getterRequiresRendering(name) {
4170 defineGetter(HTMLElement, name, getter(name)); 4612 defineGetter(HTMLElement, name, getter(name));
4171 } 4613 }
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after
4609 case 'template': 5051 case 'template':
4610 return new HTMLTemplateElement(node); 5052 return new HTMLTemplateElement(node);
4611 } 5053 }
4612 HTMLElement.call(this, node); 5054 HTMLElement.call(this, node);
4613 } 5055 }
4614 HTMLUnknownElement.prototype = Object.create(HTMLElement.prototype); 5056 HTMLUnknownElement.prototype = Object.create(HTMLElement.prototype);
4615 registerWrapper(OriginalHTMLUnknownElement, HTMLUnknownElement); 5057 registerWrapper(OriginalHTMLUnknownElement, HTMLUnknownElement);
4616 scope.wrappers.HTMLUnknownElement = HTMLUnknownElement; 5058 scope.wrappers.HTMLUnknownElement = HTMLUnknownElement;
4617 })(window.ShadowDOMPolyfill); 5059 })(window.ShadowDOMPolyfill);
4618 5060
5061 // Copyright 2014 The Polymer Authors. All rights reserved.
5062 // Use of this source code is goverened by a BSD-style
5063 // license that can be found in the LICENSE file.
5064
5065 (function(scope) {
5066 'use strict';
5067
5068 var registerObject = scope.registerObject;
5069
5070 var SVG_NS = 'http://www.w3.org/2000/svg';
5071 var svgTitleElement = document.createElementNS(SVG_NS, 'title');
5072 var SVGTitleElement = registerObject(svgTitleElement);
5073 var SVGElement = Object.getPrototypeOf(SVGTitleElement.prototype).constructor;
5074
5075 scope.wrappers.SVGElement = SVGElement;
5076 })(window.ShadowDOMPolyfill);
5077
5078 // Copyright 2014 The Polymer Authors. All rights reserved.
5079 // Use of this source code is goverened by a BSD-style
5080 // license that can be found in the LICENSE file.
5081
5082 (function(scope) {
5083 'use strict';
5084
5085 var mixin = scope.mixin;
5086 var registerWrapper = scope.registerWrapper;
5087 var unwrap = scope.unwrap;
5088 var wrap = scope.wrap;
5089
5090 var OriginalSVGUseElement = window.SVGUseElement;
5091
5092 // IE uses SVGElement as parent interface, SVG2 (Blink & Gecko) uses
5093 // SVGGraphicsElement. Use the <g> element to get the right prototype.
5094
5095 var SVG_NS = 'http://www.w3.org/2000/svg';
5096 var gWrapper = wrap(document.createElementNS(SVG_NS, 'g'));
5097 var useElement = document.createElementNS(SVG_NS, 'use');
5098 var SVGGElement = gWrapper.constructor;
5099 var parentInterfacePrototype = Object.getPrototypeOf(SVGGElement.prototype);
5100 var parentInterface = parentInterfacePrototype.constructor;
5101
5102 function SVGUseElement(impl) {
5103 parentInterface.call(this, impl);
5104 }
5105
5106 SVGUseElement.prototype = Object.create(parentInterfacePrototype);
5107
5108 // Firefox does not expose instanceRoot.
5109 if ('instanceRoot' in useElement) {
5110 mixin(SVGUseElement.prototype, {
5111 get instanceRoot() {
5112 return wrap(unwrap(this).instanceRoot);
5113 },
5114 get animatedInstanceRoot() {
5115 return wrap(unwrap(this).animatedInstanceRoot);
5116 },
5117 });
5118 }
5119
5120 registerWrapper(OriginalSVGUseElement, SVGUseElement, useElement);
5121
5122 scope.wrappers.SVGUseElement = SVGUseElement;
5123 })(window.ShadowDOMPolyfill);
5124
5125 // Copyright 2014 The Polymer Authors. All rights reserved.
5126 // Use of this source code is goverened by a BSD-style
5127 // license that can be found in the LICENSE file.
5128
5129 (function(scope) {
5130 'use strict';
5131
5132 var EventTarget = scope.wrappers.EventTarget;
5133 var mixin = scope.mixin;
5134 var registerWrapper = scope.registerWrapper;
5135 var wrap = scope.wrap;
5136
5137 var OriginalSVGElementInstance = window.SVGElementInstance;
5138 if (!OriginalSVGElementInstance)
5139 return;
5140
5141 function SVGElementInstance(impl) {
5142 EventTarget.call(this, impl);
5143 }
5144
5145 SVGElementInstance.prototype = Object.create(EventTarget.prototype);
5146 mixin(SVGElementInstance.prototype, {
5147 /** @type {SVGElement} */
5148 get correspondingElement() {
5149 return wrap(this.impl.correspondingElement);
5150 },
5151
5152 /** @type {SVGUseElement} */
5153 get correspondingUseElement() {
5154 return wrap(this.impl.correspondingUseElement);
5155 },
5156
5157 /** @type {SVGElementInstance} */
5158 get parentNode() {
5159 return wrap(this.impl.parentNode);
5160 },
5161
5162 /** @type {SVGElementInstanceList} */
5163 get childNodes() {
5164 throw new Error('Not implemented');
5165 },
5166
5167 /** @type {SVGElementInstance} */
5168 get firstChild() {
5169 return wrap(this.impl.firstChild);
5170 },
5171
5172 /** @type {SVGElementInstance} */
5173 get lastChild() {
5174 return wrap(this.impl.lastChild);
5175 },
5176
5177 /** @type {SVGElementInstance} */
5178 get previousSibling() {
5179 return wrap(this.impl.previousSibling);
5180 },
5181
5182 /** @type {SVGElementInstance} */
5183 get nextSibling() {
5184 return wrap(this.impl.nextSibling);
5185 }
5186 });
5187
5188 registerWrapper(OriginalSVGElementInstance, SVGElementInstance);
5189
5190 scope.wrappers.SVGElementInstance = SVGElementInstance;
5191 })(window.ShadowDOMPolyfill);
5192
4619 // Copyright 2013 The Polymer Authors. All rights reserved. 5193 // Copyright 2013 The Polymer Authors. All rights reserved.
4620 // Use of this source code is goverened by a BSD-style 5194 // Use of this source code is goverened by a BSD-style
4621 // license that can be found in the LICENSE file. 5195 // license that can be found in the LICENSE file.
4622 5196
4623 (function(scope) { 5197 (function(scope) {
4624 'use strict'; 5198 'use strict';
4625 5199
4626 var mixin = scope.mixin; 5200 var mixin = scope.mixin;
4627 var registerWrapper = scope.registerWrapper; 5201 var registerWrapper = scope.registerWrapper;
4628 var unwrap = scope.unwrap; 5202 var unwrap = scope.unwrap;
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
4778 return wrap(this.impl.cloneRange()); 5352 return wrap(this.impl.cloneRange());
4779 }, 5353 },
4780 isPointInRange: function(node, offset) { 5354 isPointInRange: function(node, offset) {
4781 return this.impl.isPointInRange(unwrapIfNeeded(node), offset); 5355 return this.impl.isPointInRange(unwrapIfNeeded(node), offset);
4782 }, 5356 },
4783 comparePoint: function(node, offset) { 5357 comparePoint: function(node, offset) {
4784 return this.impl.comparePoint(unwrapIfNeeded(node), offset); 5358 return this.impl.comparePoint(unwrapIfNeeded(node), offset);
4785 }, 5359 },
4786 intersectsNode: function(node) { 5360 intersectsNode: function(node) {
4787 return this.impl.intersectsNode(unwrapIfNeeded(node)); 5361 return this.impl.intersectsNode(unwrapIfNeeded(node));
5362 },
5363 toString: function() {
5364 return this.impl.toString();
4788 } 5365 }
4789 }; 5366 };
4790 5367
4791 // IE9 does not have createContextualFragment. 5368 // IE9 does not have createContextualFragment.
4792 if (OriginalRange.prototype.createContextualFragment) { 5369 if (OriginalRange.prototype.createContextualFragment) {
4793 Range.prototype.createContextualFragment = function(html) { 5370 Range.prototype.createContextualFragment = function(html) {
4794 return wrap(this.impl.createContextualFragment(html)); 5371 return wrap(this.impl.createContextualFragment(html));
4795 }; 5372 };
4796 } 5373 }
4797 5374
(...skipping 14 matching lines...) Expand all
4812 var ParentNodeInterface = scope.ParentNodeInterface; 5389 var ParentNodeInterface = scope.ParentNodeInterface;
4813 var SelectorsInterface = scope.SelectorsInterface; 5390 var SelectorsInterface = scope.SelectorsInterface;
4814 var mixin = scope.mixin; 5391 var mixin = scope.mixin;
4815 var registerObject = scope.registerObject; 5392 var registerObject = scope.registerObject;
4816 5393
4817 var DocumentFragment = registerObject(document.createDocumentFragment()); 5394 var DocumentFragment = registerObject(document.createDocumentFragment());
4818 mixin(DocumentFragment.prototype, ParentNodeInterface); 5395 mixin(DocumentFragment.prototype, ParentNodeInterface);
4819 mixin(DocumentFragment.prototype, SelectorsInterface); 5396 mixin(DocumentFragment.prototype, SelectorsInterface);
4820 mixin(DocumentFragment.prototype, GetElementsByInterface); 5397 mixin(DocumentFragment.prototype, GetElementsByInterface);
4821 5398
4822 var Text = registerObject(document.createTextNode(''));
4823 var Comment = registerObject(document.createComment('')); 5399 var Comment = registerObject(document.createComment(''));
4824 5400
4825 scope.wrappers.Comment = Comment; 5401 scope.wrappers.Comment = Comment;
4826 scope.wrappers.DocumentFragment = DocumentFragment; 5402 scope.wrappers.DocumentFragment = DocumentFragment;
4827 scope.wrappers.Text = Text;
4828 5403
4829 })(window.ShadowDOMPolyfill); 5404 })(window.ShadowDOMPolyfill);
4830 5405
4831 // Copyright 2013 The Polymer Authors. All rights reserved. 5406 // Copyright 2013 The Polymer Authors. All rights reserved.
4832 // Use of this source code is goverened by a BSD-style 5407 // Use of this source code is goverened by a BSD-style
4833 // license that can be found in the LICENSE file. 5408 // license that can be found in the LICENSE file.
4834 5409
4835 (function(scope) { 5410 (function(scope) {
4836 'use strict'; 5411 'use strict';
4837 5412
4838 var DocumentFragment = scope.wrappers.DocumentFragment; 5413 var DocumentFragment = scope.wrappers.DocumentFragment;
4839 var elementFromPoint = scope.elementFromPoint; 5414 var elementFromPoint = scope.elementFromPoint;
4840 var getInnerHTML = scope.getInnerHTML; 5415 var getInnerHTML = scope.getInnerHTML;
4841 var mixin = scope.mixin; 5416 var mixin = scope.mixin;
4842 var rewrap = scope.rewrap; 5417 var rewrap = scope.rewrap;
4843 var setInnerHTML = scope.setInnerHTML; 5418 var setInnerHTML = scope.setInnerHTML;
4844 var unwrap = scope.unwrap; 5419 var unwrap = scope.unwrap;
4845 5420
4846 var shadowHostTable = new WeakMap(); 5421 var shadowHostTable = new WeakMap();
4847 var nextOlderShadowTreeTable = new WeakMap(); 5422 var nextOlderShadowTreeTable = new WeakMap();
4848 5423
5424 var spaceCharRe = /[ \t\n\r\f]/;
5425
4849 function ShadowRoot(hostWrapper) { 5426 function ShadowRoot(hostWrapper) {
4850 var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment()); 5427 var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment());
4851 DocumentFragment.call(this, node); 5428 DocumentFragment.call(this, node);
4852 5429
4853 // createDocumentFragment associates the node with a wrapper 5430 // createDocumentFragment associates the node with a wrapper
4854 // DocumentFragment instance. Override that. 5431 // DocumentFragment instance. Override that.
4855 rewrap(node, this); 5432 rewrap(node, this);
4856 5433
4857 var oldShadowRoot = hostWrapper.shadowRoot; 5434 var oldShadowRoot = hostWrapper.shadowRoot;
4858 nextOlderShadowTreeTable.set(this, oldShadowRoot); 5435 nextOlderShadowTreeTable.set(this, oldShadowRoot);
(...skipping 20 matching lines...) Expand all
4879 5456
4880 invalidateShadowRenderer: function() { 5457 invalidateShadowRenderer: function() {
4881 return shadowHostTable.get(this).invalidateShadowRenderer(); 5458 return shadowHostTable.get(this).invalidateShadowRenderer();
4882 }, 5459 },
4883 5460
4884 elementFromPoint: function(x, y) { 5461 elementFromPoint: function(x, y) {
4885 return elementFromPoint(this, this.ownerDocument, x, y); 5462 return elementFromPoint(this, this.ownerDocument, x, y);
4886 }, 5463 },
4887 5464
4888 getElementById: function(id) { 5465 getElementById: function(id) {
4889 return this.querySelector('#' + id); 5466 if (spaceCharRe.test(id))
5467 return null;
5468 return this.querySelector('[id="' + id + '"]');
4890 } 5469 }
4891 }); 5470 });
4892 5471
4893 scope.wrappers.ShadowRoot = ShadowRoot; 5472 scope.wrappers.ShadowRoot = ShadowRoot;
4894 5473
4895 })(window.ShadowDOMPolyfill); 5474 })(window.ShadowDOMPolyfill);
4896 5475
4897 // Copyright 2013 The Polymer Authors. All rights reserved. 5476 // Copyright 2013 The Polymer Authors. All rights reserved.
4898 // Use of this source code is governed by a BSD-style 5477 // Use of this source code is governed by a BSD-style
4899 // license that can be found in the LICENSE file. 5478 // license that can be found in the LICENSE file.
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
5079 return true; 5658 return true;
5080 5659
5081 // Here we know the select attribute is a non empty string. 5660 // Here we know the select attribute is a non empty string.
5082 select = select.trim(); 5661 select = select.trim();
5083 if (!select) 5662 if (!select)
5084 return true; 5663 return true;
5085 5664
5086 if (!(node instanceof Element)) 5665 if (!(node instanceof Element))
5087 return false; 5666 return false;
5088 5667
5668 // The native matches function in IE9 does not correctly work with elements
5669 // that are not in the document.
5670 // TODO(arv): Implement matching in JS.
5671 // https://github.com/Polymer/ShadowDOM/issues/361
5672 if (select === '*' || select === node.localName)
5673 return true;
5674
5089 // TODO(arv): This does not seem right. Need to check for a simple selector. 5675 // TODO(arv): This does not seem right. Need to check for a simple selector.
5090 if (!selectorMatchRegExp.test(select)) 5676 if (!selectorMatchRegExp.test(select))
5091 return false; 5677 return false;
5092 5678
5679 // TODO(arv): This no longer matches the spec.
5093 if (select[0] === ':' && !allowedPseudoRegExp.test(select)) 5680 if (select[0] === ':' && !allowedPseudoRegExp.test(select))
5094 return false; 5681 return false;
5095 5682
5096 try { 5683 try {
5097 return node.matches(select); 5684 return node.matches(select);
5098 } catch (ex) { 5685 } catch (ex) {
5099 // Invalid selector. 5686 // Invalid selector.
5100 return false; 5687 return false;
5101 } 5688 }
5102 } 5689 }
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after
5599 6186
5600 registerWrapper(window[name], GeneratedWrapper, 6187 registerWrapper(window[name], GeneratedWrapper,
5601 document.createElement(name.slice(4, -7))); 6188 document.createElement(name.slice(4, -7)));
5602 scope.wrappers[name] = GeneratedWrapper; 6189 scope.wrappers[name] = GeneratedWrapper;
5603 } 6190 }
5604 6191
5605 elementsWithFormProperty.forEach(createWrapperConstructor); 6192 elementsWithFormProperty.forEach(createWrapperConstructor);
5606 6193
5607 })(window.ShadowDOMPolyfill); 6194 })(window.ShadowDOMPolyfill);
5608 6195
6196 // Copyright 2014 The Polymer Authors. All rights reserved.
6197 // Use of this source code is goverened by a BSD-style
6198 // license that can be found in the LICENSE file.
6199
6200 (function(scope) {
6201 'use strict';
6202
6203 var registerWrapper = scope.registerWrapper;
6204 var unwrap = scope.unwrap;
6205 var unwrapIfNeeded = scope.unwrapIfNeeded;
6206 var wrap = scope.wrap;
6207
6208 var OriginalSelection = window.Selection;
6209
6210 function Selection(impl) {
6211 this.impl = impl;
6212 }
6213 Selection.prototype = {
6214 get anchorNode() {
6215 return wrap(this.impl.anchorNode);
6216 },
6217 get focusNode() {
6218 return wrap(this.impl.focusNode);
6219 },
6220 addRange: function(range) {
6221 this.impl.addRange(unwrap(range));
6222 },
6223 collapse: function(node, index) {
6224 this.impl.collapse(unwrapIfNeeded(node), index);
6225 },
6226 containsNode: function(node, allowPartial) {
6227 return this.impl.containsNode(unwrapIfNeeded(node), allowPartial);
6228 },
6229 extend: function(node, offset) {
6230 this.impl.extend(unwrapIfNeeded(node), offset);
6231 },
6232 getRangeAt: function(index) {
6233 return wrap(this.impl.getRangeAt(index));
6234 },
6235 removeRange: function(range) {
6236 this.impl.removeRange(unwrap(range));
6237 },
6238 selectAllChildren: function(node) {
6239 this.impl.selectAllChildren(unwrapIfNeeded(node));
6240 },
6241 toString: function() {
6242 return this.impl.toString();
6243 }
6244 };
6245
6246 // WebKit extensions. Not implemented.
6247 // readonly attribute Node baseNode;
6248 // readonly attribute long baseOffset;
6249 // readonly attribute Node extentNode;
6250 // readonly attribute long extentOffset;
6251 // [RaisesException] void setBaseAndExtent([Default=Undefined] optional Node b aseNode,
6252 // [Default=Undefined] optional long baseOffset,
6253 // [Default=Undefined] optional Node extentNode,
6254 // [Default=Undefined] optional long extentOffset);
6255 // [RaisesException, ImplementedAs=collapse] void setPosition([Default=Undefin ed] optional Node node,
6256 // [Default=Undefined] optional long offset);
6257
6258 registerWrapper(window.Selection, Selection, window.getSelection());
6259
6260 scope.wrappers.Selection = Selection;
6261
6262 })(window.ShadowDOMPolyfill);
6263
5609 // Copyright 2013 The Polymer Authors. All rights reserved. 6264 // Copyright 2013 The Polymer Authors. All rights reserved.
5610 // Use of this source code is goverened by a BSD-style 6265 // Use of this source code is goverened by a BSD-style
5611 // license that can be found in the LICENSE file. 6266 // license that can be found in the LICENSE file.
5612 6267
5613 (function(scope) { 6268 (function(scope) {
5614 'use strict'; 6269 'use strict';
5615 6270
5616 var GetElementsByInterface = scope.GetElementsByInterface; 6271 var GetElementsByInterface = scope.GetElementsByInterface;
5617 var Node = scope.wrappers.Node; 6272 var Node = scope.wrappers.Node;
5618 var ParentNodeInterface = scope.ParentNodeInterface; 6273 var ParentNodeInterface = scope.ParentNodeInterface;
6274 var Selection = scope.wrappers.Selection;
5619 var SelectorsInterface = scope.SelectorsInterface; 6275 var SelectorsInterface = scope.SelectorsInterface;
5620 var ShadowRoot = scope.wrappers.ShadowRoot; 6276 var ShadowRoot = scope.wrappers.ShadowRoot;
5621 var defineWrapGetter = scope.defineWrapGetter; 6277 var defineWrapGetter = scope.defineWrapGetter;
5622 var elementFromPoint = scope.elementFromPoint; 6278 var elementFromPoint = scope.elementFromPoint;
5623 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper; 6279 var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
5624 var matchesName = scope.matchesName; 6280 var matchesNames = scope.matchesNames;
5625 var mixin = scope.mixin; 6281 var mixin = scope.mixin;
5626 var registerWrapper = scope.registerWrapper; 6282 var registerWrapper = scope.registerWrapper;
6283 var renderAllPending = scope.renderAllPending;
6284 var rewrap = scope.rewrap;
5627 var unwrap = scope.unwrap; 6285 var unwrap = scope.unwrap;
5628 var wrap = scope.wrap; 6286 var wrap = scope.wrap;
5629 var wrapEventTargetMethods = scope.wrapEventTargetMethods; 6287 var wrapEventTargetMethods = scope.wrapEventTargetMethods;
5630 var wrapNodeList = scope.wrapNodeList; 6288 var wrapNodeList = scope.wrapNodeList;
5631 6289
5632 var implementationTable = new WeakMap(); 6290 var implementationTable = new WeakMap();
5633 6291
5634 function Document(node) { 6292 function Document(node) {
5635 Node.call(this, node); 6293 Node.call(this, node);
5636 } 6294 }
(...skipping 18 matching lines...) Expand all
5655 6313
5656 [ 6314 [
5657 'createComment', 6315 'createComment',
5658 'createDocumentFragment', 6316 'createDocumentFragment',
5659 'createElement', 6317 'createElement',
5660 'createElementNS', 6318 'createElementNS',
5661 'createEvent', 6319 'createEvent',
5662 'createEventNS', 6320 'createEventNS',
5663 'createRange', 6321 'createRange',
5664 'createTextNode', 6322 'createTextNode',
5665 'getElementById', 6323 'getElementById'
5666 ].forEach(wrapMethod); 6324 ].forEach(wrapMethod);
5667 6325
5668 var originalAdoptNode = document.adoptNode; 6326 var originalAdoptNode = document.adoptNode;
5669 6327
5670 function adoptNodeNoRemove(node, doc) { 6328 function adoptNodeNoRemove(node, doc) {
5671 originalAdoptNode.call(doc.impl, unwrap(node)); 6329 originalAdoptNode.call(doc.impl, unwrap(node));
5672 adoptSubtree(node, doc); 6330 adoptSubtree(node, doc);
5673 } 6331 }
5674 6332
5675 function adoptSubtree(node, doc) { 6333 function adoptSubtree(node, doc) {
5676 if (node.shadowRoot) 6334 if (node.shadowRoot)
5677 doc.adoptNode(node.shadowRoot); 6335 doc.adoptNode(node.shadowRoot);
5678 if (node instanceof ShadowRoot) 6336 if (node instanceof ShadowRoot)
5679 adoptOlderShadowRoots(node, doc); 6337 adoptOlderShadowRoots(node, doc);
5680 for (var child = node.firstChild; child; child = child.nextSibling) { 6338 for (var child = node.firstChild; child; child = child.nextSibling) {
5681 adoptSubtree(child, doc); 6339 adoptSubtree(child, doc);
5682 } 6340 }
5683 } 6341 }
5684 6342
5685 function adoptOlderShadowRoots(shadowRoot, doc) { 6343 function adoptOlderShadowRoots(shadowRoot, doc) {
5686 var oldShadowRoot = shadowRoot.olderShadowRoot; 6344 var oldShadowRoot = shadowRoot.olderShadowRoot;
5687 if (oldShadowRoot) 6345 if (oldShadowRoot)
5688 doc.adoptNode(oldShadowRoot); 6346 doc.adoptNode(oldShadowRoot);
5689 } 6347 }
5690 6348
5691 var originalImportNode = document.importNode; 6349 var originalImportNode = document.importNode;
6350 var originalGetSelection = document.getSelection;
5692 6351
5693 mixin(Document.prototype, { 6352 mixin(Document.prototype, {
5694 adoptNode: function(node) { 6353 adoptNode: function(node) {
5695 if (node.parentNode) 6354 if (node.parentNode)
5696 node.parentNode.removeChild(node); 6355 node.parentNode.removeChild(node);
5697 adoptNodeNoRemove(node, this); 6356 adoptNodeNoRemove(node, this);
5698 return node; 6357 return node;
5699 }, 6358 },
5700 elementFromPoint: function(x, y) { 6359 elementFromPoint: function(x, y) {
5701 return elementFromPoint(this, this, x, y); 6360 return elementFromPoint(this, this, x, y);
5702 }, 6361 },
5703 importNode: function(node, deep) { 6362 importNode: function(node, deep) {
5704 // We need to manually walk the tree to ensure we do not include rendered 6363 // We need to manually walk the tree to ensure we do not include rendered
5705 // shadow trees. 6364 // shadow trees.
5706 var clone = wrap(originalImportNode.call(this.impl, unwrap(node), false)); 6365 var clone = wrap(originalImportNode.call(this.impl, unwrap(node), false));
5707 if (deep) { 6366 if (deep) {
5708 for (var child = node.firstChild; child; child = child.nextSibling) { 6367 for (var child = node.firstChild; child; child = child.nextSibling) {
5709 clone.appendChild(this.importNode(child, true)); 6368 clone.appendChild(this.importNode(child, true));
5710 } 6369 }
5711 } 6370 }
5712 return clone; 6371 return clone;
6372 },
6373 getSelection: function() {
6374 renderAllPending();
6375 return new Selection(originalGetSelection.call(unwrap(this)));
5713 } 6376 }
5714 }); 6377 });
5715 6378
5716 if (document.register) { 6379 if (document.registerElement) {
5717 var originalRegister = document.register; 6380 var originalRegisterElement = document.registerElement;
5718 Document.prototype.register = function(tagName, object) { 6381 Document.prototype.registerElement = function(tagName, object) {
5719 var prototype = object.prototype; 6382 var prototype = object.prototype;
5720 6383
5721 // If we already used the object as a prototype for another custom 6384 // If we already used the object as a prototype for another custom
5722 // element. 6385 // element.
5723 if (scope.nativePrototypeTable.get(prototype)) { 6386 if (scope.nativePrototypeTable.get(prototype)) {
5724 // TODO(arv): DOMException 6387 // TODO(arv): DOMException
5725 throw new Error('NotSupportedError'); 6388 throw new Error('NotSupportedError');
5726 } 6389 }
5727 6390
5728 // Find first object on the prototype chain that already have a native 6391 // 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--) { 6415 for (var i = prototypes.length - 1; i >= 0; i--) {
5753 newPrototype = Object.create(newPrototype); 6416 newPrototype = Object.create(newPrototype);
5754 } 6417 }
5755 6418
5756 // Add callbacks if present. 6419 // Add callbacks if present.
5757 // Names are taken from: 6420 // 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 6421 // 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. 6422 // and not from the spec since the spec is out of date.
5760 [ 6423 [
5761 'createdCallback', 6424 'createdCallback',
5762 'enteredViewCallback', 6425 'attachedCallback',
5763 'leftViewCallback', 6426 'detachedCallback',
5764 'attributeChangedCallback', 6427 'attributeChangedCallback',
5765 ].forEach(function(name) { 6428 ].forEach(function(name) {
5766 var f = prototype[name]; 6429 var f = prototype[name];
5767 if (!f) 6430 if (!f)
5768 return; 6431 return;
5769 newPrototype[name] = function() { 6432 newPrototype[name] = function() {
6433 // if this element has been wrapped prior to registration,
6434 // the wrapper is stale; in this case rewrap
6435 if (!(wrap(this) instanceof CustomElementConstructor)) {
6436 rewrap(this);
6437 }
5770 f.apply(wrap(this), arguments); 6438 f.apply(wrap(this), arguments);
5771 }; 6439 };
5772 }); 6440 });
5773 6441
5774 var p = {prototype: newPrototype}; 6442 var p = {prototype: newPrototype};
5775 if (object.extends) 6443 if (object.extends)
5776 p.extends = object.extends; 6444 p.extends = object.extends;
5777 var nativeConstructor = originalRegister.call(unwrap(this), tagName, p);
5778 6445
5779 function GeneratedWrapper(node) { 6446 function CustomElementConstructor(node) {
5780 if (!node) { 6447 if (!node) {
5781 if (object.extends) { 6448 if (object.extends) {
5782 return document.createElement(object.extends, tagName); 6449 return document.createElement(object.extends, tagName);
5783 } else { 6450 } else {
5784 return document.createElement(tagName); 6451 return document.createElement(tagName);
5785 } 6452 }
5786 } 6453 }
5787 this.impl = node; 6454 this.impl = node;
5788 } 6455 }
5789 GeneratedWrapper.prototype = prototype; 6456 CustomElementConstructor.prototype = prototype;
5790 GeneratedWrapper.prototype.constructor = GeneratedWrapper; 6457 CustomElementConstructor.prototype.constructor = CustomElementConstructor;
5791 6458
5792 scope.constructorTable.set(newPrototype, GeneratedWrapper); 6459 scope.constructorTable.set(newPrototype, CustomElementConstructor);
5793 scope.nativePrototypeTable.set(prototype, newPrototype); 6460 scope.nativePrototypeTable.set(prototype, newPrototype);
5794 6461
5795 return GeneratedWrapper; 6462 // registration is synchronous so do it last
6463 var nativeConstructor = originalRegisterElement.call(unwrap(this),
6464 tagName, p);
6465 return CustomElementConstructor;
5796 }; 6466 };
5797 6467
5798 forwardMethodsToWrapper([ 6468 forwardMethodsToWrapper([
5799 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocume nt 6469 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocume nt
5800 ], [ 6470 ], [
5801 'register', 6471 'registerElement',
5802 ]); 6472 ]);
5803 } 6473 }
5804 6474
5805 // We also override some of the methods on document.body and document.head 6475 // We also override some of the methods on document.body and document.head
5806 // for convenience. 6476 // for convenience.
5807 forwardMethodsToWrapper([ 6477 forwardMethodsToWrapper([
5808 window.HTMLBodyElement, 6478 window.HTMLBodyElement,
5809 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument 6479 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
5810 window.HTMLHeadElement, 6480 window.HTMLHeadElement,
5811 window.HTMLHtmlElement, 6481 window.HTMLHtmlElement,
5812 ], [ 6482 ], [
5813 'appendChild', 6483 'appendChild',
5814 'compareDocumentPosition', 6484 'compareDocumentPosition',
5815 'contains', 6485 'contains',
5816 'getElementsByClassName', 6486 'getElementsByClassName',
5817 'getElementsByTagName', 6487 'getElementsByTagName',
5818 'getElementsByTagNameNS', 6488 'getElementsByTagNameNS',
5819 'insertBefore', 6489 'insertBefore',
5820 'querySelector', 6490 'querySelector',
5821 'querySelectorAll', 6491 'querySelectorAll',
5822 'removeChild', 6492 'removeChild',
5823 'replaceChild', 6493 'replaceChild',
5824 matchesName, 6494 ].concat(matchesNames));
5825 ]);
5826 6495
5827 forwardMethodsToWrapper([ 6496 forwardMethodsToWrapper([
5828 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument 6497 window.HTMLDocument || window.Document, // Gecko adds these to HTMLDocument
5829 ], [ 6498 ], [
5830 'adoptNode', 6499 'adoptNode',
5831 'importNode', 6500 'importNode',
5832 'contains', 6501 'contains',
5833 'createComment', 6502 'createComment',
5834 'createDocumentFragment', 6503 'createDocumentFragment',
5835 'createElement', 6504 'createElement',
5836 'createElementNS', 6505 'createElementNS',
5837 'createEvent', 6506 'createEvent',
5838 'createEventNS', 6507 'createEventNS',
5839 'createRange', 6508 'createRange',
5840 'createTextNode', 6509 'createTextNode',
5841 'elementFromPoint', 6510 'elementFromPoint',
5842 'getElementById', 6511 'getElementById',
6512 'getSelection',
5843 ]); 6513 ]);
5844 6514
5845 mixin(Document.prototype, GetElementsByInterface); 6515 mixin(Document.prototype, GetElementsByInterface);
5846 mixin(Document.prototype, ParentNodeInterface); 6516 mixin(Document.prototype, ParentNodeInterface);
5847 mixin(Document.prototype, SelectorsInterface); 6517 mixin(Document.prototype, SelectorsInterface);
5848 6518
5849 mixin(Document.prototype, { 6519 mixin(Document.prototype, {
5850 get implementation() { 6520 get implementation() {
5851 var implementation = implementationTable.get(this); 6521 var implementation = implementationTable.get(this);
5852 if (implementation) 6522 if (implementation)
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
5913 })(window.ShadowDOMPolyfill); 6583 })(window.ShadowDOMPolyfill);
5914 6584
5915 // Copyright 2013 The Polymer Authors. All rights reserved. 6585 // Copyright 2013 The Polymer Authors. All rights reserved.
5916 // Use of this source code is goverened by a BSD-style 6586 // Use of this source code is goverened by a BSD-style
5917 // license that can be found in the LICENSE file. 6587 // license that can be found in the LICENSE file.
5918 6588
5919 (function(scope) { 6589 (function(scope) {
5920 'use strict'; 6590 'use strict';
5921 6591
5922 var EventTarget = scope.wrappers.EventTarget; 6592 var EventTarget = scope.wrappers.EventTarget;
6593 var Selection = scope.wrappers.Selection;
5923 var mixin = scope.mixin; 6594 var mixin = scope.mixin;
5924 var registerWrapper = scope.registerWrapper; 6595 var registerWrapper = scope.registerWrapper;
6596 var renderAllPending = scope.renderAllPending;
5925 var unwrap = scope.unwrap; 6597 var unwrap = scope.unwrap;
5926 var unwrapIfNeeded = scope.unwrapIfNeeded; 6598 var unwrapIfNeeded = scope.unwrapIfNeeded;
5927 var wrap = scope.wrap; 6599 var wrap = scope.wrap;
5928 var renderAllPending = scope.renderAllPending;
5929 6600
5930 var OriginalWindow = window.Window; 6601 var OriginalWindow = window.Window;
6602 var originalGetComputedStyle = window.getComputedStyle;
6603 var originalGetSelection = window.getSelection;
5931 6604
5932 function Window(impl) { 6605 function Window(impl) {
5933 EventTarget.call(this, impl); 6606 EventTarget.call(this, impl);
5934 } 6607 }
5935 Window.prototype = Object.create(EventTarget.prototype); 6608 Window.prototype = Object.create(EventTarget.prototype);
5936 6609
5937 var originalGetComputedStyle = window.getComputedStyle;
5938 OriginalWindow.prototype.getComputedStyle = function(el, pseudo) { 6610 OriginalWindow.prototype.getComputedStyle = function(el, pseudo) {
5939 renderAllPending(); 6611 return wrap(this || window).getComputedStyle(unwrapIfNeeded(el), pseudo);
5940 return originalGetComputedStyle.call(this || window, unwrapIfNeeded(el),
5941 pseudo);
5942 }; 6612 };
5943 6613
6614 OriginalWindow.prototype.getSelection = function() {
6615 return wrap(this || window).getSelection();
6616 };
6617
6618 // Work around for https://bugzilla.mozilla.org/show_bug.cgi?id=943065
6619 delete window.getComputedStyle;
6620 delete window.getSelection;
6621
5944 ['addEventListener', 'removeEventListener', 'dispatchEvent'].forEach( 6622 ['addEventListener', 'removeEventListener', 'dispatchEvent'].forEach(
5945 function(name) { 6623 function(name) {
5946 OriginalWindow.prototype[name] = function() { 6624 OriginalWindow.prototype[name] = function() {
5947 var w = wrap(this || window); 6625 var w = wrap(this || window);
5948 return w[name].apply(w, arguments); 6626 return w[name].apply(w, arguments);
5949 }; 6627 };
6628
6629 // Work around for https://bugzilla.mozilla.org/show_bug.cgi?id=943065
6630 delete window[name];
5950 }); 6631 });
5951 6632
5952 mixin(Window.prototype, { 6633 mixin(Window.prototype, {
5953 getComputedStyle: function(el, pseudo) { 6634 getComputedStyle: function(el, pseudo) {
6635 renderAllPending();
5954 return originalGetComputedStyle.call(unwrap(this), unwrapIfNeeded(el), 6636 return originalGetComputedStyle.call(unwrap(this), unwrapIfNeeded(el),
5955 pseudo); 6637 pseudo);
5956 } 6638 },
6639 getSelection: function() {
6640 renderAllPending();
6641 return new Selection(originalGetSelection.call(unwrap(this)));
6642 },
5957 }); 6643 });
5958 6644
5959 registerWrapper(OriginalWindow, Window); 6645 registerWrapper(OriginalWindow, Window);
5960 6646
5961 scope.wrappers.Window = Window; 6647 scope.wrappers.Window = Window;
5962 6648
5963 })(window.ShadowDOMPolyfill); 6649 })(window.ShadowDOMPolyfill);
5964 6650
5965 // Copyright 2013 The Polymer Authors. All rights reserved. 6651 // Copyright 2013 The Polymer Authors. All rights reserved.
5966 // Use of this source code is goverened by a BSD-style 6652 // Use of this source code is goverened by a BSD-style
5967 // license that can be found in the LICENSE file. 6653 // license that can be found in the LICENSE file.
5968 6654
5969 (function(scope) { 6655 (function(scope) {
5970 'use strict'; 6656 'use strict';
5971 6657
5972 var isWrapperFor = scope.isWrapperFor; 6658 var isWrapperFor = scope.isWrapperFor;
5973 6659
5974 // This is a list of the elements we currently override the global constructor 6660 // This is a list of the elements we currently override the global constructor
5975 // for. 6661 // for.
5976 var elements = { 6662 var elements = {
5977 'a': 'HTMLAnchorElement', 6663 'a': 'HTMLAnchorElement',
5978 'applet': 'HTMLAppletElement', 6664
6665 // Do not create an applet element by default since it shows a warning in
6666 // IE.
6667 // https://github.com/Polymer/polymer/issues/217
6668 // 'applet': 'HTMLAppletElement',
6669
5979 'area': 'HTMLAreaElement', 6670 'area': 'HTMLAreaElement',
5980 'br': 'HTMLBRElement', 6671 'br': 'HTMLBRElement',
5981 'base': 'HTMLBaseElement', 6672 'base': 'HTMLBaseElement',
5982 'body': 'HTMLBodyElement', 6673 'body': 'HTMLBodyElement',
5983 'button': 'HTMLButtonElement', 6674 'button': 'HTMLButtonElement',
5984 // 'command': 'HTMLCommandElement', // Not fully implemented in Gecko. 6675 // 'command': 'HTMLCommandElement', // Not fully implemented in Gecko.
5985 'dl': 'HTMLDListElement', 6676 'dl': 'HTMLDListElement',
5986 'datalist': 'HTMLDataListElement', 6677 'datalist': 'HTMLDataListElement',
5987 'data': 'HTMLDataElement', 6678 'data': 'HTMLDataElement',
5988 'dir': 'HTMLDirectoryElement', 6679 'dir': 'HTMLDirectoryElement',
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
6076 // patch in prefixed name 6767 // patch in prefixed name
6077 Object.defineProperties(HTMLElement.prototype, { 6768 Object.defineProperties(HTMLElement.prototype, {
6078 //TODO(sjmiles): review accessor alias with Arv 6769 //TODO(sjmiles): review accessor alias with Arv
6079 webkitShadowRoot: { 6770 webkitShadowRoot: {
6080 get: function() { 6771 get: function() {
6081 return this.shadowRoot; 6772 return this.shadowRoot;
6082 } 6773 }
6083 } 6774 }
6084 }); 6775 });
6085 6776
6777 // ShadowCSS needs this:
6778 window.wrap = window.ShadowDOMPolyfill.wrap;
6779 window.unwrap = window.ShadowDOMPolyfill.unwrap;
6780
6086 //TODO(sjmiles): review method alias with Arv 6781 //TODO(sjmiles): review method alias with Arv
6087 HTMLElement.prototype.webkitCreateShadowRoot = 6782 HTMLElement.prototype.webkitCreateShadowRoot =
6088 HTMLElement.prototype.createShadowRoot; 6783 HTMLElement.prototype.createShadowRoot;
6089 6784
6090 // TODO(jmesserly): we need to wrap document somehow (a dart:html hook?) 6785 // TODO(jmesserly): we need to wrap document somehow (a dart:html hook?)
6091 window.dartExperimentalFixupGetTag = function(originalGetTag) { 6786 window.dartExperimentalFixupGetTag = function(originalGetTag) {
6092 var NodeList = ShadowDOMPolyfill.wrappers.NodeList; 6787 var NodeList = ShadowDOMPolyfill.wrappers.NodeList;
6093 var ShadowRoot = ShadowDOMPolyfill.wrappers.ShadowRoot; 6788 var ShadowRoot = ShadowDOMPolyfill.wrappers.ShadowRoot;
6094 var unwrapIfNeeded = ShadowDOMPolyfill.unwrapIfNeeded; 6789 var unwrapIfNeeded = ShadowDOMPolyfill.unwrapIfNeeded;
6095 function getTag(obj) { 6790 function getTag(obj) {
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
6283 <div class="content-container"> 6978 <div class="content-container">
6284 <content></content> 6979 <content></content>
6285 </div> 6980 </div>
6286 6981
6287 Note the use of @polyfill in the comment above a ShadowDOM specific style 6982 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 6983 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. 6984 in comments in lieu of the next selector when running under polyfill.
6290 */ 6985 */
6291 (function(scope) { 6986 (function(scope) {
6292 6987
6988 var loader = scope.loader;
6989
6293 var ShadowCSS = { 6990 var ShadowCSS = {
6294 strictStyling: false, 6991 strictStyling: false,
6295 registry: {}, 6992 registry: {},
6296 // Shim styles for a given root associated with a name and extendsName 6993 // Shim styles for a given root associated with a name and extendsName
6297 // 1. cache root styles by name 6994 // 1. cache root styles by name
6298 // 2. optionally tag root nodes with scope name 6995 // 2. optionally tag root nodes with scope name
6299 // 3. shim polyfill directives /* @polyfill */ and /* @polyfill-rule */ 6996 // 3. shim polyfill directives /* @polyfill */ and /* @polyfill-rule */
6300 // 4. shim @host and scoping 6997 // 4. shim @host and scoping
6301 shimStyling: function(root, name, extendsName) { 6998 shimStyling: function(root, name, extendsName) {
6302 var typeExtension = this.isTypeExtension(extendsName); 6999 var typeExtension = this.isTypeExtension(extendsName);
6303 // use caching to make working with styles nodes easier and to facilitate 7000 // use caching to make working with styles nodes easier and to facilitate
6304 // lookup of extendee 7001 // lookup of extendee
6305 var def = this.registerDefinition(root, name, extendsName); 7002 var def = this.registerDefinition(root, name, extendsName);
6306 // find styles and apply shimming... 7003 // find styles and apply shimming...
6307 if (this.strictStyling) { 7004 if (this.strictStyling) {
6308 this.applyScopeToContent(root, name); 7005 this.applyScopeToContent(root, name);
6309 } 7006 }
6310 // insert @polyfill and @polyfill-rule rules into style elements 7007 var cssText = this.stylesToShimmedCssText(def.rootStyles, def.scopeStyles,
6311 // scoping process takes care of shimming these 7008 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 7009 // provide shimmedStyle for user extensibility
6319 def.shimmedStyle = cssTextToStyle(cssText); 7010 def.shimmedStyle = cssTextToStyle(cssText);
6320 if (root) { 7011 if (root) {
6321 root.shimmedStyle = def.shimmedStyle; 7012 root.shimmedStyle = def.shimmedStyle;
6322 } 7013 }
6323 // remove existing style elements 7014 // remove existing style elements
6324 for (var i=0, l=def.rootStyles.length, s; (i<l) && (s=def.rootStyles[i]); 7015 for (var i=0, l=def.rootStyles.length, s; (i<l) && (s=def.rootStyles[i]);
6325 i++) { 7016 i++) {
6326 s.parentNode.removeChild(s); 7017 s.parentNode.removeChild(s);
6327 } 7018 }
6328 // add style to document 7019 // add style to document
6329 addCssToDocument(cssText); 7020 addCssToDocument(cssText);
6330 }, 7021 },
7022 // apply @polyfill rules + @host and scope shimming
7023 stylesToShimmedCssText: function(rootStyles, scopeStyles, name,
7024 typeExtension) {
7025 name = name || '';
7026 // insert @polyfill and @polyfill-rule rules into style elements
7027 // scoping process takes care of shimming these
7028 this.insertPolyfillDirectives(rootStyles);
7029 this.insertPolyfillRules(rootStyles);
7030 var cssText = this.shimAtHost(scopeStyles, name, typeExtension) +
7031 this.shimScoping(scopeStyles, name, typeExtension);
7032 // note: we only need to do rootStyles since these are unscoped.
7033 cssText += this.extractPolyfillUnscopedRules(rootStyles);
7034 return cssText;
7035 },
6331 registerDefinition: function(root, name, extendsName) { 7036 registerDefinition: function(root, name, extendsName) {
6332 var def = this.registry[name] = { 7037 var def = this.registry[name] = {
6333 root: root, 7038 root: root,
6334 name: name, 7039 name: name,
6335 extendsName: extendsName 7040 extendsName: extendsName
6336 } 7041 }
6337 var styles = root ? root.querySelectorAll('style') : []; 7042 var styles = root ? root.querySelectorAll('style') : [];
6338 styles = styles ? Array.prototype.slice.call(styles, 0) : []; 7043 styles = styles ? Array.prototype.slice.call(styles, 0) : [];
6339 def.rootStyles = styles; 7044 def.rootStyles = styles;
6340 def.scopeStyles = def.rootStyles; 7045 def.scopeStyles = def.rootStyles;
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
6439 } 7144 }
6440 return cssText; 7145 return cssText;
6441 }, 7146 },
6442 extractPolyfillUnscopedRulesFromCssText: function(cssText) { 7147 extractPolyfillUnscopedRulesFromCssText: function(cssText) {
6443 var r = '', matches; 7148 var r = '', matches;
6444 while (matches = cssPolyfillUnscopedRuleCommentRe.exec(cssText)) { 7149 while (matches = cssPolyfillUnscopedRuleCommentRe.exec(cssText)) {
6445 r += matches[1].slice(0, -1) + '\n\n'; 7150 r += matches[1].slice(0, -1) + '\n\n';
6446 } 7151 }
6447 return r; 7152 return r;
6448 }, 7153 },
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 } } 7154 // form: @host { .foo { declarations } }
6455 // becomes: scopeName.foo { declarations } 7155 // becomes: scopeName.foo { declarations }
6456 shimAtHost: function(styles, name, typeExtension) { 7156 shimAtHost: function(styles, name, typeExtension) {
6457 if (styles) { 7157 if (styles) {
6458 return this.convertAtHostStyles(styles, name, typeExtension); 7158 return this.convertAtHostStyles(styles, name, typeExtension);
6459 } 7159 }
6460 }, 7160 },
6461 convertAtHostStyles: function(styles, name, typeExtension) { 7161 convertAtHostStyles: function(styles, name, typeExtension) {
6462 var cssText = stylesToCssText(styles), self = this; 7162 var cssText = stylesToCssText(styles), self = this;
6463 cssText = cssText.replace(hostRuleRe, function(m, p1) { 7163 cssText = cssText.replace(hostRuleRe, function(m, p1) {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
6512 */ 7212 */
6513 shimScoping: function(styles, name, typeExtension) { 7213 shimScoping: function(styles, name, typeExtension) {
6514 if (styles) { 7214 if (styles) {
6515 return this.convertScopedStyles(styles, name, typeExtension); 7215 return this.convertScopedStyles(styles, name, typeExtension);
6516 } 7216 }
6517 }, 7217 },
6518 convertScopedStyles: function(styles, name, typeExtension) { 7218 convertScopedStyles: function(styles, name, typeExtension) {
6519 var cssText = stylesToCssText(styles).replace(hostRuleRe, ''); 7219 var cssText = stylesToCssText(styles).replace(hostRuleRe, '');
6520 cssText = this.insertPolyfillHostInCssText(cssText); 7220 cssText = this.insertPolyfillHostInCssText(cssText);
6521 cssText = this.convertColonHost(cssText); 7221 cssText = this.convertColonHost(cssText);
7222 cssText = this.convertColonAncestor(cssText);
7223 // TODO(sorvell): deprecated, remove
6522 cssText = this.convertPseudos(cssText); 7224 cssText = this.convertPseudos(cssText);
7225 // TODO(sorvell): deprecated, remove
6523 cssText = this.convertParts(cssText); 7226 cssText = this.convertParts(cssText);
6524 cssText = this.convertCombinators(cssText); 7227 cssText = this.convertCombinators(cssText);
6525 var rules = cssToRules(cssText); 7228 var rules = cssToRules(cssText);
6526 cssText = this.scopeRules(rules, name, typeExtension); 7229 if (name) {
7230 cssText = this.scopeRules(rules, name, typeExtension);
7231 }
6527 return cssText; 7232 return cssText;
6528 }, 7233 },
6529 convertPseudos: function(cssText) { 7234 convertPseudos: function(cssText) {
6530 return cssText.replace(cssPseudoRe, ' [pseudo=$1]'); 7235 return cssText.replace(cssPseudoRe, ' [pseudo=$1]');
6531 }, 7236 },
6532 convertParts: function(cssText) { 7237 convertParts: function(cssText) {
6533 return cssText.replace(cssPartRe, ' [part=$1]'); 7238 return cssText.replace(cssPartRe, ' [part=$1]');
6534 }, 7239 },
6535 /* 7240 /*
6536 * convert a rule like :host(.foo) > .bar { } 7241 * convert a rule like :host(.foo) > .bar { }
6537 * 7242 *
6538 * to 7243 * to
6539 * 7244 *
7245 * scopeName.foo > .bar
7246 */
7247 convertColonHost: function(cssText) {
7248 return this.convertColonRule(cssText, cssColonHostRe,
7249 this.colonHostPartReplacer);
7250 },
7251 /*
7252 * convert a rule like :ancestor(.foo) > .bar { }
7253 *
7254 * to
7255 *
6540 * scopeName.foo > .bar, .foo scopeName > .bar { } 7256 * scopeName.foo > .bar, .foo scopeName > .bar { }
6541 * 7257 *
6542 * and 7258 * and
6543 * 7259 *
6544 * :host(.foo:host) .bar { ... } 7260 * :ancestor(.foo:host) .bar { ... }
6545 * 7261 *
6546 * to 7262 * to
6547 * 7263 *
6548 * scopeName.foo .bar { ... } 7264 * scopeName.foo .bar { ... }
6549 */ 7265 */
6550 convertColonHost: function(cssText) { 7266 convertColonAncestor: function(cssText) {
7267 return this.convertColonRule(cssText, cssColonAncestorRe,
7268 this.colonAncestorPartReplacer);
7269 },
7270 convertColonRule: function(cssText, regExp, partReplacer) {
6551 // p1 = :host, p2 = contents of (), p3 rest of rule 7271 // p1 = :host, p2 = contents of (), p3 rest of rule
6552 return cssText.replace(cssColonHostRe, function(m, p1, p2, p3) { 7272 return cssText.replace(regExp, function(m, p1, p2, p3) {
6553 p1 = polyfillHostNoCombinator; 7273 p1 = polyfillHostNoCombinator;
6554 if (p2) { 7274 if (p2) {
6555 var parts = p2.split(','), r = []; 7275 var parts = p2.split(','), r = [];
6556 for (var i=0, l=parts.length, p; (i<l) && (p=parts[i]); i++) { 7276 for (var i=0, l=parts.length, p; (i<l) && (p=parts[i]); i++) {
6557 p = p.trim(); 7277 p = p.trim();
6558 if (p.match(polyfillHost)) { 7278 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 } 7279 }
6564 return r.join(','); 7280 return r.join(',');
6565 } else { 7281 } else {
6566 return p1 + p3; 7282 return p1 + p3;
6567 } 7283 }
6568 }); 7284 });
6569 }, 7285 },
7286 colonAncestorPartReplacer: function(host, part, suffix) {
7287 if (part.match(polyfillHost)) {
7288 return this.colonHostPartReplacer(host, part, suffix);
7289 } else {
7290 return host + part + suffix + ', ' + part + ' ' + host + suffix;
7291 }
7292 },
7293 colonHostPartReplacer: function(host, part, suffix) {
7294 return host + part.replace(polyfillHost, '') + suffix;
7295 },
6570 /* 7296 /*
6571 * Convert ^ and ^^ combinators by replacing with space. 7297 * Convert ^ and ^^ combinators by replacing with space.
6572 */ 7298 */
6573 convertCombinators: function(cssText) { 7299 convertCombinators: function(cssText) {
6574 return cssText.replace(/\^\^/g, ' ').replace(/\^/g, ' '); 7300 return cssText.replace(/\^\^/g, ' ').replace(/\^/g, ' ');
6575 }, 7301 },
6576 // change a selector like 'div' to 'name div' 7302 // change a selector like 'div' to 'name div'
6577 scopeRules: function(cssRules, name, typeExtension) { 7303 scopeRules: function(cssRules, name, typeExtension) {
6578 var cssText = ''; 7304 var cssText = '';
6579 Array.prototype.forEach.call(cssRules, function(rule) { 7305 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)) { 7362 if (t && (splits.indexOf(t) < 0) && (t.indexOf(attrName) < 0)) {
6637 p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3') 7363 p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3')
6638 } 7364 }
6639 return p; 7365 return p;
6640 }).join(sep); 7366 }).join(sep);
6641 }); 7367 });
6642 return scoped; 7368 return scoped;
6643 }, 7369 },
6644 insertPolyfillHostInCssText: function(selector) { 7370 insertPolyfillHostInCssText: function(selector) {
6645 return selector.replace(hostRe, polyfillHost).replace(colonHostRe, 7371 return selector.replace(hostRe, polyfillHost).replace(colonHostRe,
6646 polyfillHost); 7372 polyfillHost).replace(colonAncestorRe, polyfillAncestor);
6647 }, 7373 },
6648 propertiesFromRule: function(rule) { 7374 propertiesFromRule: function(rule) {
7375 // TODO(sorvell): Safari cssom incorrectly removes quotes from the content
7376 // property. (https://bugs.webkit.org/show_bug.cgi?id=118045)
7377 if (rule.style.content && !rule.style.content.match(/['"]+/)) {
7378 return rule.style.cssText.replace(/content:[^;]*;/g, 'content: \'' +
7379 rule.style.content + '\';');
7380 }
6649 return rule.style.cssText; 7381 return rule.style.cssText;
6650 } 7382 }
6651 }; 7383 };
6652 7384
6653 var hostRuleRe = /@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim, 7385 var hostRuleRe = /@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim,
6654 selectorRe = /([^{]*)({[\s\S]*?})/gim, 7386 selectorRe = /([^{]*)({[\s\S]*?})/gim,
6655 hostElementRe = /(.*)((?:\*)|(?:\:scope))(.*)/, 7387 hostElementRe = /(.*)((?:\*)|(?:\:scope))(.*)/,
6656 hostFixableRe = /^[.\[:]/, 7388 hostFixableRe = /^[.\[:]/,
6657 cssCommentRe = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim, 7389 cssCommentRe = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,
6658 cssPolyfillCommentRe = /\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*? ){/gim, 7390 cssPolyfillCommentRe = /\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*? ){/gim,
6659 cssPolyfillRuleCommentRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\/ /gim, 7391 cssPolyfillRuleCommentRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\/ /gim,
6660 cssPolyfillUnscopedRuleCommentRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([ ^/*][^*]*\*+)*)\//gim, 7392 cssPolyfillUnscopedRuleCommentRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([ ^/*][^*]*\*+)*)\//gim,
6661 cssPseudoRe = /::(x-[^\s{,(]*)/gim, 7393 cssPseudoRe = /::(x-[^\s{,(]*)/gim,
6662 cssPartRe = /::part\(([^)]*)\)/gim, 7394 cssPartRe = /::part\(([^)]*)\)/gim,
6663 // note: :host pre-processed to -shadowcsshost. 7395 // note: :host pre-processed to -shadowcsshost.
6664 polyfillHost = '-shadowcsshost', 7396 polyfillHost = '-shadowcsshost',
6665 cssColonHostRe = new RegExp('(' + polyfillHost + 7397 // note: :ancestor pre-processed to -shadowcssancestor.
6666 ')(?:\\((' + 7398 polyfillAncestor = '-shadowcssancestor',
7399 parenSuffix = ')(?:\\((' +
6667 '(?:\\([^)(]*\\)|[^)(]*)+?' + 7400 '(?:\\([^)(]*\\)|[^)(]*)+?' +
6668 ')\\))?([^,{]*)', 'gim'), 7401 ')\\))?([^,{]*)';
7402 cssColonHostRe = new RegExp('(' + polyfillHost + parenSuffix, 'gim'),
7403 cssColonAncestorRe = new RegExp('(' + polyfillAncestor + parenSuffix, 'gim') ,
6669 selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$', 7404 selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$',
6670 hostRe = /@host/gim, 7405 hostRe = /@host/gim,
6671 colonHostRe = /\:host/gim, 7406 colonHostRe = /\:host/gim,
7407 colonAncestorRe = /\:ancestor/gim,
6672 /* host name without combinator */ 7408 /* host name without combinator */
6673 polyfillHostNoCombinator = polyfillHost + '-no-combinator', 7409 polyfillHostNoCombinator = polyfillHost + '-no-combinator',
6674 polyfillHostRe = new RegExp(polyfillHost, 'gim'); 7410 polyfillHostRe = new RegExp(polyfillHost, 'gim');
7411 polyfillAncestorRe = new RegExp(polyfillAncestor, 'gim');
6675 7412
6676 function stylesToCssText(styles, preserveComments) { 7413 function stylesToCssText(styles, preserveComments) {
6677 var cssText = ''; 7414 var cssText = '';
6678 Array.prototype.forEach.call(styles, function(s) { 7415 Array.prototype.forEach.call(styles, function(s) {
6679 cssText += s.textContent + '\n\n'; 7416 cssText += s.textContent + '\n\n';
6680 }); 7417 });
6681 // strip comments for easier processing 7418 // strip comments for easier processing
6682 if (!preserveComments) { 7419 if (!preserveComments) {
6683 cssText = cssText.replace(cssCommentRe, ''); 7420 cssText = cssText.replace(cssCommentRe, '');
6684 } 7421 }
(...skipping 25 matching lines...) Expand all
6710 if (cssText) { 7447 if (cssText) {
6711 getSheet().appendChild(document.createTextNode(cssText)); 7448 getSheet().appendChild(document.createTextNode(cssText));
6712 } 7449 }
6713 } 7450 }
6714 7451
6715 var sheet; 7452 var sheet;
6716 function getSheet() { 7453 function getSheet() {
6717 if (!sheet) { 7454 if (!sheet) {
6718 sheet = document.createElement("style"); 7455 sheet = document.createElement("style");
6719 sheet.setAttribute('ShadowCSSShim', ''); 7456 sheet.setAttribute('ShadowCSSShim', '');
7457 sheet.shadowCssShim = true;
6720 } 7458 }
6721 return sheet; 7459 return sheet;
6722 } 7460 }
6723 7461
6724 // add polyfill stylesheet to document 7462 // add polyfill stylesheet to document
6725 if (window.ShadowDOMPolyfill) { 7463 if (window.ShadowDOMPolyfill) {
6726 addCssToDocument('style { display: none !important; }\n'); 7464 addCssToDocument('style { display: none !important; }\n');
6727 var head = document.querySelector('head'); 7465 var doc = wrap(document);
7466 var head = doc.querySelector('head');
6728 head.insertBefore(getSheet(), head.childNodes[0]); 7467 head.insertBefore(getSheet(), head.childNodes[0]);
7468
7469 document.addEventListener('DOMContentLoaded', function() {
7470 if (window.HTMLImports && !HTMLImports.useNative) {
7471 HTMLImports.importer.preloadSelectors +=
7472 ', link[rel=stylesheet]:not([nopolyfill])';
7473 HTMLImports.parser.parseGeneric = function(elt) {
7474 if (elt.shadowCssShim) {
7475 return;
7476 }
7477 var style = elt;
7478 if (!elt.hasAttribute('nopolyfill')) {
7479 if (elt.__resource) {
7480 style = elt.ownerDocument.createElement('style');
7481 style.textContent = Platform.loader.resolveUrlsInCssText(
7482 elt.__resource, elt.href);
7483 // remove links from main document
7484 if (elt.ownerDocument === doc) {
7485 elt.parentNode.removeChild(elt);
7486 }
7487 } else {
7488 Platform.loader.resolveUrlsInStyle(style);
7489 }
7490 var styles = [style];
7491 style.textContent = ShadowCSS.stylesToShimmedCssText(styles, styles);
7492 style.shadowCssShim = true;
7493 }
7494 // place in document
7495 if (style.parentNode !== head) {
7496 head.appendChild(style);
7497 }
7498 }
7499 }
7500 });
6729 } 7501 }
6730 7502
6731 // exports 7503 // exports
6732 scope.ShadowCSS = ShadowCSS; 7504 scope.ShadowCSS = ShadowCSS;
6733 7505
6734 })(window.Platform); 7506 })(window.Platform);
6735 } 7507 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698