fabric-pure-browser
Version:
Fabric.js package with no node-specific dependencies (node-canvas, jsdom). The project is published once a day (in case if a new version appears) from 'master' branch of https://github.com/fabricjs/fabric.js repository. You can keep original imports in
322 lines (287 loc) • 9.71 kB
JavaScript
(function() {
var _slice = Array.prototype.slice;
/**
* Takes id and returns an element with that id (if one exists in a document)
* @memberOf fabric.util
* @param {String|HTMLElement} id
* @return {HTMLElement|null}
*/
function getById(id) {
return typeof id === 'string' ? fabric.document.getElementById(id) : id;
}
var sliceCanConvertNodelists,
/**
* Converts an array-like object (e.g. arguments or NodeList) to an array
* @memberOf fabric.util
* @param {Object} arrayLike
* @return {Array}
*/
toArray = function(arrayLike) {
return _slice.call(arrayLike, 0);
};
try {
sliceCanConvertNodelists = toArray(fabric.document.childNodes) instanceof Array;
}
catch (err) { }
if (!sliceCanConvertNodelists) {
toArray = function(arrayLike) {
var arr = new Array(arrayLike.length), i = arrayLike.length;
while (i--) {
arr[i] = arrayLike[i];
}
return arr;
};
}
/**
* Creates specified element with specified attributes
* @memberOf fabric.util
* @param {String} tagName Type of an element to create
* @param {Object} [attributes] Attributes to set on an element
* @return {HTMLElement} Newly created element
*/
function makeElement(tagName, attributes) {
var el = fabric.document.createElement(tagName);
for (var prop in attributes) {
if (prop === 'class') {
el.className = attributes[prop];
}
else if (prop === 'for') {
el.htmlFor = attributes[prop];
}
else {
el.setAttribute(prop, attributes[prop]);
}
}
return el;
}
/**
* Adds class to an element
* @memberOf fabric.util
* @param {HTMLElement} element Element to add class to
* @param {String} className Class to add to an element
*/
function addClass(element, className) {
if (element && (' ' + element.className + ' ').indexOf(' ' + className + ' ') === -1) {
element.className += (element.className ? ' ' : '') + className;
}
}
/**
* Wraps element with another element
* @memberOf fabric.util
* @param {HTMLElement} element Element to wrap
* @param {HTMLElement|String} wrapper Element to wrap with
* @param {Object} [attributes] Attributes to set on a wrapper
* @return {HTMLElement} wrapper
*/
function wrapElement(element, wrapper, attributes) {
if (typeof wrapper === 'string') {
wrapper = makeElement(wrapper, attributes);
}
if (element.parentNode) {
element.parentNode.replaceChild(wrapper, element);
}
wrapper.appendChild(element);
return wrapper;
}
/**
* Returns element scroll offsets
* @memberOf fabric.util
* @param {HTMLElement} element Element to operate on
* @return {Object} Object with left/top values
*/
function getScrollLeftTop(element) {
var left = 0,
top = 0,
docElement = fabric.document.documentElement,
body = fabric.document.body || {
scrollLeft: 0, scrollTop: 0
};
// While loop checks (and then sets element to) .parentNode OR .host
// to account for ShadowDOM. We still want to traverse up out of ShadowDOM,
// but the .parentNode of a root ShadowDOM node will always be null, instead
// it should be accessed through .host. See http://stackoverflow.com/a/24765528/4383938
while (element && (element.parentNode || element.host)) {
// Set element to element parent, or 'host' in case of ShadowDOM
element = element.parentNode || element.host;
if (element === fabric.document) {
left = body.scrollLeft || docElement.scrollLeft || 0;
top = body.scrollTop || docElement.scrollTop || 0;
}
else {
left += element.scrollLeft || 0;
top += element.scrollTop || 0;
}
if (element.nodeType === 1 && element.style.position === 'fixed') {
break;
}
}
return { left: left, top: top };
}
/**
* Returns offset for a given element
* @function
* @memberOf fabric.util
* @param {HTMLElement} element Element to get offset for
* @return {Object} Object with "left" and "top" properties
*/
function getElementOffset(element) {
var docElem,
doc = element && element.ownerDocument,
box = { left: 0, top: 0 },
offset = { left: 0, top: 0 },
scrollLeftTop,
offsetAttributes = {
borderLeftWidth: 'left',
borderTopWidth: 'top',
paddingLeft: 'left',
paddingTop: 'top'
};
if (!doc) {
return offset;
}
for (var attr in offsetAttributes) {
offset[offsetAttributes[attr]] += parseInt(getElementStyle(element, attr), 10) || 0;
}
docElem = doc.documentElement;
if ( typeof element.getBoundingClientRect !== 'undefined' ) {
box = element.getBoundingClientRect();
}
scrollLeftTop = getScrollLeftTop(element);
return {
left: box.left + scrollLeftTop.left - (docElem.clientLeft || 0) + offset.left,
top: box.top + scrollLeftTop.top - (docElem.clientTop || 0) + offset.top
};
}
/**
* Returns style attribute value of a given element
* @memberOf fabric.util
* @param {HTMLElement} element Element to get style attribute for
* @param {String} attr Style attribute to get for element
* @return {String} Style attribute value of the given element.
*/
var getElementStyle;
if (fabric.document.defaultView && fabric.document.defaultView.getComputedStyle) {
getElementStyle = function(element, attr) {
var style = fabric.document.defaultView.getComputedStyle(element, null);
return style ? style[attr] : undefined;
};
}
else {
getElementStyle = function(element, attr) {
var value = element.style[attr];
if (!value && element.currentStyle) {
value = element.currentStyle[attr];
}
return value;
};
}
(function () {
var style = fabric.document.documentElement.style,
selectProp = 'userSelect' in style
? 'userSelect'
: 'MozUserSelect' in style
? 'MozUserSelect'
: 'WebkitUserSelect' in style
? 'WebkitUserSelect'
: 'KhtmlUserSelect' in style
? 'KhtmlUserSelect'
: '';
/**
* Makes element unselectable
* @memberOf fabric.util
* @param {HTMLElement} element Element to make unselectable
* @return {HTMLElement} Element that was passed in
*/
function makeElementUnselectable(element) {
if (typeof element.onselectstart !== 'undefined') {
element.onselectstart = fabric.util.falseFunction;
}
if (selectProp) {
element.style[selectProp] = 'none';
}
else if (typeof element.unselectable === 'string') {
element.unselectable = 'on';
}
return element;
}
/**
* Makes element selectable
* @memberOf fabric.util
* @param {HTMLElement} element Element to make selectable
* @return {HTMLElement} Element that was passed in
*/
function makeElementSelectable(element) {
if (typeof element.onselectstart !== 'undefined') {
element.onselectstart = null;
}
if (selectProp) {
element.style[selectProp] = '';
}
else if (typeof element.unselectable === 'string') {
element.unselectable = '';
}
return element;
}
fabric.util.makeElementUnselectable = makeElementUnselectable;
fabric.util.makeElementSelectable = makeElementSelectable;
})();
(function() {
/**
* Inserts a script element with a given url into a document; invokes callback, when that script is finished loading
* @memberOf fabric.util
* @param {String} url URL of a script to load
* @param {Function} callback Callback to execute when script is finished loading
*/
function getScript(url, callback) {
var headEl = fabric.document.getElementsByTagName('head')[0],
scriptEl = fabric.document.createElement('script'),
loading = true;
/** @ignore */
scriptEl.onload = /** @ignore */ scriptEl.onreadystatechange = function(e) {
if (loading) {
if (typeof this.readyState === 'string' &&
this.readyState !== 'loaded' &&
this.readyState !== 'complete') {
return;
}
loading = false;
callback(e || fabric.window.event);
scriptEl = scriptEl.onload = scriptEl.onreadystatechange = null;
}
};
scriptEl.src = url;
headEl.appendChild(scriptEl);
// causes issue in Opera
// headEl.removeChild(scriptEl);
}
fabric.util.getScript = getScript;
})();
function getNodeCanvas(element) {
var impl = fabric.jsdomImplForWrapper(element);
return impl._canvas || impl._image;
};
function cleanUpJsdomNode(element) {
if (!fabric.isLikelyNode) {
return;
}
var impl = fabric.jsdomImplForWrapper(element);
if (impl) {
impl._image = null;
impl._canvas = null;
// unsure if necessary
impl._currentSrc = null;
impl._attributes = null;
impl._classList = null;
}
}
fabric.util.getById = getById;
fabric.util.toArray = toArray;
fabric.util.makeElement = makeElement;
fabric.util.addClass = addClass;
fabric.util.wrapElement = wrapElement;
fabric.util.getScrollLeftTop = getScrollLeftTop;
fabric.util.getElementOffset = getElementOffset;
fabric.util.getElementStyle = getElementStyle;
fabric.util.getNodeCanvas = getNodeCanvas;
fabric.util.cleanUpJsdomNode = cleanUpJsdomNode;
})();