processmaker-builder
Version:
The gulp task runner for ProcessMaker building
1,494 lines (1,398 loc) • 1.72 MB
JavaScript
/**
* @class PMUI
* Base class PMUI
* @singleton
*/
var PMUI.util.PMUI = {};
PMUI.version = '0.1.1';
PMUI.isCtrl = false;
PMUI.isShift = false;
PMUI.activeCanvas = null;
PMUI.currentContextMenu = null;
$(document).keydown(function (e) {
if (PMUI.activeCanvas) {
switch (e.which) {
case 16: // SHIFT KEY
PMUI.isShift = true;
break;
case 17: // CTRL KEY
PMUI.isCtrl = true;
break;
case 116: // F5 KEY
e.preventDefault();
window.location.reload(true);
break;
case 37:
// Left
if (!PMUI.activeCanvas.currentLabel) {
e.preventDefault();
PMUI.activeCanvas.moveElements(PMUI.activeCanvas, 'LEFT');
}
break;
case 38:
// Top
if (!PMUI.activeCanvas.currentLabel) {
e.preventDefault();
PMUI.activeCanvas.moveElements(PMUI.activeCanvas, 'TOP');
}
break;
case 39:
// Right
if (!PMUI.activeCanvas.currentLabel) {
e.preventDefault();
PMUI.activeCanvas.moveElements(PMUI.activeCanvas, 'RIGHT');
}
break;
case 40:
// Bottom
if (!PMUI.activeCanvas.currentLabel) {
e.preventDefault();
PMUI.activeCanvas.moveElements(PMUI.activeCanvas, 'BOTTOM');
}
break;
case 67: // char 'c'
if (!PMUI.activeCanvas.currentLabel && PMUI.isCtrl) {
if (PMUI.activeCanvas.copyAndPaste) {
e.preventDefault();
PMUI.activeCanvas.copy();
}
}
break;
case 86: // char 'v'
if (!PMUI.activeCanvas.currentLabel && PMUI.isCtrl) {
if (PMUI.activeCanvas.copyAndPaste) {
e.preventDefault();
PMUI.activeCanvas.paste();
}
}
break;
case 90: // char 'z'
if (PMUI.isCtrl && !PMUI.activeCanvas.readOnly) {
if (PMUI.isShift) {
// ctrl + shift + z (redo)
PMUI.activeCanvas.redo();
e.preventDefault();
} else {
// ctrl + z (undo)
PMUI.activeCanvas.undo();
e.preventDefault();
}
}
break;
}
}
}).keypress(function (e) {
}).keyup(function (e) {
var current;
e.preventDefault();
switch (e.which) {
case 8: //BACKSPACE
if (PMUI.isCtrl) {
if (PMUI.activeCanvas && !PMUI.activeCanvas.currentLabel) {
PMUI.activeCanvas.removeElements();
}
}
break;
case 13: // ENTER
if (PMUI.activeCanvas && PMUI.activeCanvas.currentLabel) {
PMUI.activeCanvas.currentLabel.loseFocus();
}
break;
case 46: // DELETE KEY
if (PMUI.activeCanvas && !PMUI.activeCanvas.currentLabel) {
PMUI.activeCanvas.removeElements();
}
break;
case 16: // SHIFT KEY
PMUI.isShift = false;
break;
case 17: //CTRL KEY
PMUI.isCtrl = false;
break;
case 113: //F2 KEY
if (PMUI.activeCanvas &&
PMUI.activeCanvas.getCurrentSelection().getLast() !== null) {
//Run other code here when the element
// 'CurElement' is deleted
current = PMUI.activeCanvas.getCurrentSelection().getLast();
if (current !== undefined && current.label.html !== null) {
$(current.label.html).dblclick();
$(current.label.text.html).focus();
}
}
break;
}
});
/**
* Extends the PMUI namespace with the given `path` and making a pointer
* from `path` to the given `class` (note that the `path`'s last token will be the pointer visible from outside
* the definition of the class).
*
* // e.g.
* // let's define a class inside an anonymous function
* // so that the global scope is not polluted
* (function () {
* var Canvas = function () {...};
*
* // let's extend the namespace
* PMUI.extendNamespace('PMUI.core.Panel', Canvas);
*
* }());
*
* // now PMDraw.draw.Canvas is a pointer to the class defined above
*
* Another example:
*
* // let's define a class inside an anonymous function
* // so that the global scope is not polluted
* (function () {
* var Shape = function () {...};
*
* // let's extend the namespace
* PMUI.extendNamespace('PMUI.draw.RandomName', Shape);
*
* }());
*
* // now PMUI.draw.RandomName is a pointer to the class Shape
* // note that this class can only be accessed through this pointer
*
* @param {string} path
* @param {Object} newClass
* @return {Object} The argument `newClass`
*/
PMUI.extendNamespace = function (path, newClass) {
var current,
pathArray,
extension,
i;
if (arguments.length !== 2) {
throw new Error("PMUI.extendNamespace(): method needs 2 arguments");
}
pathArray = path.split('.');
if (pathArray[0] === 'PMUI') {
pathArray = pathArray.slice(1);
}
current = PMUI;
// create the 'path' namespace
for (i = 0; i < pathArray.length - 1; i += 1) {
extension = pathArray[i];
if (typeof current[extension] === 'undefined') {
current[extension] = {};
}
current = current[extension];
}
extension = pathArray[pathArray.length - 1];
if (current[extension]) {
//console.log("PMUI.extendNamespace(): Warning! overriding the class '" + pathArray.join('.') + "'");
}
current[extension] = newClass;
return newClass;
};
/**
* Checks if `path` (a string separated with dots) is a valid path inside the `from` object if provided otherwise
* checks if `path` is a valid path inside the {@link PMUI} object,
* if so then returns a pointer to the object which is the last token of the string
*
* // e.g
* validPath('PMDraw.event.Keyboard.modifiers.alt'); // returns a pointer to alt
* validPath('modifiers.alt', PMUI.event.Keyboard); // returns a pointer to alt
*
* @param {string} path
* @param {Object} [from]
* @return {Object}
*/
PMUI.validPath = function (path, from) {
var pathArray = path.split('.'),
current,
extension,
i;
if (!from) {
if (pathArray[0] === 'PMUI') {
pathArray = pathArray.slice(1);
}
current = PMUI;
} else {
current = from;
}
for (i = 0; i < pathArray.length; i += 1) {
extension = pathArray[i];
if (!current[extension]) {
return null;
}
current = current[extension];
}
return current;
};
/**
* Creates an object whose [[Prototype]] link points to an object's prototype (the object is gathered using the
* argument `path` and it's the last token in the string), since `subClass` is given it will also mimic the
* creation of the property `constructor` and a pointer to its parent called `superclass`:
*
* // constructor pointer
* subClass.prototype.constructor === subClass // true
*
* // let's assume that superClass is the last token in the string 'path'
* subClass.superclass === superClass // true
*
* An example of use:
*
* (function () {
* var Core = function () {...};
*
* // extending the namespace
* PMDraw.extendNamespace('PMDraw.draw.Core', Core);
*
* }());
*
* (function () {
* var BehavioralElement = function () {...};
*
* // this class inherits from PMDraw.draw.Core
* PMDraw.inheritFrom('PMDraw.draw.Core', BehavioralElement);
*
* // extending the namespace
* PMDraw.extendNamespace('PMDraw.draw.BehavioralElement', BehavioralElement);
*
* }());
*
* @param {string} path
* @param {Object} subClass
* @return {Object}
*/
PMUI.inheritFrom = function (path, subClass) {
var current,
extension,
pathArray,
i,
prototype;
if (arguments.length !== 2) {
throw new Error("PMUI.inheritFrom(): method needs 2 arguments");
}
// function used to create an object whose [[Prototype]] link
// points to `object`
function clone(object) {
var F = function () {};
F.prototype = object;
return new F();
}
pathArray = path.split('.');
if (pathArray[0] === 'PMUI') {
pathArray = pathArray.slice(1);
}
current = PMUI;
// find that class the 'path' namespace
for (i = 0; i < pathArray.length; i += 1) {
extension = pathArray[i];
if (typeof current[extension] === 'undefined') {
throw new Error("PMUI.inheritFrom(): object " + extension + " not found, full path was " + path);
}
current = current[extension];
}
prototype = clone(current.prototype);
prototype.constructor = subClass;
subClass.prototype = prototype;
subClass.superclass = current;
};
/**
* Generates 32-digits alphanumeric unique IDs
* @return {String} Alphanumeric 32-char unique string
*/
PMUI.generateUniqueId = function () {
var rand = function (min, max) {
// Returns a random number
//
// version: 1109.2015
// discuss at: http://phpjs.org/functions/rand
// + original by: Leslie Hoare
// + bugfixed by: Onno Marsman
// % note 1: See the commented out code below for a
// version which will work with our experimental
// (though probably unnecessary) srand() function)
// * example 1: rand(1, 1);
// * returns 1: 1
// fix for jsLint
// from: var argc = arguments.length;
if (typeof min === "undefined") {
min = 0;
}
if (typeof max === "undefined") {
max = 999999999;
}
return Math.floor(Math.random() * (max - min + 1)) + min;
},
uniqid = function (prefix, more_entropy) {
// + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + revised by: Kankrelune (http://www.webfaktory.info/)
// % note 1: Uses an internal counter (in php_js global) to avoid collision
// * example 1: uniqid();
// * returns 1: 'a30285b160c14'
// * example 2: uniqid('foo');
// * returns 2: 'fooa30285b1cd361'
// * example 3: uniqid('bar', true);
// * returns 3: 'bara20285b23dfd1.31879087'
if (typeof prefix === 'undefined') {
prefix = "";
}
var retId,
formatSeed = function (seed, reqWidth) {
var tempString = "",
i;
seed = parseInt(seed, 10).toString(16); // to hex str
if (reqWidth < seed.length) { // so long we split
return seed.slice(seed.length - reqWidth);
}
if (reqWidth > seed.length) { // so short we pad
// jsLint fix
tempString = "";
for (i = 0; i < 1 + (reqWidth - seed.length); i += 1) {
tempString += "0";
}
return tempString + seed;
}
return seed;
};
// BEGIN REDUNDANT
if (!this.php_js) {
this.php_js = {};
}
// END REDUNDANT
if (!this.php_js.uniqidSeed) { // init seed with big random int
this.php_js.uniqidSeed = Math.floor(Math.random() * 0x75bcd15);
}
this.php_js.uniqidSeed += 1;
retId = prefix; // start with prefix, add current milliseconds hex string
retId += formatSeed(parseInt(new Date().getTime() / 1000, 10), 8);
retId += formatSeed(this.php_js.uniqidSeed, 5); // add seed hex string
if (more_entropy) {
// for more entropy we add a float lower to 10
retId += (Math.random() * 10).toFixed(8).toString();
}
return retId;
},
sUID;
do {
sUID = uniqid(rand(0, 999999999), true);
sUID = sUID.replace('.', '0');
} while (sUID.length !== 32);
return sUID;
};
/**
* Creates and returns a HTML element
* @param {String} type The type for the element to be created, for example: div, span, p
* @return {HTMLElement} An HTML element
*/
PMUI.createHTMLElement = function(type) {
return document.createElement(type);
};
/**
* Calculates the text width usign a font family
* @param {String} text The text which width will be calculated
* @param {String} font The font family and size (expressed as the 'font' css properties)
* to be used to calculate the width
* @return {Number}
*/
PMUI.calculateWidth = function (text, font) {
var f = font || '12px arial',
$o = $(this.createHTMLElement('div')), w;
$o.text(text)
.css({'position': 'absolute', 'float': 'left', 'white-space': 'nowrap', 'visibility': 'hidden', 'font': f})
.appendTo($('body'));
w = $o.width();
$o.remove();
return w;
};
PMUI.emToPx = function(emUnits, context) {
var testDiv = PMUI.createHTMLElement('div'), theWidth, $div;
testDiv.style.margin = '0';
testDiv.style.padding = '0';
testDiv.style.position = 'absolute';
testDiv.style.display = 'inline-block';
testDiv.style.backgroundColor = 'none';
testDiv.style.width = emUnits + "em";
context = PMUI.isHTMLElement(context) ? context : document.body;
if(context !== document.body && !jQuery(context).parents('body').length) {
throw new Error("The context must be an HTML element appended to the DOM.");
}
context.appendChild(testDiv);
$div = jQuery(testDiv);
theWidth = $div.outerWidth();
$div.remove();
return theWidth;
};
/**
* Get PMUI Version.
* @return {String}
*/
PMUI.getVersion = function () {
return this.version;
};
/**
* Trigger events defined in the element
* @param {PMUI.core.Element} el Element associated with the event
* @param {String} eventName Event Name or alias
* @param {Object} scope Calling scope for the event
*/
PMUI.triggerEvent = function(el, eventName, scope) {
var scopeTrigger = scope || this;
if (el instanceof PMUI.core.Element) {
if (el.events[eventName] instanceof PMUI.event.Event){
el.events[eventName].handler.call(scopeTrigger);
} else {
throw new Error('Event name is not registered int this element');
}
} else {
throw new Error('Current Element is not able to trigger events');
}
};
/**
* Sets the active canvas.
* @param {PMUI.draw.Canvas} canvas
* @chainable
*/
PMUI.setActiveCanvas = function (canvas) {
PMUI.activeCanvas = canvas;
return this;
};
/**
* Gets the active canvas
* @return {PMUI.draw.Canvas}
*/
PMUI.getActiveCanvas = function () {
return PMUI.activeCanvas;
};
/**
* Converts the coordinates `xCoord` and `yCoord` (assuming that xCoord and yCoord are pageCoordinates)
* or the page coordinates gathered from the object `e` if there is no `xCoord` or `yCoord` to
* `shape` coordinates, this new coordinate also considers the scroll done in the canvas
*
* // e.g.
* // Let's assume that:
* // the canvas coordinates are [100, 100] and that it has no scroll
* // the shape coordinates are [100, 100] (inside the canvas)
* // e is an object containing page.X = 300, page.Y = 300
* Utils.pageCoordinatesToShapeCoordinates(shape, e) // new Point(100, 100) respect to the shape
*
*
* @param {Object} shape
* @param {Object} e
* @param {number} [xCoord]
* @param {number} [yCoord]
* @return {PMUI.util.Point} a point relative to the canvas
*/
PMUI.pageCoordinatesToShapeCoordinates = function (shape, e, xCoord, yCoord, customShape) {
var coordinates,
x = (!xCoord) ? e.pageX : xCoord,
y = (!yCoord) ? e.pageY : yCoord,
orgX = (!xCoord) ? e.pageX : xCoord,
orgY = (!yCoord) ? e.pageY : yCoord,
canvas = shape.getCanvas();
x += canvas.getLeftScroll() - shape.getAbsoluteX() - canvas.getX();
y += canvas.getTopScroll() - shape.getAbsoluteY() - canvas.getY();
if (orgX === x) {
x -= parseInt(customShape.width / 2, 10);
}
if (orgY === y) {
y -= parseInt(customShape.height / 2, 10);
}
coordinates = new PMUI.util.Point(x, y);
return coordinates;
};
/**
* Validates the parameters that represents the coordinates for create a new shape
* @param {Object} canvas Represents the current canvas for the project
* @param {Object} e Represents the event that triggered on the event
* @param {Object} customShape Represents the object that will create a new element on the canvas
* @return {Boolean} flag After the review of the coordinates the method return true if the component
* will create on the canvas and false if not possible create it.
*/
PMUI.validCoordinatedToCreate = function (canvas, e, customShape) {
return function (canvas, e, customShape) {
return true;
};
};
/**
* Converts the coordinates of the `shape` to page coordinates, this method
* also considers the scroll of the canvas in the calculation
*
* // e.g.
* // Let's assume that:
* // the canvas coordinates are [100, 100] and that it has no scroll
* // the shape coordinates are [100, 100] (inside the canvas)
* Utils.getPointRelativeToPage(shape) // new Point(200, 200) respect to the page
*
* @param {Object} shape
* @return {PMUI.util.Point} a point relative to the page
*/
PMUI.getPointRelativeToPage = function (shape) {
var canvas = shape.getCanvas(),
x = shape.absoluteX + canvas.getX() - canvas.getLeftScroll() +
shape.zoomWidth / 2,
y = shape.absoluteY + canvas.getY() - canvas.getTopScroll() +
shape.zoomHeight / 2;
return new PMUI.point.Point(x, y);
};
PMUI.json2xml = function (o) {
var len,
toXML,
safeXMLValue,
a;
len = function (o) {
var n = 0,
a;
for (a in o) {
if (o.hasOwnProperty(a)) {
n += 1;
}
}
return n;
};
toXML = function (tag, o) {
var a,
b,
doc = '<' + tag,
sw = false,
i;
if (typeof o === 'undefined' || o === null) {
doc += '/>';
return doc;
}
if (typeof o !== 'object') {
doc += '>' + safeXMLValue(o) + '</' + tag + '>';
return doc;
}
if (o.constructor === Object) {
for (a in o) {
if (o.hasOwnProperty(a)) {
if (a.charAt(0) === '@') {
if (typeof o[a] !== 'object') {
doc += ' ' + a.substring(1) + '="' + o[a] + '"';
delete o[a];
} else {
throw new Error((typeof o[a])
+ ' being attribute is not supported.');
}
}
}
}
if (len(o) === 0) {
doc += '/>';
sw = true;
} else {
doc += '>';
}
if (sw) {
return doc;
}
if (typeof o['#text'] !== 'undefined') {
if (typeof o['#text'] !== 'object') {
doc += o['#text'];
delete o['#text'];
} else {
throw new Error((typeof o['#text'])
+ ' being #text is not supported.');
}
}
for (b in o) {
if (o.hasOwnProperty(b)) {
if (o[b].constructor === Array) {
for (i = 0; i < o[b].length; i++) {
if (typeof o[b][i] !== 'object'
|| o[b][i].constructor === Object) {
doc += toXML(b, o[b][i]);
} else {
throw new Error((typeof o[b][i])
+ ' is not supported.');
}
}
} else if (o[b].constructor === Object
|| typeof o[b] !== 'object') {
doc += toXML(b, o[b]);
} else {
throw new Error((typeof o[b]) + ' is not supported.');
}
}
}
doc += '</' + tag + '>';
return doc;
}
};
safeXMLValue = function (value) {
var s = value.toString();
s = s.replace(/\&/g, '&');
s = s.replace(/\"/g, '"');
s = s.replace(/</g, '<');
s = s.replace(/>/g, '>');
return s;
};
if (typeof o === 'object' && o.constructor === Object && len(o) === 1) {
for (a in o) {
if (o.hasOwnProperty(a)){
return toXML(a, o[a]);
}
}
}
};
PMUI.linkToPMUIObject = function(element, pmuiObject) {
if(this.isHTMLElement(element) && pmuiObject instanceof PMUI.core.Element) {
jQuery(element).data('pmui', pmuiObject);
} else {
throw new Error("PMUI.linkToPMUIObject(): the first parameter must be a HTMLElement and the second one must be "
+ "an instance of PMUI.core.Element.");
}
};
PMUI.getPMUIObject = function(element) {
if(this.isHTMLElement(element)) {
return jQuery(element).data("pmui");
}
throw new Error("PMUI.getPMUIObject(): the parameter must be a HTMLElement.");
};
PMUI.isHTMLElement = function(obj) {
try {
//Using W3 DOM2 (works for FF, Opera and Chrom)
return obj instanceof HTMLElement;
}
catch(e){
//Browsers not supporting W3 DOM2 don't have HTMLElement and
//an exception is thrown and we end up here. Testing some
//properties that all elements have. (works on IE7)
return (typeof obj==="object") &&
(obj.nodeType===1) && (typeof obj.style === "object") &&
(typeof obj.ownerDocument ==="object");
}
};
PMUI.removeCurrentMenu = function() {
if (PMUI.currentContextMenu && PMUI.currentContextMenu.displayed) {
PMUI.currentContextMenu.hide();
PMUI.currentContextMenu = null;
}
};
PMUI.init = function () {
String.prototype.translate = PMUI.lang.I18N.translate;
String.prototype.translateContext = PMUI.lang.I18N.translateContext;
return this;
};
PMUI.loadLanguage = function (data, lang, loaded){
PMUI.lang.I18N.loadLanguage(data, lang, loaded);
return this;
};
PMUI.setCurrentLanguage = function (lang){
PMUI.lang.I18N.setCurrentLanguage(lang);
return this;
};
PMUI.setDefaultLanguage = function (lang){
PMUI.lang.I18N.setDefaultLanguage(lang);
return this;
};
PMUI.convertDateFormat = function(dateInput) {
//TODO Implement this method considering locate options
return dateInput;
};
PMUI.castValue = function (value, format) {
try {
switch(format) {
case 'string':
out = String(value);
break;
case 'number':
if(value!=''){
out = Number(value);
} else {
out = 'NaN';
}
break;
case 'date':
out = PMUI.convertDateFormat(value);
break;
case 'boolean':
out = Boolean(value);
break;
default:
out = value;
}
return out;
} catch (e) {
throw new Error("The value cannot be showed in '" + format + "' format");
}
};
if (typeof exports !== "undefined") {
module.exports = PMUI;
}
(function () {
/**
* @class PMUI.util.ArrayList
* Construct a List similar to Java's ArrayList that encapsulates methods for
* making a list that supports operations like get, insert and others.
*
* some examples:
* var item,
* arrayList = new ArrayList();
* arrayList.getSize() // 0
* arrayList.insert({ // insert an object
* id: 100,
* width: 100,
* height: 100
* });
* arrayList.getSize(); // 1
* arrayList.asArray(); // [{id : 100, ...}]
* item = arrayList.find('id', 100); // finds the first element with an id that equals 100
* arrayList.remove(item); // remove item from the arrayList
* arrayList.getSize(); // 0
* arrayList.isEmpty(); // true because the arrayList has no elements
*
* @constructor Returns an instance of the class ArrayList
*/
var ArrayList = function () {
/**
* The elements of the arrayList
* @property {Array}
* @private
*/
var elements = [],
/**
* The size of the array
* @property {number} [size=0]
* @private
*/
size = 0,
index,
i;
return {
/**
* The ID of this ArrayList is generated using the function Math.random
* @property {number} id
*/
id: Math.random(),
/**
* Gets an element in the specified index or undefined if the index
* is not present in the array
* @param {number} index
* @returns {Object / undefined}
*/
get : function (index) {
return elements[index];
},
/**
* Inserts an element at the end of the list
* @param {Object} item
* @chainable
*/
insert : function (item) {
elements[size] = item;
size += 1;
return this;
},
/**
* Inserts an element in a specific position
* @param {Object} item
* @chainable
*/
insertAt: function(item, index) {
elements.splice(index, 0, item);
size = elements.length;
return this;
},
/**
* Removes an item from the list
* @param {Object} item
* @return {boolean}
*/
remove : function (item) {
index = this.indexOf(item);
if (index === -1) {
return false;
}
//swap(elements[index], elements[size-1]);
size -= 1;
elements.splice(index, 1);
return true;
},
/**
* Gets the length of the list
* @return {number}
*/
getSize : function () {
return size;
},
/**
* Returns true if the list is empty
* @returns {boolean}
*/
isEmpty : function () {
return size === 0;
},
/**
* Returns the first occurrence of an element, if the element is not
* contained in the list then returns -1
* @param {Object} item
* @return {number}
*/
indexOf : function (item) {
for (i = 0; i < size; i += 1) {
if (item === elements[i]) {
return i;
}
}
return -1;
},
/**
* Returns the the first object of the list that has the
* specified attribute with the specified value
* if the object is not found it returns undefined
* @param {string} attribute
* @param {string} value
* @return {Object / undefined}
*/
find : function (attribute, value) {
var i,
current;
for (i = 0; i < elements.length; i += 1) {
current = elements[i];
if (current[attribute] === value) {
return current;
}
}
return undefined;
},
/**
* Returns true if the list contains the item and false otherwise
* @param {Object} item
* @return {boolean}
*/
contains : function (item) {
if (this.indexOf(item) !== -1) {
return true;
}
return false;
},
/**
* Sorts the list using compFunction if possible, if no compFunction
* is passed as an parameter then a default sorting method will be used. This default method will sort in
* ascending order.
* @param {Function} [compFunction] The criteria function used to find out the position for the elements in
* the array list. This function will receive two parameters, each one will be an element from the array
* list, the function will compare those elements and it must return:
*
* - 1, if the first element must be before the second element.
* - -1, if the second element must be before the first element.
* - 0, if the current situation doesn't met any of the two situations above. In this case both elements
* can be evaluated as they had the same value. For example, in an array list of numbers, when you are
* trying to apply a lineal sorting (ascending/descending) in a array list of numbers, if the array sorting
* function finds two elements with the value 3 they should be evaluated returning 0, since both values are
* the same.
*
* IMPORTANT NOTE: for a correct performance the sent parameter must return at least two of the values
* listed above, if it doesn't the function can produce an infinite loop and thus an error.
* @return {boolean}
*/
sort : function (compFunction) {
var compFunction = compFunction || function(a, b) {
if(a < b) {
return 1;
} else if(a > b) {
return -1;
} else {
return 0;
}
}, swap = function (items, firstIndex, secondIndex){
var temp = items[firstIndex];
items[firstIndex] = items[secondIndex];
items[secondIndex] = temp;
}, partition = function(items, left, right) {
var pivot = items[Math.floor((right + left) / 2)],
i = left,
j = right;
while (i <= j) {
while (compFunction(items[i], pivot) > 0) {
i++;
}
while (compFunction(items[j], pivot) < 0) {
j--;
}
if (i <= j) {
swap(items, i, j);
i++;
j--;
}
}
return i;
}, quickSort = function (items, left, right) {
var index;
if (items.length > 1) {
index = partition(items, left, right);
if (left < index - 1) {
quickSort(items, left, index - 1);
}
if (index < right) {
quickSort(items, index, right);
}
}
return items;
};
return quickSort(elements, 0, size - 1);
},
/**
* Returns the list as an array
* @return {Array}
*/
asArray : function () {
return elements.slice(0);
},
/**
* Swaps the position of two elements
* @chainable
*/
swap: function(index1, index2) {
var aux;
if(index1 < size && index1 >=0 && index2 < size && index2 >= 0) {
aux = elements[index1];
elements[index1] = elements[index2];
elements[index2] = aux;
}
return this;
},
/**
* Returns the first element of the list
* @return {Object}
*/
getFirst : function () {
return elements[0];
},
/**
* Returns the last element of the list
* @return {Object}
*/
getLast : function () {
return elements[size - 1];
},
/**
* Returns the last element of the list and deletes it from the list
* @return {Object}
*/
popLast : function () {
var lastElement;
size -= 1;
lastElement = elements[size];
elements.splice(size, 1);
return lastElement;
},
/**
* Returns an array with the objects that determine the minimum size
* the container should have
* The array values are in this order TOP, RIGHT, BOTTOM AND LEFT
* @return {Array}
*/
getDimensionLimit : function () {
var result = [100000, -1, -1, 100000],
objects = [undefined, undefined, undefined, undefined];
//number of pixels we want the inner shapes to be
//apart from the border
for (i = 0; i < size; i += 1) {
if (result[0] > elements[i].y) {
result[0] = elements[i].y;
objects[0] = elements[i];
}
if (result[1] < elements[i].x + elements[i].width) {
result[1] = elements[i].x + elements[i].width;
objects[1] = elements[i];
}
if (result[2] < elements[i].y + elements[i].height) {
result[2] = elements[i].y + elements[i].height;
objects[2] = elements[i];
}
if (result[3] > elements[i].x) {
result[3] = elements[i].x;
objects[3] = elements[i];
}
}
return result;
},
/**
* Clears the content of the arrayList
* @chainable
*/
clear : function () {
if (size !== 0) {
elements = [];
size = 0;
}
return this;
},
/**
* Sets the elements for the object.
* @param {Array|null} items Array with the items to set.
* @chainable
*/
set: function(items) {
if(!(items === null || jQuery.isArray(items))) {
throw new Error("set(): The parameter must be an array or null.");
}
elements = (items && items.slice(0)) || [];
size = elements.length;
return this;
}
};
};
PMUI.extendNamespace('PMUI.util.ArrayList', ArrayList);
if (typeof exports !== "undefined") {
module.exports = ArrayList;
}
}());
(function () {
/**
* @class PMUI.util.Style
* Class that represent the style of a an object.
*
* // i.e
* // Let's assume that 'shape' is a CustomShape
* var style = new Style({
* cssClasses: [
* 'sprite-class', 'marker-class', ...
* ],
* cssProperties: {
* border: 1px solid black,
* background-color: grey,
* ...
* },
* belongsTo: shape
* })
*
* @constructor Creates a new instance of this class
* @param {Object} options
* @cfg {Array} [cssClasses=[]] the classes that `this.belongsTo` has
* @cfg {Object} [cssProperties={}] the css properties that `this.belongsTo` has
* @cfg {Object} [belongsTo=null] a pointer to the owner of this instance
*/
var Style = function (options) {
/**
* JSON Object used to map each of the css properties of the object,
* this object has the same syntax as the object passed to jQuery.css()
* cssProperties: {
* background-color: [value],
* border: [value],
* ...
* }
* @property {Object}
*/
this.cssProperties = null;
/**
* Array of all the classes of this object
* cssClasses = [
* 'class_1',
* 'class_2',
* ...
* ]
* @property {Array}
*/
this.cssClasses = null;
/**
* Pointer to the object to whom this style belongs to
* @property {Object}
*/
this.belongsTo = null;
Style.prototype.initObject.call(this, options);
};
/**
* The type of this class
* @property {String}
*/
Style.prototype.type = "Style";
/**
* Constant for the max z-index
* @property {number} [MAX_ZINDEX=100]
*/
Style.MAX_ZINDEX = 100;
/**
* Instance initializer which uses options to extend the config options to
* initialize the instance
* @private
* @param {Object} options
*/
Style.prototype.initObject = function (options) {
var defaults = {cssClasses: [],cssProperties: {}, belongsTo: null};
jQuery.extend(true, defaults, options);
this.cssClasses = defaults.cssClasses;
this.cssProperties = defaults.cssProperties;
this.belongsTo = defaults.belongsTo;
};
/**
* Applies cssProperties and cssClasses to `this.belongsTo`
* @chainable
*/
Style.prototype.applyStyle = function () {
if (!this.belongsTo.html) {
throw new Error("applyStyle(): can't apply style to an" +
" object with no html.");
}
var i, t, class_i;
// apply the cssProperties
jQuery(this.belongsTo.html).css(this.cssProperties);
//adding default classes
t = this.belongsTo.type.toLowerCase();
if (this.cssClasses.indexOf('pmui-' + t) === -1) {
this.cssClasses.unshift('pmui-' + t);
}
if (this.cssClasses.indexOf('pmui') === -1) {
this.cssClasses.unshift('pmui');
}
// apply saved classes
for (i = 0; i < this.cssClasses.length; i += 1) {
class_i = this.cssClasses[i];
if (!$(this.belongsTo.html).hasClass(class_i)) {
jQuery(this.belongsTo.html).addClass(class_i);
}
}
return this;
};
Style.prototype.unapplyStyle = function() {
var i, t, property;
if(!this.belongsTo.html) {
throw new Error("unapplyStyle(): can't unapply style to an object with no html.");
}
t = this.belongsTo.type.toLowerCase();
jQuery(this.belongsTo.html).removeClass("pmui-" + t);
for(property in this.cssProperties) {
jQuery(this.belongsTo.html).css(property, "");
}
};
/**
* Extends the property `cssProperties` with a new object and also applies those new properties
* @param {Object} properties
* @chainable
*/
Style.prototype.addProperties = function (properties) {
jQuery.extend(true, this.cssProperties, properties);
jQuery(this.belongsTo && this.belongsTo.html).css(properties);
return this;
};
/**
* Gets a property from `this.cssProperties` using jQuery or `window.getComputedStyle()`
* @param {String} property
* @return {String}
*/
Style.prototype.getProperty = function (property) {
return this.cssProperties[property] ||
jQuery(this.belongsTo.html).css(property) ||
(this.belongsTo.html && window.getComputedStyle(this.belongsTo.html, null)
.getPropertyValue(property)) || "";
};
/**
* Returns all the style's css properties set explicitly.
* @return {Object} An object literal with the properties.
*/
Style.prototype.getProperties = function() {
return this.cssProperties;
};
/**
* Removes ´properties´ from the ´this.cssProperties´, also disables those properties from
* the HTMLElement
* @param {Array} properties An array in which each element is th name of the cssProperty to be removed.
* @chainable
*/
Style.prototype.removeProperties = function (properties) {
var property,
i;
for (i = 0; i < properties.length; i += 1) {
property = properties[i];
if (this.cssProperties.hasOwnProperty(property)) { // JS Code Convention
jQuery(this.belongsTo.html).css(property, ""); // reset inline style
delete this.cssProperties[property];
}
}
return this;
};
/**
* Removes all properties from the object.
* @chainable
*/
Style.prototype.removeAllProperties = function() {
var key;
if(this.belongsTo) {
for(key in this.cssProperties) {
jQuery(this.belongsTo.html).css(key, "");
}
}
this.cssProperties = {};
return this;
};
/**
* Adds new classes to ´this.cssClasses´ array
* @param {Array} cssClasses
* @chainable
*/
Style.prototype.addClasses = function (cssClasses) {
var i,
cssClass;
if (cssClasses && cssClasses instanceof Array) {
for (i = 0; i < cssClasses.length; i += 1) {
cssClass = cssClasses[i];
if (typeof cssClass === "string") {
if (this.cssClasses.indexOf(cssClass) === -1) {
this.cssClasses.push(cssClass);
jQuery(this.belongsTo && this.belongsTo.html).addClass(cssClass);
}
} else {
throw new Error("addClasses(): array element is not of type string");
}
}
} else {
throw new Error("addClasses(): parameter must be of type Array");
}
return this;
};
/**
* Removes classes from ´this.cssClasses´ array, also removes those classes from
* the HTMLElement
* @param {Array} cssClasses
* @chainable
*/
Style.prototype.removeClasses = function (cssClasses) {
var i,
index,
cssClass;
if (cssClasses && cssClasses instanceof Array) {
for (i = 0; i < cssClasses.length; i += 1) {
cssClass = cssClasses[i];
if (typeof cssClass === "string") {
index = this.cssClasses.indexOf(cssClass);
if (index !== -1) {
jQuery(this.belongsTo.html).removeClass(this.cssClasses[index]);
this.cssClasses.splice(index, 1);
}
} else {
throw new Error("removeClasses(): array element is not of " +
"type string");
}
}
} else {
throw new Error("removeClasses(): parameter must be of type Array");
}
return this;
};
/**
* Removes all the classes from ´this.cssClasses´ array
* @param {Array} cssClasses
* @chainable
*/
Style.prototype.removeAllClasses = function () {
while(this.cssClasses.length) {
jQuery(this.belongsTo && this.belongsTo.html).removeClass(this.cssClasses.pop());
}
return this;
};
/**
* Checks if the class is a class stored in ´this.cssClasses´
* @param cssClass
* @return {boolean}
*/
Style.prototype.containsClass = function (cssClass) {
return this.cssClasses.indexOf(cssClass) !== -1;
};
/**
* Returns an array with all the classes of ´this.belongsTo´
* @return {Array}
*/
Style.prototype.getClasses = function () {
return this.cssClasses.slice(0);
};
/**
* Clears all the css properties and classes.
* @chainable
*/
Style.prototype.clear = function() {
return this.removeAllClasses().removeAllProperties();
}
/**
* Serializes this instance
* @return {Object}
* @return {Array} return.cssClasses
*/
Style.prototype.stringify = function () {
return {
cssClasses: this.cssClasses
// cssProperties: this.cssProperties
};
};
// Declarations created to instantiate in NodeJS environment
if (typeof exports !== "undefined") {
module.exports = Style;
}
PMUI.extendNamespace('PMUI.util.Style', Style);
}());
(function () {
/**
* @class PMUI.util.Factory
* This class encapsulate the way to construct object using the product definition inside
*
* @constructor
* This method creates a new instance of this object
* @param {Object} settings Constructor setiings
*/
var Factory = function (settings) {
/**
* Defines the products can be make by the factory
* @type {Object}
*/
this.products = null;
/**
* Defines the default product to make
* @type {String}
*/
this.defaultProduct = null;
Factory.prototype.init.call(this, settings);
};
/**
* Defines the object type
* @type {String}
*/
Factory.prototype.type = "Factory";
/**
* Defines the object family
* @type {String}
*/
Factory.prototype.family = "Factory";
/**
* Initializes the object with the default values
* @param {Object} options Contructor options
*/
Factory.prototype.init = function (options) {
var defaults;
if (!options) {
options = {};
}
defaults = {
defaultProduct: options.defaultProduct || "element",
products: options.products || {"element": PMUI.core.Element}
};
this.setDefaultProduct(defaults.defaultProduct)
.setProducts(defaults.products);
};
/**
* Sets the default product property
* @param {String} def Default value
*/
Factory.prototype.setDefaultProduct = function (def) {
this.defaultProduct = def;
return this;
};
/**
* Sets the product object
* @param {Object} products Products object
*/
Factory.prototype.setProducts = function (products) {
this.products = products;
return this;
};
/**
* Removes a product from the factory.
* @param {String|Object} product The product to be removed, it can be:
*
* - a string: the product referenced with that pmType will be removed from factory.
* - a object: the constructor, all the products with that constructor will be removed.
* @return {[type]} [description]
*/
Factory.prototype.removeProduct = function(product) {
var key, products = this.products;
if(typeof product === 'string') {
delete products[product];
} else {
for(key in p