/* * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * http://paperjs.org/ * * Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey * http://lehni.org/ & http://jonathanpuckey.com/ * * Distributed under the MIT license. See LICENSE file for details. * * All rights reserved. */ /** * @name DomElement * @namespace * @private */ var DomElement = new function() { // We use a mix of Bootstrap.js legacy and Bonzo.js magic, ported over and // furhter simplified to a subset actually required by Paper.js var special = /^(checked|value|selected|disabled)$/i, translated = { text: 'textContent', html: 'innerHTML' }, unitless = { lineHeight: 1, zoom: 1, zIndex: 1, opacity: 1 }; function create(nodes, parent) { var res = []; for (var i = 0, l = nodes && nodes.length; i < l;) { var el = nodes[i++]; if (typeof el === 'string') { el = document.createElement(el); } else if (!el || !el.nodeType) { continue; } // Do we have attributes? if (Base.isPlainObject(nodes[i])) DomElement.set(el, nodes[i++]); // Do we have children? if (Array.isArray(nodes[i])) create(nodes[i++], el); // Are we adding to a parent? if (parent) parent.appendChild(el); res.push(el); } return res; } return /** @lends DomElement */{ create: function(nodes, parent) { var isArray = Array.isArray(nodes), res = create(isArray ? nodes : arguments, isArray ? parent : null); return res.length == 1 ? res[0] : res; }, find: function(selector, root) { return (root || document).querySelector(selector); }, findAll: function(selector, root) { return (root || document).querySelectorAll(selector); }, get: function(el, key) { return el ? special.test(key) ? key === 'value' || typeof el[key] !== 'string' ? el[key] : true : key in translated ? el[translated[key]] : el.getAttribute(key) : null; }, set: function(el, key, value) { if (typeof key !== 'string') { for (var name in key) if (key.hasOwnProperty(name)) this.set(el, name, key[name]); } else if (!el || value === undefined) { return el; } else if (special.test(key)) { el[key] = value; } else if (key in translated) { el[translated[key]] = value; } else if (key === 'style') { this.setStyle(el, value); } else if (key === 'events') { DomEvent.add(el, value); } else { el.setAttribute(key, value); } return el; }, getStyles: function(el) { // If el is a document (nodeType == 9), use it directly var doc = el && el.nodeType !== 9 ? el.ownerDocument : el, view = doc && doc.defaultView; return view && view.getComputedStyle(el, ''); }, getStyle: function(el, key) { return el && el.style[key] || this.getStyles(el)[key] || null; }, setStyle: function(el, key, value) { if (typeof key !== 'string') { for (var name in key) if (key.hasOwnProperty(name)) this.setStyle(el, name, key[name]); } else { if (/^-?[\d\.]+$/.test(value) && !(key in unitless)) value += 'px'; el.style[key] = value; } return el; }, hasClass: function(el, cls) { return new RegExp('\\s*' + cls + '\\s*').test(el.className); }, addClass: function(el, cls) { el.className = (el.className + ' ' + cls).trim(); }, removeClass: function(el, cls) { el.className = el.className.replace( new RegExp('\\s*' + cls + '\\s*'), ' ').trim(); }, remove: function(el) { if (el.parentNode) el.parentNode.removeChild(el); }, removeChildren: function(el) { while (el.firstChild) el.removeChild(el.firstChild); }, getBounds: function(el, viewport) { var doc = el.ownerDocument, body = doc.body, html = doc.documentElement, rect; try { // On IE, for nodes that are not inside the DOM, this throws an // exception. Emulate the behavior of all other browsers, which // return a rectangle of 0 dimensions. rect = el.getBoundingClientRect(); } catch (e) { rect = { left: 0, top: 0, width: 0, height: 0 }; } var x = rect.left - (html.clientLeft || body.clientLeft || 0), y = rect.top - (html.clientTop || body.clientTop || 0); if (!viewport) { var view = doc.defaultView; x += view.pageXOffset || html.scrollLeft || body.scrollLeft; y += view.pageYOffset || html.scrollTop || body.scrollTop; } return new Rectangle(x, y, rect.width, rect.height); }, getViewportBounds: function(el) { var doc = el.ownerDocument, view = doc.defaultView, html = doc.documentElement; return new Rectangle(0, 0, view.innerWidth || html.clientWidth, view.innerHeight || html.clientHeight ); }, getOffset: function(el, viewport) { return this.getBounds(el, viewport).getPoint(); }, getSize: function(el) { return this.getBounds(el, true).getSize(); }, /** * Checks if element is invisibile (display: none, ...) */ isInvisible: function(el) { return this.getSize(el).equals(new Size(0, 0)); }, /** * Checks if element is visibile in current viewport */ isInView: function(el) { // See if the viewport bounds intersect with the windows rectangle // which always starts at 0, 0 return !this.isInvisible(el) && this.getViewportBounds(el).intersects( this.getBounds(el, true)); }, /** * Gets the given property from the element, trying out all browser * prefix variants. */ getPrefixValue: function(el, name) { var value = el[name], prefixes = ['webkit', 'moz', 'ms', 'o'], suffix = name[0].toUpperCase() + name.substring(1); for (var i = 0; i < 4 && value == null; i++) value = el[prefixes[i] + suffix]; return value; } }; };