File: src/helpers.js
/*
* Copyright (c) 2014-2015, Wanadev <http://www.wanadev.fr/>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Wanadev nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authored by: Fabien LOISON <http://flozz.fr/>
*/
/**
* PhotonUI - Javascript Web User Interface.
*
* @module PhotonUI
* @submodule Helpers
* @main helpers
* @namespace photonui
*/
var uuid = require("uuid");
/**
* Helpers.
*
* @class Helpers
* @constructor
*/
var Helpers = function () {
};
/**
* Escape HTML.
*
* @method escapeHtml
* @static
* @param {String} string
* @return {String}
*/
Helpers.escapeHtml = function (string) {
return string
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">");
};
/**
* Generate an UUID version 4 (RFC 4122).
*
* This method is deprecated, please use `photonui.lib.uuid.v4()` instead.
*
* @method uuid4
* @static
* @deprecated
* @return {String} The generated UUID
*/
Helpers.uuid4 = function () {
Helpers.log("warn", "'photonui.Helpers.uuid4()' is deprecated. Use 'photonui.lib.uuid.v4()' instead.");
return uuid.v4();
};
/**
* Clean node (remove all children of the node).
*
* @method cleanNode
* @static
* @param {HTMLElement} node
*/
Helpers.cleanNode = function (node) {
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
}
};
/**
* Get the absolute position of an HTML Element.
*
* @method getAbsolutePosition
* @static
* @param {HTMLElement} element The HTML element (or its id)
* @return {Object} `{x: <Number>, y: <Number>}
*/
Helpers.getAbsolutePosition = function (element) {
if (typeof(element) == "string") {
element = document.getElementById(element);
}
if (!(element instanceof Element)) {
return {x: 0, y: 0};
}
var css;
var origElement = element;
try {
css = getComputedStyle(element);
} catch (e) {
return {x: 0, y: 0};
}
if (!css) {
return {x: 0, y: 0};
}
var x = -parseInt(css.borderLeftWidth);
var y = -parseInt(css.borderTopWidth);
while (element.offsetParent) {
css = getComputedStyle(element);
x += element.offsetLeft || 0;
x += parseInt(css.borderLeftWidth);
y += element.offsetTop || 0;
y += parseInt(css.borderTopWidth);
element = element.offsetParent;
}
element = origElement;
while (element.parentNode && !(element instanceof HTMLBodyElement)) {
x -= element.scrollLeft || 0;
y -= element.scrollTop || 0;
element = element.parentNode;
}
return {x: x, y: y};
};
/**
* Check and compute size to valid CSS size
*
* Valid values and transformations:
* undefined -> defaultValue
* null -> "auto" (if "auto" is alowed, "0px" else)
* +Infinity -> "100%"
* Number -> "<Number>px"
*
* @method numberToCssSize
* @static
* @param {Number} value
* @param {Number} defaultValue (opt, default=nullValue)
* @param {String} nullValue (opt, default="auto")
* @return {String} sanitized version of the size.
*/
Helpers.numberToCssSize = function (value, defaultValue, nullValue) {
nullValue = (nullValue === undefined) ? "auto" : nullValue;
defaultValue = (nullValue === undefined) ? null : defaultValue;
value = (value === undefined) ? defaultValue : value;
if (value === Infinity) {
return "100%";
} else if (!isNaN(parseFloat(value))) {
return Math.max(0, parseFloat(value) | 0) + "px";
} else if (value !== defaultValue) {
return Helpers.numberToCssSize(defaultValue, defaultValue, nullValue);
} else {
return nullValue;
}
};
/**
* Write log into the terminal.
*
* @method log
* @static
* @param {String} level The log level ("info", "warn", "error", ...)
* @param {String} message The message to log
*/
Helpers.log = function (level, message) {
try {
if (!window.console) {
return;
}
if (!window.console.log) {
return;
}
if (!window.console[level]) {
level = "log";
}
window.console[level]("PhotonUI: " + message);
} catch (e) {
}
};
/**
* Get the closest matching element up the DOM tree.
* https://gomakethings.com/climbing-up-and-down-the-dom-tree-with-vanilla-javascript/
*
* @method getClosest
* @param {Element} elem Starting element
* @param {String} selector Selector to match against
* @return {Boolean|Element} Returns null if not match found
*/
Helpers.getClosest = function (elem, selector) {
// Element.matches() polyfill
if (!Element.prototype.matches) {
Element.prototype.matches =
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector ||
function (s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s);
var i = matches.length;
// jscs:disable
while (--i >= 0 && matches.item(i) !== this) {}
// jscs:enable
return i > -1;
};
}
// Get closest match
for (; elem && elem !== document; elem = elem.parentNode) {
if (elem.matches(selector)) {
return elem;
}
}
return null;
};
module.exports = Helpers;