/* <copyright> This file contains proprietary software owned by Motorola Mobility, Inc.<br/> No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/> (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. </copyright> */ var Montage = require("montage/core/core").Montage, Component = require("montage/ui/component").Component, Uuid = require("montage/core/uuid").Uuid, ElementModel = require("js/models/element-model").ElementModel, Properties3D = require("js/models/properties-3d").Properties3D, ShapeModel = require("js/models/shape-model").ShapeModel, ControllerFactory = require("js/controllers/elements/controller-factory").ControllerFactory; exports.NJUtils = Montage.create(Component, { /* =============== DOM Access ================ */ ///// Quick "getElementById" $ : { value: function(id, doc) { doc = doc || document; return doc.getElementById(id); } }, ///// Quick "getElementsByClassName" which also returns as an Array ///// Can return as NodeList by passing true as second argument $$ : { value: function(className, asNodeList, doc) { doc = doc || document; var list = doc.getElementsByClassName(className); return (asNodeList) ? list : this.toArray(list); } }, ///// Get child nodes of element ///// Omit filter to only return element nodes ///// Pass in filter function to minimize collection, or ///// set to true to include all nodes children : { value : function(el, filter) { var f = filter || function(item) { return item.nodeType === 1; }; return this.toArray(el.childNodes).filter(f); } }, /* ============= DOM Manipulation ============= */ ///// Creates and returns text node from string textNode : { value: function(text) { return document.createTextNode(text); } }, ///// Quick "createElement" function "attr" can be classname or object ///// with attribute key/values ///// Support for data attributes ///// Support user/ninja document make: { value: function(tag, attr, doc) { var _doc, el; _doc = doc ? doc.model.views.design.document : document; el = _doc.createElement(tag); this.decor(el, attr); return el; } }, decor: { value: function(el, attr) { if (typeof attr === 'object') { for (var a in attr) { if (attr.hasOwnProperty(a)) { if(a.indexOf("data-") > -1) { el.setAttribute(a, attr[a]); } else { el[a] = attr[a]; } } } } else if (typeof attr === 'string') { el.className = (el.className + ' ' + attr).trim(); } } }, // TODO: Find a better place for this method stylesFromDraw: { value: function(element, width, height, drawData, pos) { var styles = {}; styles['position'] = pos ? pos: "absolute"; styles['left'] = (Math.round(drawData.midPt[0] - 0.5 * width)) - this.application.ninja.currentDocument.model.domContainer.offsetLeft + 'px'; styles['top'] = (Math.round(drawData.midPt[1] - 0.5 * height)) - this.application.ninja.currentDocument.model.domContainer.offsetTop + 'px'; styles['width'] = width + 'px'; styles['height'] = height + 'px'; // TODO: Check why Canvas has different tranform styles from default. if(!MathUtils.isIdentityMatrix(drawData.planeMat)) { styles['-webkit-transform-style'] = 'preserve-3d'; styles['-webkit-transform'] = this.getElementMatrix(drawData.planeMat, drawData.midPt); } if(element.nodeName === "CANVAS") { element.width = width; element.height = height; delete styles['width']; delete styles['height']; styles['-webkit-transform-style'] = 'preserve-3d'; } return styles; } }, // Get the matrix for the actual element being added to the user document. // TODO: Find a better place for this method getElementMatrix: { value: function(planeMat, midPt) { var divMat, flatMat, flatMatSafe; // we should not need to worry about divide by zero below since we snapped to the point divMat = planeMat.slice(0); divMat[12] = 0.0; divMat[13] = 0.0; //divMat[14] = 0.0; divMat[14] = midPt[2]; // set the left and top of the element such that the center of the rectangle is at the mid point this.application.ninja.stage.setStageAsViewport(); flatMat = divMat; flatMatSafe = MathUtils.scientificToDecimal(flatMat, 10); return "matrix3d(" + flatMatSafe + ")"; } }, ///// Removes all child nodes and returns node ///// Accepts a single node, or an array of dom nodes empty : { value: function(node) { var elements = [], self = this; if (node.constructor === Array) { node.forEach(function(el) { self.empty(el) }); } else { this.toArray(node.childNodes).forEach(function(child) { child.parentNode.removeChild(child); }); } return node; } }, queryParentSelector : { value: function(el, strSelector) { // queryParentSelector: // Given a DOM element el (required), walk up the DOM tree // and find the first parent that matches selector strSelector (required). // Returns: The element that matches, or false if there is no match // or if insufficient parameters are supplied. if ((typeof(el) === "undefined") || (typeof(strSelector) === "undefined")) { // Parameters are required, m'kay? return false; } else if ((typeof(el) !== "object") || (typeof(strSelector) !== "string" )) { // You also have to use the right parameters. return false; } // First, get an empty clone of the parent. var myParent = el.parentNode; var clone = myParent.cloneNode(false); if (clone === null) { return false; } // If we're at the top of the DOM, our clone will be an htmlDocument. // htmlDocument has no tagName. if (typeof(clone.tagName) !== "undefined") { // create a bogus div to use as a base for querySelector var temp = document.createElement("div"); // Append the clone to the bogus div temp.appendChild(clone); // Now we can use querySelector! Sweet. var selectorTest = temp.querySelector(strSelector); // What has querySelector returned? if (selectorTest === null) { // No match, so recurse. return this.queryParentSelector(myParent, strSelector); } else { // Match! Return the element. return myParent; } } else { // We're at the top of the DOM so we're done. return false; } } }, // Returns the numerical value and unit string from a string. // Useful for element properties. // 100px will return the following array: [100, px] getValueAndUnits: { value: function(input) { var numberValue = parseFloat(input); // Ignore all whitespace, digits, negative sign and "." when looking for units label // The units must come after one or more digits var objRegExp = /(\-*\d+\.*\d*)(\s*)(\w*\%*)/; var unitsString = input.replace(objRegExp, "$3"); if(unitsString) { var noSpaces = /(\s*)(\S*)(\s*)/; // strip out spaces and convert to lower case var match = (unitsString.replace(noSpaces, "$2")).toLowerCase(); } return [numberValue, match]; } }, /* ================= Style methods ================= */ ///// Get computed height of element height : { value: function(node, pseudo) { return node.ownerDocument.defaultView.getComputedStyle(node, pseudo).getPropertyValue('height'); } }, /* ================= Array methods ================= */ ///// Return an array from an array-like object toArray : { value: function(arrayLikeObj) { return Array.prototype.slice.call(arrayLikeObj); } }, /* ================= String methods ================= */ ///// Return the last part of a path (e.g. filename) getFileNameFromPath : { value: function(path) { path = path.replace(/[/\\]$/g,""); path = path.replace(/\\/g,"/"); return path.substr(path.lastIndexOf('/') + 1); } }, /*** * file name validation */ isValidFileName:{ value: function(fileName){ var status = false; if(fileName !== ""){ fileName = fileName.replace(/^\s+|\s+$/g,""); status = !(/[/\\]/g.test(fileName)); if(status && navigator.userAgent.indexOf("Macintosh") != -1){//for Mac files beginning with . are hidden status = !(/^\./g.test(fileName)); } } return status; } }, /* ================= misc methods ================= */ // Generates an alpha-numeric random number // len: number of chars // default length is '8' generateRandom: { value: function(len) { var length; len ? length = len : length = 8; return Uuid.generate().substring(0,length); } } });