aurelia-pal-browser
Version:
The browser-specific implementation of Aurelia's platform abstraction layer.
561 lines (470 loc) • 15.3 kB
JavaScript
import { initializePAL, isInitialized } from 'aurelia-pal';
export const _PLATFORM = {
location: window.location,
history: window.history,
addEventListener(eventName, callback, capture) {
this.global.addEventListener(eventName, callback, capture);
},
removeEventListener(eventName, callback, capture) {
this.global.removeEventListener(eventName, callback, capture);
},
performance: window.performance,
requestAnimationFrame(callback) {
return this.global.requestAnimationFrame(callback);
}
};
if (typeof FEATURE_NO_IE === 'undefined') {
function test() {}
if (test.name === undefined) {
Object.defineProperty(Function.prototype, 'name', {
get: function () {
let name = this.toString().match(/^\s*function\s*(\S*)\s*\(/)[1];
Object.defineProperty(this, 'name', { value: name });
return name;
}
});
}
}
if (typeof FEATURE_NO_IE === 'undefined') {
if (!('classList' in document.createElement('_')) || document.createElementNS && !('classList' in document.createElementNS('http://www.w3.org/2000/svg', 'g'))) {
let protoProp = 'prototype';
let strTrim = String.prototype.trim;
let arrIndexOf = Array.prototype.indexOf;
let emptyArray = [];
let DOMEx = function (type, message) {
this.name = type;
this.code = DOMException[type];
this.message = message;
};
let checkTokenAndGetIndex = function (classList, token) {
if (token === '') {
throw new DOMEx('SYNTAX_ERR', 'An invalid or illegal string was specified');
}
if (/\s/.test(token)) {
throw new DOMEx('INVALID_CHARACTER_ERR', 'String contains an invalid character');
}
return arrIndexOf.call(classList, token);
};
let ClassList = function (elem) {
let trimmedClasses = strTrim.call(elem.getAttribute('class') || '');
let classes = trimmedClasses ? trimmedClasses.split(/\s+/) : emptyArray;
for (let i = 0, ii = classes.length; i < ii; ++i) {
this.push(classes[i]);
}
this._updateClassName = function () {
elem.setAttribute('class', this.toString());
};
};
let classListProto = ClassList[protoProp] = [];
DOMEx[protoProp] = Error[protoProp];
classListProto.item = function (i) {
return this[i] || null;
};
classListProto.contains = function (token) {
token += '';
return checkTokenAndGetIndex(this, token) !== -1;
};
classListProto.add = function () {
let tokens = arguments;
let i = 0;
let ii = tokens.length;
let token;
let updated = false;
do {
token = tokens[i] + '';
if (checkTokenAndGetIndex(this, token) === -1) {
this.push(token);
updated = true;
}
} while (++i < ii);
if (updated) {
this._updateClassName();
}
};
classListProto.remove = function () {
let tokens = arguments;
let i = 0;
let ii = tokens.length;
let token;
let updated = false;
let index;
do {
token = tokens[i] + '';
index = checkTokenAndGetIndex(this, token);
while (index !== -1) {
this.splice(index, 1);
updated = true;
index = checkTokenAndGetIndex(this, token);
}
} while (++i < ii);
if (updated) {
this._updateClassName();
}
};
classListProto.toggle = function (token, force) {
token += '';
let result = this.contains(token);
let method = result ? force !== true && 'remove' : force !== false && 'add';
if (method) {
this[method](token);
}
if (force === true || force === false) {
return force;
}
return !result;
};
classListProto.toString = function () {
return this.join(' ');
};
Object.defineProperty(Element.prototype, 'classList', {
get: function () {
return new ClassList(this);
},
enumerable: true,
configurable: true
});
} else {
let testElement = document.createElement('_');
testElement.classList.add('c1', 'c2');
if (!testElement.classList.contains('c2')) {
let createMethod = function (method) {
let original = DOMTokenList.prototype[method];
DOMTokenList.prototype[method] = function (token) {
for (let i = 0, ii = arguments.length; i < ii; ++i) {
token = arguments[i];
original.call(this, token);
}
};
};
createMethod('add');
createMethod('remove');
}
testElement.classList.toggle('c3', false);
if (testElement.classList.contains('c3')) {
let _toggle = DOMTokenList.prototype.toggle;
DOMTokenList.prototype.toggle = function (token, force) {
if (1 in arguments && !this.contains(token) === !force) {
return force;
}
return _toggle.call(this, token);
};
}
testElement = null;
}
}
if (typeof FEATURE_NO_IE === 'undefined') {
// @license http://opensource.org/licenses/MIT
if ('performance' in window === false) {
window.performance = {};
}
if ('now' in window.performance === false) {
let nowOffset = Date.now();
if (performance.timing && performance.timing.navigationStart) {
nowOffset = performance.timing.navigationStart;
}
window.performance.now = function now() {
return Date.now() - nowOffset;
};
}
const startOffset = Date.now ? Date.now() : +new Date();
const _entries = [];
const _marksIndex = {};
function _filterEntries(key, value) {
var i = 0,
n = _entries.length,
result = [];
for (; i < n; i++) {
if (_entries[i][key] == value) {
result.push(_entries[i]);
}
}
return result;
}
function _clearEntries(type, name) {
var i = _entries.length,
entry;
while (i--) {
entry = _entries[i];
if (entry.entryType == type && (name === void 0 || entry.name == name)) {
_entries.splice(i, 1);
}
}
};
if (!window.performance.mark) {
window.performance.mark = window.performance.webkitMark || function (name) {
const mark = {
name,
entryType: "mark",
startTime: window.performance.now(),
duration: 0
};
_entries.push(mark);
_marksIndex[name] = mark;
};
}
if (!window.performance.measure) {
window.performance.measure = window.performance.webkitMeasure || function (name, startMark, endMark) {
startMark = _marksIndex[startMark].startTime;
endMark = _marksIndex[endMark].startTime;
_entries.push({
name,
entryType: "measure",
startTime: startMark,
duration: endMark - startMark
});
};
}
if (!window.performance.getEntriesByType) {
window.performance.getEntriesByType = window.performance.webkitGetEntriesByType || function (type) {
return _filterEntries("entryType", type);
};
}
if (!window.performance.getEntriesByName) {
window.performance.getEntriesByName = window.performance.webkitGetEntriesByName || function (name) {
return _filterEntries("name", name);
};
}
if (!window.performance.clearMarks) {
window.performance.clearMarks = window.performance.webkitClearMarks || function (name) {
_clearEntries("mark", name);
};
}
if (!window.performance.clearMeasures) {
window.performance.clearMeasures = window.performance.webkitClearMeasures || function (name) {
_clearEntries("measure", name);
};
}
_PLATFORM.performance = window.performance;
}
if (typeof FEATURE_NO_IE === 'undefined') {
let con = window.console = window.console || {};
let nop = function () {};
if (!con.memory) con.memory = {};
('assert,clear,count,debug,dir,dirxml,error,exception,group,' + 'groupCollapsed,groupEnd,info,log,markTimeline,profile,profiles,profileEnd,' + 'show,table,time,timeEnd,timeline,timelineEnd,timeStamp,trace,warn').split(',').forEach(m => {
if (!con[m]) con[m] = nop;
});
if (typeof con.log === 'object') {
'log,info,warn,error,assert,dir,clear,profile,profileEnd'.split(',').forEach(function (method) {
console[method] = this.bind(console[method], console);
}, Function.prototype.call);
}
}
if (typeof FEATURE_NO_IE === 'undefined') {
if (!window.CustomEvent || typeof window.CustomEvent !== 'function') {
let CustomEvent = function (event, params) {
params = params || {
bubbles: false,
cancelable: false,
detail: undefined
};
let evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
};
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent = CustomEvent;
}
}
if (Element && !Element.prototype.matches) {
let proto = Element.prototype;
proto.matches = proto.matchesSelector || proto.mozMatchesSelector || proto.msMatchesSelector || proto.oMatchesSelector || proto.webkitMatchesSelector;
}
export const _FEATURE = {
shadowDOM: !!HTMLElement.prototype.attachShadow,
scopedCSS: 'scoped' in document.createElement('style'),
htmlTemplateElement: function () {
let d = document.createElement('div');
d.innerHTML = '<template></template>';
return 'content' in d.children[0];
}(),
mutationObserver: !!(window.MutationObserver || window.WebKitMutationObserver),
ensureHTMLTemplateElement: t => t
};
if (typeof FEATURE_NO_IE === 'undefined') {
function isSVGTemplate(el) {
return el.tagName === 'template' && el.namespaceURI === 'http://www.w3.org/2000/svg';
}
function fixSVGTemplateElement(el) {
let template = el.ownerDocument.createElement('template');
let attrs = el.attributes;
let length = attrs.length;
let attr;
el.parentNode.insertBefore(template, el);
while (length-- > 0) {
attr = attrs[length];
template.setAttribute(attr.name, attr.value);
el.removeAttribute(attr.name);
}
el.parentNode.removeChild(el);
return fixHTMLTemplateElement(template);
}
function fixHTMLTemplateElement(template) {
let content = template.content = document.createDocumentFragment();
let child;
while (child = template.firstChild) {
content.appendChild(child);
}
return template;
}
function fixHTMLTemplateElementRoot(template) {
let content = fixHTMLTemplateElement(template).content;
let childTemplates = content.querySelectorAll('template');
for (let i = 0, ii = childTemplates.length; i < ii; ++i) {
let child = childTemplates[i];
if (isSVGTemplate(child)) {
fixSVGTemplateElement(child);
} else {
fixHTMLTemplateElement(child);
}
}
return template;
}
if (!_FEATURE.htmlTemplateElement) {
_FEATURE.ensureHTMLTemplateElement = fixHTMLTemplateElementRoot;
}
}
let shadowPoly = window.ShadowDOMPolyfill || null;
export const _DOM = {
Element: Element,
NodeList: NodeList,
SVGElement: SVGElement,
boundary: 'aurelia-dom-boundary',
addEventListener(eventName, callback, capture) {
document.addEventListener(eventName, callback, capture);
},
removeEventListener(eventName, callback, capture) {
document.removeEventListener(eventName, callback, capture);
},
adoptNode(node) {
return document.adoptNode(node);
},
createAttribute(name) {
return document.createAttribute(name);
},
createElement(tagName) {
return document.createElement(tagName);
},
createTextNode(text) {
return document.createTextNode(text);
},
createComment(text) {
return document.createComment(text);
},
createDocumentFragment() {
return document.createDocumentFragment();
},
createTemplateElement() {
let template = document.createElement('template');
return _FEATURE.ensureHTMLTemplateElement(template);
},
createMutationObserver(callback) {
return new (window.MutationObserver || window.WebKitMutationObserver)(callback);
},
createCustomEvent(eventType, options) {
return new window.CustomEvent(eventType, options);
},
dispatchEvent(evt) {
document.dispatchEvent(evt);
},
getComputedStyle(element) {
return window.getComputedStyle(element);
},
getElementById(id) {
return document.getElementById(id);
},
querySelector(query) {
return document.querySelector(query);
},
querySelectorAll(query) {
return document.querySelectorAll(query);
},
nextElementSibling(element) {
if (element.nextElementSibling) {
return element.nextElementSibling;
}
do {
element = element.nextSibling;
} while (element && element.nodeType !== 1);
return element;
},
createTemplateFromMarkup(markup) {
let parser = document.createElement('div');
parser.innerHTML = markup;
let temp = parser.firstElementChild;
if (!temp || temp.nodeName !== 'TEMPLATE') {
throw new Error('Template markup must be wrapped in a <template> element e.g. <template> <!-- markup here --> </template>');
}
return _FEATURE.ensureHTMLTemplateElement(temp);
},
appendNode(newNode, parentNode) {
(parentNode || document.body).appendChild(newNode);
},
replaceNode(newNode, node, parentNode) {
if (node.parentNode) {
node.parentNode.replaceChild(newNode, node);
} else if (shadowPoly !== null) {
shadowPoly.unwrap(parentNode).replaceChild(shadowPoly.unwrap(newNode), shadowPoly.unwrap(node));
} else {
parentNode.replaceChild(newNode, node);
}
},
removeNode(node, parentNode) {
if (node.parentNode) {
node.parentNode.removeChild(node);
} else if (parentNode) {
if (shadowPoly !== null) {
shadowPoly.unwrap(parentNode).removeChild(shadowPoly.unwrap(node));
} else {
parentNode.removeChild(node);
}
}
},
injectStyles(styles, destination, prepend, id) {
if (id) {
let oldStyle = document.getElementById(id);
if (oldStyle) {
let isStyleTag = oldStyle.tagName.toLowerCase() === 'style';
if (isStyleTag) {
oldStyle.innerHTML = styles;
return;
}
throw new Error('The provided id does not indicate a style tag.');
}
}
let node = document.createElement('style');
node.innerHTML = styles;
node.type = 'text/css';
if (id) {
node.id = id;
}
destination = destination || document.head;
if (prepend && destination.childNodes.length > 0) {
destination.insertBefore(node, destination.childNodes[0]);
} else {
destination.appendChild(node);
}
return node;
}
};
export function initialize() {
if (isInitialized) {
return;
}
initializePAL((platform, feature, dom) => {
Object.assign(platform, _PLATFORM);
Object.assign(feature, _FEATURE);
Object.assign(dom, _DOM);
Object.defineProperty(dom, 'title', {
get: () => document.title,
set: value => {
document.title = value;
}
});
Object.defineProperty(dom, 'activeElement', {
get: () => document.activeElement
});
Object.defineProperty(platform, 'XMLHttpRequest', {
get: () => platform.global.XMLHttpRequest
});
});
}