51612 lines
1.7 MiB
51612 lines
1.7 MiB
/**
|
||
* @class PMUI
|
||
* Base class PMUI
|
||
* @singleton
|
||
*/
|
||
var PMUI = {},
|
||
getUsersOS;
|
||
/**
|
||
* Detect the users' OS
|
||
* @return {string}
|
||
*/
|
||
getUsersOS = function () {
|
||
var userAgent = window.navigator.userAgent,
|
||
platform = window.navigator.platform,
|
||
macOsPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'],
|
||
windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'],
|
||
iosPlatforms = ['iPhone', 'iPad', 'iPod'],
|
||
os = null;
|
||
|
||
if (macOsPlatforms.indexOf(platform) !== -1) {
|
||
os = 'MacOS';
|
||
} else if (iosPlatforms.indexOf(platform) !== -1) {
|
||
os = 'iOS';
|
||
} else if (windowsPlatforms.indexOf(platform) !== -1) {
|
||
os = 'Windows';
|
||
} else if (/Android/.test(userAgent)) {
|
||
os = 'Android';
|
||
} else if (!os && /Linux/.test(platform)) {
|
||
os = 'Linux';
|
||
}
|
||
return os;
|
||
};
|
||
|
||
PMUI.version = '0.1.1';
|
||
PMUI.isCtrl = false;
|
||
PMUI.isAlt = false;
|
||
PMUI.isShift = false;
|
||
PMUI.metaKey = false;
|
||
PMUI.activeCanvas = null;
|
||
PMUI.currentContextMenu = null;
|
||
PMUI.keyCodeF5 = 116;
|
||
PMUI.keyDown = false;
|
||
PMUI.isDelete = false;
|
||
PMUI.OS = getUsersOS();
|
||
|
||
$(document).keydown(function (e) {
|
||
var elementSelected,
|
||
flowSelected;
|
||
if (PMUI.activeCanvas) {
|
||
elementSelected = PMUI.activeCanvas.getCurrentSelection();
|
||
flowSelected = PMUI.activeCanvas.getCurrentConnection();
|
||
switch (e.which) {
|
||
case 8: //BACKSPACE
|
||
if (PMUI.metaKey && PMUI.OS === "MacOS" && !PMUI.activeCanvas.readOnly &&
|
||
(elementSelected.asArray().length !== 0 || flowSelected !== null) && !PMUI.isDelete) {
|
||
if (PMUI.activeCanvas && !PMUI.activeCanvas.currentLabel) {
|
||
PMUI.isDelete = true;
|
||
PMUI.activeCanvas.removeElements();
|
||
}
|
||
}
|
||
break;
|
||
case 16: // SHIFT KEY
|
||
PMUI.isShift = true;
|
||
break;
|
||
case 17: // CTRL KEY
|
||
if (!PMUI.isAlt) {
|
||
PMUI.isCtrl = true;
|
||
} else if (PMUI.OS !== "MacOS") {
|
||
PMUI.isAlt = false;
|
||
PMUI.isCtrl = false;
|
||
}
|
||
break;
|
||
case 18: //ALT KEY
|
||
if (!PMUI.isCtrl) {
|
||
PMUI.isAlt = true;
|
||
} else if (PMUI.OS !== "MacOS") {
|
||
PMUI.isCtrl = false;
|
||
PMUI.isAlt = false;
|
||
}
|
||
break;
|
||
case 116: // F5 KEY
|
||
e.preventDefault();
|
||
window.location.reload(true);
|
||
break;
|
||
case 91: //meta key - window key - command key
|
||
PMUI.metaKey = true;
|
||
break;
|
||
case 37:
|
||
// Left
|
||
if (!PMUI.activeCanvas.currentLabel && !PMUI.isDelete) {
|
||
e.preventDefault();
|
||
if (!PMUI.getCoordinatesElement(elementSelected.asArray(), "LEFT")) {
|
||
PMUI.activeCanvas.moveElements(PMUI.activeCanvas, 'LEFT');
|
||
}
|
||
}
|
||
break;
|
||
case 38:
|
||
// Top
|
||
if (!PMUI.activeCanvas.currentLabel && !PMUI.isDelete) {
|
||
e.preventDefault();
|
||
if (!PMUI.getCoordinatesElement(elementSelected.asArray(), "TOP")) {
|
||
PMUI.activeCanvas.moveElements(PMUI.activeCanvas, 'TOP');
|
||
}
|
||
}
|
||
break;
|
||
case 39:
|
||
// Right
|
||
if (!PMUI.activeCanvas.currentLabel && !PMUI.isDelete) {
|
||
e.preventDefault();
|
||
if (!PMUI.getCoordinatesElement(elementSelected.asArray(), "RIGHT")) {
|
||
PMUI.activeCanvas.moveElements(PMUI.activeCanvas, 'RIGHT');
|
||
}
|
||
}
|
||
break;
|
||
case 40:
|
||
// Bottom
|
||
if (!PMUI.activeCanvas.currentLabel && !PMUI.isDelete) {
|
||
e.preventDefault();
|
||
if (!PMUI.getCoordinatesElement(elementSelected.asArray(), "BOTTOM")) {
|
||
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.OS !== "MacOS") || (PMUI.metaKey && PMUI.OS === "MacOS")
|
||
&& !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;
|
||
case 46: //Delete Key - Don't go to default.
|
||
if (!PMUI.isCtrl && !PMUI.isAlt && !PMUI.metaKey && PMUI.activeCanvas && !PMUI.keyDown &&
|
||
!PMUI.activeCanvas.currentLabel && !PMUI.activeCanvas.readOnly && !PMUI.isDelete &&
|
||
(elementSelected.asArray().length !== 0 || flowSelected !== null)) {
|
||
PMUI.isDelete = true;
|
||
PMUI.activeCanvas.removeElements();
|
||
}
|
||
break;
|
||
default:
|
||
PMUI.keyDown = true;
|
||
break;
|
||
}
|
||
}
|
||
}).keypress(function (e) {
|
||
|
||
}).keyup(function (e) {
|
||
var current;
|
||
if (PMUI.activeCanvas) {
|
||
e.preventDefault();
|
||
switch (e.which) {
|
||
case 8: //BACKSPACE
|
||
if (PMUI.metaKey && PMUI.OS === "MacOS" && !PMUI.activeCanvas.readOnly) {
|
||
if (PMUI.activeCanvas && !PMUI.activeCanvas.currentLabel) {
|
||
PMUI.activeCanvas.removeElements();
|
||
}
|
||
}
|
||
break;
|
||
case 13: // ENTER
|
||
if (PMUI.activeCanvas && PMUI.activeCanvas.currentLabel) {
|
||
PMUI.activeCanvas.currentLabel.loseFocus();
|
||
}
|
||
PMUI.keyDown = false;
|
||
break;
|
||
case 91: // META KEY
|
||
PMUI.metaKey = false;
|
||
break;
|
||
case 16: // SHIFT KEY
|
||
PMUI.isShift = false;
|
||
break;
|
||
case 17: //CTRL KEY
|
||
PMUI.isCtrl = false;
|
||
break;
|
||
case 18: //ALT KEY
|
||
PMUI.isAlt = false;
|
||
break;
|
||
case 46:
|
||
//PMUI.isDelete = 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;
|
||
default:
|
||
PMUI.keyDown = false;
|
||
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]) {
|
||
}
|
||
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.util.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 += 1) {
|
||
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;
|
||
|
||
if (!Array.prototype.indexOf) {
|
||
Array.prototype.indexOf = function (elt /*, from*/) {
|
||
var len = this.length >>> 0;
|
||
|
||
var from = Number(arguments[1]) || 0;
|
||
from = (from < 0)
|
||
? Math.ceil(from)
|
||
: Math.floor(from);
|
||
if (from < 0)
|
||
from += len;
|
||
|
||
for (; from < len; from += 1) {
|
||
if (from in this &&
|
||
this[from] === elt)
|
||
return from;
|
||
}
|
||
return -1;
|
||
};
|
||
}
|
||
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");
|
||
}
|
||
};
|
||
/**
|
||
* validates that the items do not leave the parent container
|
||
* @param elements array of items selecteds
|
||
* @param direction string of cursor key
|
||
* @returns {boolean}
|
||
*/
|
||
PMUI.getCoordinatesElement = function (elements, direction) {
|
||
var element,
|
||
factorPixel,
|
||
swError,
|
||
factorZoom,
|
||
ParentPoints,
|
||
ShapePoints,
|
||
limitTop,
|
||
limitRight,
|
||
limitBottom,
|
||
limitLeft;
|
||
|
||
swError = false;
|
||
if (elements.length > 0) {
|
||
if (elements[0].parent.parent !== null) {
|
||
element = elements[0];
|
||
factorPixel = [4, 4, 4, 2];
|
||
factorZoom = element.getCanvas().getZoomFactor();
|
||
ParentPoints = PMUI.getCoordenatesParent(element.parent, factorZoom);
|
||
ShapePoints = PMUI.getAbsoluteShape(elements, factorZoom);
|
||
limitTop = ParentPoints.PInit.getY() + (factorPixel[0] * factorZoom);
|
||
limitRight = ParentPoints.PFinal.getX() - (factorPixel[1] * factorZoom);
|
||
limitBottom = ParentPoints.PFinal.getY() - (factorPixel[2] * factorZoom);
|
||
limitLeft = ParentPoints.PInit.getX() + (factorPixel[3] * factorZoom);
|
||
switch (direction) {
|
||
case 'TOP':
|
||
if (limitTop > ShapePoints.PInit.getY()) {
|
||
swError = true;
|
||
}
|
||
break;
|
||
case 'RIGHT':
|
||
if (limitRight < ShapePoints.PFinal.getX()) {
|
||
swError = true;
|
||
}
|
||
break;
|
||
case 'BOTTOM':
|
||
if (limitBottom < ShapePoints.PFinal.getY()) {
|
||
swError = true;
|
||
}
|
||
break;
|
||
case 'LEFT':
|
||
if (limitLeft > ShapePoints.PInit.getX()) {
|
||
swError = true;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
return swError;
|
||
};
|
||
/**
|
||
* Get the parent coordenates
|
||
* @param parent Object parent of the item selected
|
||
* @param factorZoom
|
||
* @returns {Object of Objects Point}
|
||
*/
|
||
PMUI.getCoordenatesParent = function (parent, factorZoom) {
|
||
var coordenatesParent,
|
||
xInit,
|
||
yInit,
|
||
xFinal,
|
||
yFinal,
|
||
pointInit,
|
||
pointFinal,
|
||
headParent;
|
||
|
||
headParent = 0;
|
||
if (parent.type === "PMPool") {
|
||
headParent = parent.headLineCoord * factorZoom;
|
||
}
|
||
xInit = parent.getAbsoluteX() + headParent;
|
||
yInit = parent.getAbsoluteY();
|
||
xFinal = parent.getAbsoluteX() + (parent.getWidth() * factorZoom);
|
||
yFinal = parent.getAbsoluteY() + (parent.getHeight() * factorZoom);
|
||
pointInit = new PMUI.util.Point(xInit, yInit);
|
||
pointFinal = new PMUI.util.Point(xFinal, yFinal);
|
||
coordenatesParent = {
|
||
"PInit": pointInit,
|
||
"PFinal": pointFinal
|
||
};
|
||
|
||
return coordenatesParent;
|
||
};
|
||
/**
|
||
* Get coordenates min y max of the items selecteds
|
||
* @param shapes Array of items selecteds
|
||
* @param factorZoom
|
||
* @returns {Object of Objects Point}
|
||
*/
|
||
PMUI.getAbsoluteShape = function (shapes, factorZoom) {
|
||
var coordenatesShapeAux,
|
||
coordenatesShape,
|
||
arrayShapesAux = [],
|
||
pointShapeInit,
|
||
pointShapeFinal,
|
||
shape,
|
||
xFinalAux,
|
||
yFinalAux,
|
||
i;
|
||
|
||
for (i = 0; i < shapes.length; i += 1) {
|
||
shape = shapes[i];
|
||
xFinalAux = shape.getAbsoluteX() + (shape.getWidth() * factorZoom);
|
||
yFinalAux = shape.getAbsoluteY() + (shape.getHeight() * factorZoom);
|
||
pointShapeInit = new PMUI.util.Point(shape.getAbsoluteX(), shape.getAbsoluteY());
|
||
pointShapeFinal = new PMUI.util.Point(xFinalAux, yFinalAux);
|
||
coordenatesShapeAux = {
|
||
"PInit": pointShapeInit,
|
||
"PFinal": pointShapeFinal
|
||
};
|
||
arrayShapesAux.push(coordenatesShapeAux);
|
||
}
|
||
coordenatesShape = PMUI.getMinMaxCoordenates(arrayShapesAux);
|
||
return coordenatesShape;
|
||
};
|
||
/**
|
||
* Get the Min y Max coordenates of a array of Objects Point
|
||
* @param coordenates array of Objects Point
|
||
* @returns {Object of Objects Point}
|
||
*/
|
||
PMUI.getMinMaxCoordenates = function (coordenates) {
|
||
var objectCoordenates,
|
||
xInit,
|
||
yInit,
|
||
xFinal,
|
||
yFinal,
|
||
j;
|
||
|
||
xInit = coordenates[0].PInit.getX();
|
||
yInit = coordenates[0].PInit.getY();
|
||
xFinal = coordenates[0].PFinal.getX();
|
||
yFinal = coordenates[0].PFinal.getY();
|
||
|
||
for (j = 0; j < coordenates.length; j += 1) {
|
||
if (coordenates[j].PInit.getX() < xInit) {
|
||
xInit = coordenates[j].PInit.getX();
|
||
}
|
||
if (coordenates[j].PInit.getY() < yInit) {
|
||
yInit = coordenates[j].PInit.getY();
|
||
}
|
||
if (coordenates[j].PFinal.getX() > xFinal) {
|
||
xFinal = coordenates[j].PFinal.getX();
|
||
}
|
||
if (coordenates[j].PFinal.getY() > yFinal) {
|
||
yFinal = coordenates[j].PFinal.getY();
|
||
}
|
||
}
|
||
|
||
objectCoordenates = {
|
||
"PInit": new PMUI.util.Point(xInit, yInit),
|
||
"PFinal": new PMUI.util.Point(xFinal, yFinal)
|
||
};
|
||
|
||
return objectCoordenates;
|
||
};
|
||
|
||
PMUI.isInDOM = function (html) {
|
||
var targetHTML = html instanceof PMUI.core.Element ? html.html : html,
|
||
aux;
|
||
|
||
if (targetHTML === null) {
|
||
return false;
|
||
} else if (!PMUI.isHTMLElement(targetHTML)) {
|
||
throw new Error('isInDOM(): invalid parameter, only HTML or instance of PMUI.core.Element are allowed.');
|
||
}
|
||
|
||
aux = jQuery(html).parents('html')[0];
|
||
return !!aux && aux.parentNode === document;
|
||
};
|
||
|
||
String.prototype.capitalize = function () {
|
||
return this.toLowerCase().replace(/(^|\s)([a-z])/g, function (m, p1, p2) {
|
||
return p1 + p2.toUpperCase();
|
||
});
|
||
};
|
||
|
||
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);
|
||
// },
|
||
|
||
sort: function (compFunction) {
|
||
var returnValue = false;
|
||
|
||
if (compFunction) {
|
||
elements.sort(compFunction);
|
||
returnValue = true;
|
||
}
|
||
return returnValue;
|
||
},
|
||
/**
|
||
* Bubble sort function in array
|
||
* @param {*} compFunction
|
||
* @return {Array}
|
||
*/
|
||
bubbleSort: function (compFunction) {
|
||
var inputArr = elements,
|
||
i,
|
||
tmp,
|
||
len = inputArr.length,
|
||
swapped;
|
||
do {
|
||
swapped = false;
|
||
for (i = 0; i < len; i++) {
|
||
if (inputArr[i] && inputArr[i + 1] && compFunction(inputArr[i], inputArr[i + 1])) {
|
||
tmp = inputArr[i];
|
||
inputArr[i] = inputArr[i + 1];
|
||
inputArr[i + 1] = tmp;
|
||
swapped = true;
|
||
}
|
||
}
|
||
} while (swapped);
|
||
elements = inputArr;
|
||
return elements;
|
||
},
|
||
/**
|
||
* 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 () {
|
||
var i,
|
||
t,
|
||
class_i;
|
||
|
||
if (!this.belongsTo.html) {
|
||
throw new Error("applyStyle(): can't apply style to an" +
|
||
" object with no html.");
|
||
}
|
||
|
||
// 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 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
|
||
};
|
||
};
|
||
|
||
// 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 products) {
|
||
if (products[key] === product) {
|
||
delete products[key];
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes all the productrs from the factory.
|
||
* @chainable
|
||
*/
|
||
Factory.prototype.clearProducts = function () {
|
||
var key;
|
||
|
||
for (key in this.products) {
|
||
this.removeProduct(key);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Register a new product into the products object
|
||
* @param {String} name Product type
|
||
* @param {Object} classObj Product Class
|
||
* @chainable
|
||
*/
|
||
Factory.prototype.register = function (name, classObj) {
|
||
var aux = this.products || {};
|
||
|
||
aux[name] = classObj;
|
||
this.products = aux;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Retuns a new instance (product)
|
||
* @param {String} type Product type
|
||
* @param {Object} options Settings object
|
||
* @return {Object} Instance of the object
|
||
*/
|
||
Factory.prototype.build = function (type, options) {
|
||
var Constructor,
|
||
instance;
|
||
|
||
if (this.isValidName(type)) {
|
||
Constructor = this.products[type];
|
||
instance = new Constructor(options);
|
||
} else {
|
||
throw new Error('The type "' + type + '" has not valid constructor or is undefined.');
|
||
}
|
||
return instance;
|
||
};
|
||
|
||
/**
|
||
* Retuns true if the type is valid into the products object
|
||
* @param {String} name Product Name
|
||
* @return {Boolean}
|
||
*/
|
||
Factory.prototype.isValidName = function (name) {
|
||
var test = this.products[name];
|
||
|
||
return !!test;
|
||
};
|
||
|
||
/**
|
||
* Returns true if the class input is instance of one class into the product object
|
||
* @param {Object} className [description]
|
||
* @return {Boolean} [description]
|
||
*/
|
||
Factory.prototype.isValidClass = function (className) {
|
||
var valid = false;
|
||
|
||
jQuery.each(this.products, function (type, classProduct) {
|
||
if (className instanceof classProduct) {
|
||
valid = true;
|
||
}
|
||
});
|
||
return valid;
|
||
};
|
||
|
||
|
||
/**
|
||
* Comprobes the obj in and returns the instance of the object
|
||
* @param {Object} obj Input can be an isntance or an object with the pmType property or simply a JSON
|
||
* @return {Object} Returns an instance made from the products object.
|
||
*/
|
||
Factory.prototype.make = function (obj) {
|
||
var product,
|
||
productType = obj.pmType || '';
|
||
|
||
if (this.isValidClass(obj)) {
|
||
product = obj;
|
||
} else if (this.isValidName(productType)) {
|
||
product = this.build.call(this, productType, obj);
|
||
} else {
|
||
product = this.build.call(this, this.defaultProduct, obj);
|
||
}
|
||
return product;
|
||
};
|
||
|
||
//Create a namespace for Factory class
|
||
PMUI.extendNamespace('PMUI.util.Factory', Factory);
|
||
|
||
// Publish to NodeJS environment
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Factory;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.util.Color
|
||
* This class holds the representation and operations of RGBa representation of color,
|
||
* it's very useful if we want to save color constants as an instance and later get the representation
|
||
* in CSS.
|
||
*
|
||
* //e.g.
|
||
* var color = new PMUI.util.Color(
|
||
* 128, // red
|
||
* 128, // green
|
||
* 128, // blue
|
||
* 1 // opacity
|
||
* )
|
||
*
|
||
* @constructor Creates an instance of this class.
|
||
* @param {number} red
|
||
* @param {number} green
|
||
* @param {number} blue
|
||
* @param {number} opacity
|
||
* @return {PMUI.util.Color}
|
||
*/
|
||
var Color = function (red, green, blue, opacity) {
|
||
/**
|
||
* Red value of the RGB Color
|
||
* @property {number} [red=0]
|
||
*/
|
||
this.red = (!red) ? 0 : red;
|
||
/**
|
||
* Green value of the RGB Color
|
||
* @property {number} [green=0]
|
||
*/
|
||
this.green = (!green) ? 0 : green;
|
||
/**
|
||
* Blue value of the RGB Color
|
||
* @property {number} [blue=0]
|
||
*/
|
||
this.blue = (!blue) ? 0 : blue;
|
||
/**
|
||
* Opacity of the RGB Color
|
||
* @property {number} [opacity=1]
|
||
*/
|
||
this.opacity = (!opacity) ? 1 : opacity;
|
||
};
|
||
|
||
/**
|
||
* Type of this class
|
||
* @property {String}
|
||
*/
|
||
Color.prototype.type = "Color";
|
||
|
||
/**
|
||
* Constant for the color grey
|
||
* @property {PMUI.util.Color} [GREY=new Color(192, 192, 192, 1)]
|
||
*/
|
||
Color.GREY = new Color(192, 192, 192, 1);
|
||
|
||
/**
|
||
* Returns the red value of the RGB Color
|
||
* @returns {number}
|
||
*/
|
||
Color.prototype.getRed = function () {
|
||
return this.red;
|
||
};
|
||
|
||
/**
|
||
* Returns the green value of the RGB Color
|
||
* @returns {number}
|
||
*/
|
||
Color.prototype.getGreen = function () {
|
||
return this.green;
|
||
};
|
||
|
||
/**
|
||
* Returns the blue value of the RGB Color
|
||
* @returns {number}
|
||
*/
|
||
Color.prototype.getBlue = function () {
|
||
return this.blue;
|
||
};
|
||
|
||
/**
|
||
* Returns the opacity of the RGB Color
|
||
* @returns {number}
|
||
*/
|
||
Color.prototype.getOpacity = function () {
|
||
return this.opacity;
|
||
};
|
||
|
||
/**
|
||
* Sets the red value of the RGB Color
|
||
* @param {number} newRed
|
||
* @chainable
|
||
*/
|
||
Color.prototype.setRed = function (newRed) {
|
||
if (typeof newRed === "number" && newRed >= 0 && newRed <= 255) {
|
||
this.red = newRed;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the green value of the RGB Color
|
||
* @param {number} newRed
|
||
* @chainable
|
||
*/
|
||
Color.prototype.setGreen = function (newGreen) {
|
||
if (typeof newGreen === "number" && newGreen >= 0 && newGreen <= 255) {
|
||
this.green = newGreen;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the blue value of the RGB Color
|
||
* @param {number} newBlue
|
||
* @chainable
|
||
*/
|
||
Color.prototype.setBlue = function (newBlue) {
|
||
if (typeof newBlue === "number" && newBlue >= 0 && newBlue <= 255) {
|
||
this.blue = newBlue;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the opacity of the RGB Color
|
||
* @param {number} newOpacity
|
||
* @chainable
|
||
*/
|
||
Color.prototype.setOpacity = function (newOpacity) {
|
||
if (typeof newOpacity === "number" && newOpacity >= 0 && newOpacity <= 255) {
|
||
this.opacity = newOpacity;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the css representation of the RGB color
|
||
* //e.g.
|
||
* var color = new PMUI.util.Color(10, 20, 30, 0.1);
|
||
* color.getCSS(); // "rgba(10, 20, 30, 0.1)"
|
||
* @returns {String}
|
||
*/
|
||
Color.prototype.getCSS = function () {
|
||
var css = "rgba(" + this.red + "," + this.green + "," + this.blue +
|
||
"," + this.opacity + ")";
|
||
return css;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.util.Color', Color);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.util.Point
|
||
* Class to represent points in the PMDraw library
|
||
*
|
||
* // e.g.
|
||
* var p = new PMUI.util.Point(100, 100);
|
||
*
|
||
* @constructor Creates an instance of this class
|
||
* @param {number} xCoordinate x-coordinate of the point
|
||
* @param {number} yCoordinate y-coordinate of the point
|
||
* @return {PMUI.util.Point}
|
||
*/
|
||
var Point = function (xCoordinate, yCoordinate) {
|
||
/**
|
||
* x coordinate of the point in the plane
|
||
*/
|
||
this.x = xCoordinate;
|
||
/**
|
||
* y coordinate of the point in the plane
|
||
*/
|
||
this.y = yCoordinate;
|
||
};
|
||
|
||
/**
|
||
* Type of this class
|
||
* @property {String}
|
||
*/
|
||
Point.prototype.type = "Point";
|
||
|
||
/**
|
||
* Returns the X coordinate
|
||
* @property {number}
|
||
**/
|
||
Point.prototype.getX = function () {
|
||
return this.x;
|
||
};
|
||
|
||
/**
|
||
* Returns the Y coordinate
|
||
* @property {number}
|
||
**/
|
||
Point.prototype.getY = function () {
|
||
return this.y;
|
||
};
|
||
|
||
/**
|
||
* Adds `other` point to `this` point and returns a new point with those coordinates.
|
||
*
|
||
* // e.g.
|
||
* var p1 = new PMUI.util.Point(3, 5),
|
||
* p2 = new PMUI.util.Point(2, 3);
|
||
* p1.add(p2); // new Point(5, 8)
|
||
*
|
||
* @param {PMUI.util.Point} other Point to be added to the current point
|
||
* @returns {PMUI.util.Point}
|
||
*/
|
||
Point.prototype.add = function (other) {
|
||
return new Point(this.x + other.x, this.y + other.y);
|
||
};
|
||
|
||
/**
|
||
* Subtracts the other point to the one that called the function.
|
||
*
|
||
* // e.g.
|
||
* var p1 = new PMUI.util.Point(3, 5),
|
||
* p2 = new PMUI.util.Point(2, 3);
|
||
* p1.subtract(p2); // new Point(1, 2)
|
||
*
|
||
* @param {PMUI.util.Point} other Point to be added to the current point
|
||
* @returns {PMUI.util.Point}
|
||
*/
|
||
Point.prototype.subtract = function (other) {
|
||
return new Point(this.x - other.x, this.y - other.y);
|
||
};
|
||
|
||
/**
|
||
* Multiplies the point with a scalar k.
|
||
*
|
||
* // e.g.
|
||
* var p1 = new PMUI.util.Point(3, 5),
|
||
* k = 3;
|
||
* p1.multiply(k); // new Point(9, 15)
|
||
*
|
||
* @param {number} k
|
||
* @return {PMUI.util.Point}
|
||
*/
|
||
Point.prototype.multiply = function (k) {
|
||
return new Point(this.x * k, this.y * k);
|
||
};
|
||
|
||
/**
|
||
* Determine if the points are equal.
|
||
*
|
||
* // e.g.
|
||
* var p1 = new PMUI.util.Point(3, 5),
|
||
* p2 = new PMUI.util.Point(2, 3),
|
||
* p3 = new PMUI.util.Point(3, 5);
|
||
* p1.equals(p2); // false
|
||
* p1.equals(p3); // true
|
||
* p1.equals(p1); // true
|
||
*
|
||
* @param {PMUI.util.Point} other Point to be compared with the current point
|
||
* @returns {boolean}
|
||
*/
|
||
Point.prototype.equals = function (other) {
|
||
return (Math.abs(this.x - other.x) < PMUI.draw.Geometry.eps) &&
|
||
(Math.abs(this.y - other.y) < PMUI.draw.Geometry.eps);
|
||
};
|
||
|
||
/**
|
||
* Determine the distance between two Points
|
||
*
|
||
* // e.g.
|
||
* // distance = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2))
|
||
* var p1 = new PMUI.util.Point(3, 5),
|
||
* p2 = new PMUI.util.Point(2, 3);
|
||
* p1.getDistance(p2); // sqrt(1 + 4)
|
||
*
|
||
* @param {PMUI.util.Point} other Point to be calculated from current point
|
||
* @returns {number}
|
||
**/
|
||
Point.prototype.getDistance = function (other) {
|
||
return Math.sqrt(
|
||
(this.x - other.x) * (this.x - other.x) +
|
||
(this.y - other.y) * (this.y - other.y)
|
||
);
|
||
};
|
||
|
||
/**
|
||
* Determine the squared distance between two Points
|
||
*
|
||
* // e.g.
|
||
* // distance = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2))
|
||
* // but since it's the squared distance then
|
||
* // distance = pow(distance, 2)
|
||
* var p1 = new PMUI.util.Point(3, 5),
|
||
* p2 = new PMUI.util.Point(2, 3);
|
||
* p1.getSquaredDistance(p2); // (1 + 4)
|
||
*
|
||
* @param {PMUI.util.Point} other Point to be calculated from current point
|
||
* @returns {number}
|
||
**/
|
||
Point.prototype.getSquaredDistance = function (other) {
|
||
return (this.x - other.x) * (this.x - other.x) +
|
||
(this.y - other.y) * (this.y - other.y);
|
||
};
|
||
|
||
/**
|
||
* Determine the manhattan distance between two Points
|
||
*
|
||
* // e.g.
|
||
* var p1 = new PMUI.util.Point(3, 5),
|
||
* p2 = new PMUI.util.Point(2, 3);
|
||
* p1.getManhattanDistance(p2); // (1 + 2)
|
||
*
|
||
* @param {PMUI.util.Point} other Point to be calculated from current point
|
||
* @returns {number}
|
||
**/
|
||
Point.prototype.getManhattanDistance = function (other) {
|
||
return Math.abs(this.x - other.x) + Math.abs(this.y - other.y);
|
||
};
|
||
|
||
/**
|
||
* Makes a clone of this
|
||
*
|
||
* // e.g.
|
||
* var p1 = new PMUI.util.Point(3, 5),
|
||
* cloneP1;
|
||
* cloneP1 = p1.clone(); // cloneP1 is Point(3, 5)
|
||
*
|
||
* @returns {PMUI.util.Point} This point
|
||
*/
|
||
Point.prototype.clone = function () {
|
||
return new Point(this.x, this.y);
|
||
};
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Point;
|
||
}
|
||
|
||
// extend namespace
|
||
PMUI.extendNamespace('PMUI.util.Point', Point);
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Graphics
|
||
* Class Graphics is the HTMLElement drawing engine used to draw lines (as HTMLElement divs),
|
||
* arcs (using HTMLElement divs) and ovals.
|
||
* Currently some elements in the designer are completely represented with the drawing engine:
|
||
*
|
||
* - Connection => a set of segments (regular, segmented, dotted)
|
||
* - Port => oval
|
||
* - Intersection => arc
|
||
*
|
||
* Some important notes:
|
||
*
|
||
* - Currently this class acts as an interface between the library **PMDraw** and the HTMLElement
|
||
* drawing engine wz_jsGraphics
|
||
* - The drawing engine constructor needs the HTMLElement where it will go as a parameter **(this
|
||
* HTMLElement must exist in the DOM)**
|
||
*
|
||
* @constructor
|
||
* Creates an instance of this class (currently it's an interface of the wz_graphics framework)
|
||
* @param {Object} html This parameter can be either an id, or an html object
|
||
*/
|
||
var Graphics = function (html) {
|
||
|
||
if (!html) {
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Create an instance of the class JSGraphics (this.graphics is an interface)
|
||
* @type {Object}
|
||
*/
|
||
this.graphics = new JSGraphics(html);
|
||
|
||
/**
|
||
* Creates an instance of the class Color (color black)
|
||
* @type {PMUI.util.Color}
|
||
*/
|
||
this.color = new PMUI.util.Color(0, 0, 0);
|
||
};
|
||
|
||
/**
|
||
* Draws a line of a given type between two points.
|
||
*
|
||
* @param {number} x1
|
||
* @param {number} y1
|
||
* @param {number} x2
|
||
* @param {number} y2
|
||
* @param {string} type the type of line we wish to draw
|
||
* @param {PMUI.util.Color} color The color of the segment
|
||
* @param {number} segLength the segment length for segmented and segmentdot type of line
|
||
* @param {number} spaceLength the space length for segmented and segmentdot type of line
|
||
* @param {boolean} [doNotErasePrevious] if set to true then it won't clear the elements drew with this instance
|
||
*/
|
||
Graphics.prototype.drawLine = function (x1, y1, x2, y2, type, color, segLength, spaceLength, doNotErasePrevious) {
|
||
|
||
if (!doNotErasePrevious) {
|
||
this.graphics.clear();
|
||
}
|
||
|
||
if (!type) {
|
||
type = "regular";
|
||
}
|
||
switch (type) {
|
||
case "dotted":
|
||
this.graphics.setStroke(-1);
|
||
break;
|
||
case "segmented":
|
||
this.graphics.setStroke(1);
|
||
this.graphics.drawLine = this.makeSegmentedLine;
|
||
break;
|
||
case "segmentdot":
|
||
this.graphics.setStroke(1);
|
||
this.graphics.drawLine = this.makeSegmentDotLine;
|
||
break;
|
||
default:
|
||
this.graphics.setStroke(1);
|
||
}
|
||
|
||
this.graphics.setColor(color.getCSS());
|
||
this.graphics.drawLine(x1, y1, x2, y2, segLength, spaceLength);
|
||
this.graphics.paint();
|
||
|
||
};
|
||
|
||
/**
|
||
* Returns the color that was being used for drawing
|
||
* @returns {PMUI.util.Color}
|
||
*/
|
||
Graphics.prototype.getColor = function () {
|
||
return this.color;
|
||
};
|
||
|
||
/**
|
||
* Sets the color to be used for drawing
|
||
* @param newColor
|
||
* @chainable
|
||
*/
|
||
Graphics.prototype.setColor = function (newColor) {
|
||
if (newColor.type === "Color") {
|
||
this.color = newColor;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* This function will make a segmented line between two points in the same axis,
|
||
* if points in different axis are provided the method would simple return
|
||
*
|
||
* @param {number} x1
|
||
* @param {number} y1
|
||
* @param {number} x2
|
||
* @param {number} y2
|
||
* @param {number} segmentLength the segment length for segmented and
|
||
* segmentdot type of line
|
||
* @param {number} spLength the space length for segmented and
|
||
* segmentdot type of line
|
||
*/
|
||
Graphics.prototype.makeSegmentedLine = function (x1, y1, x2, y2, segmentLength, spLength) {
|
||
var dx,
|
||
dy,
|
||
aux,
|
||
segLength = 4,
|
||
spaceLength = 3,
|
||
diff = 0,
|
||
x,
|
||
y;
|
||
|
||
//not same axis so just return
|
||
if ((x2 !== x1 && y2 !== y1)) {
|
||
return;
|
||
}
|
||
|
||
if (x2 === x1) {
|
||
//same point just return
|
||
if (y2 === y1) {
|
||
return;
|
||
}
|
||
dx = 0;
|
||
//swap
|
||
if (y2 < y1) {
|
||
aux = y2;
|
||
y2 = y1;
|
||
y1 = aux;
|
||
}
|
||
dy = diff = y2 - y1;
|
||
} else {
|
||
dy = 0;
|
||
if (x2 < x1) {
|
||
aux = x2;
|
||
x2 = x1;
|
||
x1 = aux;
|
||
}
|
||
dx = diff = x2 - x1;
|
||
}
|
||
|
||
x = x1;
|
||
y = y1;
|
||
|
||
if (diff < 7) {
|
||
segLength = 2;
|
||
spaceLength = 1;
|
||
}
|
||
|
||
segLength = (!segmentLength) ? segLength : segmentLength;
|
||
spaceLength = (!spLength) ? spaceLength : spLength;
|
||
|
||
if (dy === 0) {
|
||
while (dx > 0) {
|
||
if (dx >= segLength) {
|
||
this._mkDiv(x, y, segLength, 1);
|
||
x += segLength + spaceLength;
|
||
dx -= (segLength + spaceLength);
|
||
} else {
|
||
this._mkDiv(x, y, dx, 1);
|
||
dx = 0;
|
||
}
|
||
}
|
||
} else {
|
||
while (dy > 0) {
|
||
if (dy >= segLength) {
|
||
this._mkDiv(x, y, 1, segLength);
|
||
y += segLength + spaceLength;
|
||
dy -= (segLength + spaceLength);
|
||
} else {
|
||
this._mkDiv(x, y, 1, dy);
|
||
dy = 0;
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* This function will make a segment between two points in the same axis with
|
||
* the following structure segment-dot-segment
|
||
* if points in different axis are provided the function will simply return.
|
||
*
|
||
* @param {number} x1
|
||
* @param {number} y1
|
||
* @param {number} x2
|
||
* @param {number} y2
|
||
* @param {number} segmentLength the segment length for segmented and
|
||
* segmentdot type of line
|
||
* @param {number} spLength the space length for segmented and
|
||
* segmentdot type of line
|
||
*/
|
||
|
||
Graphics.prototype.makeSegmentDotLine = function (x1, y1, x2, y2, segmentLength, spLength) {
|
||
var dx,
|
||
dy,
|
||
aux,
|
||
segLength = 7,
|
||
spaceLength = 4,
|
||
dotLength = 1,
|
||
diff = 0,
|
||
x,
|
||
y;
|
||
|
||
//not same axis so just return
|
||
if ((x2 !== x1 && y2 !== y1)) {
|
||
return;
|
||
}
|
||
|
||
|
||
if (x2 === x1) {
|
||
//same point just return
|
||
if (y2 === y1) {
|
||
return;
|
||
}
|
||
dx = 0;
|
||
//swap
|
||
if (y2 < y1) {
|
||
aux = y2;
|
||
y2 = y1;
|
||
y1 = aux;
|
||
}
|
||
dy = y2 - y1;
|
||
diff = dy;
|
||
} else {
|
||
dy = 0;
|
||
if (x2 < x1) {
|
||
aux = x2;
|
||
x2 = x1;
|
||
x1 = aux;
|
||
}
|
||
dx = x2 - x1;
|
||
diff = dx;
|
||
}
|
||
|
||
x = x1;
|
||
y = y1;
|
||
|
||
segLength = (!segmentLength) ? segLength : segmentLength;
|
||
spaceLength = (!spLength) ? spaceLength : spLength;
|
||
|
||
if (dy === 0) {
|
||
while (dx > 0) {
|
||
if (dx >= segLength) {
|
||
this._mkDiv(x, y, segLength, 1);
|
||
dx -= (segLength + spaceLength);
|
||
x += segLength + spaceLength;
|
||
if (dx > 0) {
|
||
this._mkDiv(x, y, dotLength, 1);
|
||
dx -= (dotLength + spaceLength);
|
||
x += dotLength + spaceLength;
|
||
}
|
||
} else {
|
||
this._mkDiv(x, y, dx, 1);
|
||
dx = 0;
|
||
}
|
||
}
|
||
} else {
|
||
while (dy > 0) {
|
||
if (dy >= segLength) {
|
||
this._mkDiv(x, y, 1, segLength);
|
||
dy -= (segLength + spaceLength);
|
||
y += segLength + spaceLength;
|
||
if (dy > 0) {
|
||
this._mkDiv(x, y, 1, dotLength);
|
||
dy -= (dotLength + spaceLength);
|
||
y += dotLength + spaceLength;
|
||
|
||
}
|
||
} else {
|
||
this._mkDiv(x, y, 1, dy);
|
||
dy = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
};
|
||
/**
|
||
* Draws an arc with the center `[cx, cy]`, with a radius equal to `radius` from `startAngle` to `endAngle`
|
||
* and drawing a line every `step` steps.
|
||
* Logic:
|
||
*
|
||
* 1. Let's assume that we have a circle with center `[cx, cy]` and with a radius equal to `radius`
|
||
* 2. We want to draw only a portion of the circle (from `startAngle` to `endAngle`)
|
||
* 3. Given any angle of the circle `0 <= angle < 360` we can get its `x` and `y` coordinates using
|
||
* Pythagoras triangle rectangle laws.
|
||
* - We know that `hyp^2 = dx^2 + dy^2` and that `hyp = radius`
|
||
* - We know that `cos(angle) = dx / radius` so `dx = radius * cos(angle)`
|
||
* - We know that `sin(angle) = dy / radius` so `dx = radius * cos(angle)`
|
||
* 4. Finally let's use the given center of the circle to move the triangle
|
||
*
|
||
* @param {number} cx
|
||
* @param {number} cy
|
||
* @param {number} radius
|
||
* @param {number} startAngle
|
||
* @param {number} endAngle
|
||
* @param {number} step
|
||
*/
|
||
Graphics.prototype.drawArc = function (cx, cy, radius, startAngle, endAngle, step) {
|
||
var x,
|
||
y,
|
||
angle = startAngle;
|
||
|
||
if (!step) {
|
||
step = 10;
|
||
}
|
||
|
||
while (Math.abs(angle - endAngle) > 1e-5) {
|
||
angle = (angle + step) % 360;
|
||
x = cx + radius * Math.cos(angle * PMUI.draw.Geometry.pi / 180.0);
|
||
y = cy + radius * Math.sin(angle * PMUI.draw.Geometry.pi / 180.0);
|
||
this.graphics.drawLine(x, y, x, y);
|
||
}
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Graphics', Graphics);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Geometry
|
||
* A little object that encapsulates most geometry functions used in the designer, most of the examples
|
||
* are in 'spec/draw/geometry.spec.js'
|
||
*
|
||
* @singleton
|
||
*/
|
||
var Geometry = {
|
||
/**
|
||
* The number pi
|
||
* @property {number} [pi=Math.acos(-1)]
|
||
*/
|
||
pi: Math.acos(-1),
|
||
/**
|
||
* Epsilon used for the correctness in comparison of float numbers
|
||
* @property {number} [eps=1e-8]
|
||
*/
|
||
eps: 1e-8,
|
||
/**
|
||
* Calculates the cross product of 2-dimensional vectors
|
||
* @param {PMUI.util.Point} p1
|
||
* @param {PMUI.util.Point} p2
|
||
* @return {number}
|
||
*/
|
||
cross: function (p1, p2) {
|
||
return p1.x * p2.y - p1.y * p2.x;
|
||
},
|
||
/**
|
||
* Calculates the SIGNED area of a parallelogram given three points, these three points are the points
|
||
* that conforms the triangle that is half of the parallelogram, so. the area of the triangle
|
||
* defined with these points is half the returned number (this method can return negative values)
|
||
*
|
||
* // e.g.
|
||
* var p1 = new PMUI.util.Point(0, 0),
|
||
* p2 = new PMUI.util.Point(0, 1),
|
||
* p3 = new PMUI.util.Point(1, 0),
|
||
* parallelogramArea,
|
||
* triangleArea;
|
||
*
|
||
* parallelogramArea = Geometry.area(p1, p2, p3) // -1 (area of the parallelogram)
|
||
* triangleArea = parallelogramArea / 2 // -0.5 (area of the triangle)
|
||
*
|
||
* @param {PMUI.util.Point} p1
|
||
* @param {PMUI.util.Point} p2
|
||
* @param {PMUI.util.Point} p3
|
||
* @return {number}
|
||
*/
|
||
area: function (p1, p2, p3) {
|
||
var auxP2 = p2.clone(),
|
||
auxP3 = p3.clone();
|
||
return this.cross(auxP2.subtract(p1), auxP3.subtract(p1));
|
||
},
|
||
/**
|
||
* Determines if the point P is on segment AB
|
||
* @param {PMUI.util.Point} P
|
||
* @param {PMUI.util.Point} A
|
||
* @param {PMUI.util.Point} B
|
||
* @return {boolean}
|
||
*/
|
||
onSegment: function (P, A, B) {
|
||
return (Math.abs(this.area(A, B, P)) < this.eps &&
|
||
P.x >= Math.min(A.x, B.x) && P.x <= Math.max(A.x, B.x) &&
|
||
P.y >= Math.min(A.y, B.y) && P.y <= Math.max(A.y, B.y));
|
||
},
|
||
/**
|
||
* Checks if two perpendicular segments intersect, if so it returns the intersection point,
|
||
* (this method only allows the perpendicular segment to be parallel to the x and y axis)
|
||
* @param {PMUI.util.Point} A
|
||
* @param {PMUI.util.Point} B
|
||
* @param {PMUI.util.Point} C
|
||
* @param {PMUI.util.Point} D
|
||
* @return {Object}
|
||
*/
|
||
perpendicularSegmentIntersection: function (A, B, C, D) {
|
||
var clone,
|
||
returnValue = null;
|
||
|
||
// swap the segments if possible
|
||
if (A.x > B.x || A.y > B.y) {
|
||
clone = A.clone();
|
||
A = B.clone();
|
||
B = clone;
|
||
}
|
||
|
||
if (C.x > D.x || C.y > D.y) {
|
||
clone = C.clone();
|
||
C = D.clone();
|
||
D = clone;
|
||
}
|
||
|
||
if (A.x === B.x) {
|
||
if (C.y === D.y && C.x < A.x && A.x < D.x &&
|
||
A.y < C.y && C.y < B.y) {
|
||
returnValue = new PMUI.util.Point(A.x, C.y);
|
||
}
|
||
} else if (A.y === B.y) {
|
||
if (C.x === D.x && A.x < C.x && C.x < B.x &&
|
||
C.y < A.y && A.y < D.y) {
|
||
returnValue = new PMUI.util.Point(C.x, A.y);
|
||
}
|
||
}
|
||
return returnValue;
|
||
},
|
||
/**
|
||
* Determines if segment AB intersects with segment CD (won't check infinite intersections),
|
||
* if `strict` is set to `true` then it'll consider the case when one end of a segment is right in the
|
||
* other segment
|
||
* @param {PMUI.util.Point} A
|
||
* @param {PMUI.util.Point} B
|
||
* @param {PMUI.util.Point} C
|
||
* @param {PMUI.util.Point} D
|
||
* @param {boolean} [strict]
|
||
* @return {boolean}
|
||
*/
|
||
segmentIntersection: function (A, B, C, D, strict) {
|
||
|
||
var area1 = this.area(C, D, A),
|
||
area2 = this.area(C, D, B),
|
||
area3 = this.area(A, B, C),
|
||
area4 = this.area(A, B, D),
|
||
returnValue;
|
||
if (((area1 > 0 && area2 < 0) || (area1 < 0 && area2 > 0)) &&
|
||
((area3 > 0 && area4 < 0) || (area3 < 0 && area4 > 0))) {
|
||
return true;
|
||
}
|
||
|
||
returnValue = false;
|
||
if (strict) {
|
||
if (area1 === 0 && this.onSegment(A, C, D)) {
|
||
returnValue = true;
|
||
} else if (area2 === 0 && this.onSegment(B, C, D)) {
|
||
returnValue = true;
|
||
} else if (area3 === 0 && this.onSegment(C, A, B)) {
|
||
returnValue = true;
|
||
} else if (area4 === 0 && this.onSegment(D, A, B)) {
|
||
returnValue = true;
|
||
}
|
||
}
|
||
return returnValue;
|
||
},
|
||
/**
|
||
* Checks if two segments intersect, if so it returns the intersection point
|
||
* @param {PMUI.util.Point} A
|
||
* @param {PMUI.util.Point} B
|
||
* @param {PMUI.util.Point} C
|
||
* @param {PMUI.util.Point} D
|
||
* @return {PMUI.util.Point}
|
||
*/
|
||
segmentIntersectionPoint: function (A, B, C, D) {
|
||
return A.add((B.subtract(A))
|
||
.multiply(this.cross(C.subtract(A), D.subtract(A)) /
|
||
this.cross(B.subtract(A), D.subtract(C))));
|
||
},
|
||
/**
|
||
* Determines whether a point is in a given rectangle or not given its
|
||
* upperLeft and bottomRight corner (consider that a rectangle is turned in the y-axis)
|
||
* @param {PMUI.util.Point} point
|
||
* @param {PMUI.util.Point} upperLeft
|
||
* @param {PMUI.util.Point} bottomRight
|
||
* @return {boolean}
|
||
*/
|
||
pointInRectangle: function (point, upperLeft, bottomRight) {
|
||
return (point.x >= upperLeft.x && point.x <= bottomRight.x &&
|
||
point.y >= upperLeft.y && point.y <= bottomRight.y);
|
||
},
|
||
/**
|
||
* Determines whether a point is in a circle or not given its center and
|
||
* radius
|
||
* @param {PMUI.util.Point} point
|
||
* @param {PMUI.util.Point} center
|
||
* @param {number} radius
|
||
* @returns {boolean}
|
||
*/
|
||
pointInCircle: function (point, center, radius) {
|
||
return center.getDistance(point) <= radius;
|
||
},
|
||
/**
|
||
* Determine whether a point is inside a rhombus or not given its center
|
||
* and its points in clockwise order
|
||
* @param {PMUI.util.Point} point
|
||
* @param {Array} rhombus
|
||
* @param {PMUI.util.Point} center
|
||
* @return {boolean}
|
||
*/
|
||
pointInRhombus: function (point, rhombus, center) {
|
||
var i,
|
||
j = rhombus.length - 1;
|
||
for (i = 0; i < rhombus.length; j = i, i += 1) {
|
||
if (this.segmentIntersection(center, point,
|
||
rhombus[j], rhombus[i], true) &&
|
||
this.onSegment(point, rhombus[j], rhombus[i]) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
};
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Geometry;
|
||
}
|
||
|
||
// extend the namespace
|
||
PMUI.extendNamespace('PMUI.draw.Geometry', Geometry);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.event.Action
|
||
* Handles the action for buttons, menues, toolbars
|
||
*
|
||
* Example:
|
||
*
|
||
* var action = new PMUI.event.Action({
|
||
* text: 'Save Document',
|
||
* icon: 'pm-icon-save',
|
||
* disabled: false,
|
||
* handler: function () {
|
||
* alert('Action has been called!');
|
||
* }
|
||
* });
|
||
*
|
||
* Using action as parameter to create another objects:
|
||
*
|
||
* var button = new PMUI.ui.Button(action);
|
||
*
|
||
* var form = new PMUI.form.Form({
|
||
* ...
|
||
* buttons: [
|
||
* action,
|
||
* {
|
||
* text: 'Refresh',
|
||
* handler: function() {
|
||
* obj.refresh() //this object is fake used for sample purposes only
|
||
* }
|
||
* }
|
||
* ]
|
||
* ...
|
||
* });
|
||
*
|
||
* Actions are created to handle user functionality you can extend or use over several places or components
|
||
*
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of object
|
||
* @param {Object} options
|
||
*/
|
||
var Action = function (options) {
|
||
/**
|
||
* Defines the text of the action
|
||
* @type {String}
|
||
*/
|
||
this.actionText = null;
|
||
/**
|
||
* Defines the icon asssociated with the action
|
||
* @type {String}
|
||
*/
|
||
this.actionIcon = null;
|
||
/**
|
||
* Defines the state of the action
|
||
* @type {Boolean}
|
||
*/
|
||
this.disabled = false;
|
||
/**
|
||
* Defines the action to be executed
|
||
* @type {Function}
|
||
*/
|
||
this.handler = null;
|
||
|
||
Action.prototype.init.call(this, options);
|
||
};
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
Action.prototype.type = 'Action';
|
||
/**
|
||
* Defines the object's family
|
||
* @type {String}
|
||
*/
|
||
Action.prototype.family = 'Action';
|
||
|
||
/**
|
||
* Defines the action flag
|
||
* @type {Boolean}
|
||
*/
|
||
Action.prototype.isAction = true;
|
||
|
||
/**
|
||
* @private
|
||
* Initializes the object with the default values
|
||
* @param {Object} options Constructor options
|
||
*/
|
||
Action.prototype.init = function (options) {
|
||
var defaults;
|
||
defaults = {
|
||
icon: null,
|
||
text: null,
|
||
disabled: false,
|
||
handler: function () {
|
||
}
|
||
};
|
||
jQuery.extend(true, defaults, options);
|
||
this.setActionIcon(defaults.icon)
|
||
.setActionText(defaults.text)
|
||
.setDisable(defaults.disabled)
|
||
.setHandler(defaults.handler);
|
||
};
|
||
|
||
/**
|
||
* Sets the action Icon
|
||
* @param {String} icon Icon URL or class
|
||
*/
|
||
Action.prototype.setActionIcon = function (icon) {
|
||
this.actionIcon = icon;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the action's text
|
||
* @param {String} text Actions's name
|
||
*/
|
||
Action.prototype.setActionText = function (text) {
|
||
this.actionText = text;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the disabled value
|
||
* @param {Boolean} value
|
||
*/
|
||
Action.prototype.setDisable = function (value) {
|
||
if (typeof(value) === 'boolean') {
|
||
this.disabled = value;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the icon url or class
|
||
* @return {String} [description]
|
||
*/
|
||
Action.prototype.getIcon = function () {
|
||
return this.actionIcon;
|
||
};
|
||
|
||
/**
|
||
* Returns the action name
|
||
* @return {String} [description]
|
||
*/
|
||
Action.prototype.getText = function () {
|
||
return this.actionText;
|
||
};
|
||
|
||
/**
|
||
* Sets the handler function
|
||
* @param {Function} fn
|
||
*/
|
||
Action.prototype.setHandler = function (fn) {
|
||
if (typeof(fn) === 'function') {
|
||
this.handler = fn;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Enables the action functionality
|
||
*/
|
||
Action.prototype.enable = function () {
|
||
this.setDisable(false);
|
||
};
|
||
|
||
/**
|
||
* Disables the action functionality
|
||
*/
|
||
Action.prototype.disable = function () {
|
||
this.setDisable(true);
|
||
};
|
||
|
||
/**
|
||
* Returns if the action is enabled
|
||
* @return {Boolean}
|
||
*/
|
||
Action.prototype.isEnabled = function () {
|
||
return !this.disabled;
|
||
};
|
||
|
||
/**
|
||
* Executes the action if is enabled and has a valid handler
|
||
*/
|
||
Action.prototype.execute = function () {
|
||
if (!this.disabled && typeof this.handler === 'function') {
|
||
this.handler();
|
||
}
|
||
};
|
||
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = Action;
|
||
}
|
||
|
||
PMUI.extendNamespace('PMUI.event.Action', Action);
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.core.Base
|
||
* Base class for any other class in PMUI, this class is an abstract so it shouldn't be instantiated.
|
||
* @param {Object} settings All the settings the the class requires
|
||
*
|
||
* Usage example:
|
||
*
|
||
* var anObject = new PMUI.core.Base({
|
||
* id: "myUniqueId"
|
||
* });
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class 'Base'.
|
||
* @param {Object} [options={}] The config options for the object.
|
||
*
|
||
* @cfg {String} [id=[an autogenerated unique id]] The unique identifier for the object. If it is not specified
|
||
* then one is created an assigned to it.
|
||
*/
|
||
var Base = function (settings) {
|
||
/**
|
||
* Unique ID
|
||
* @type {String}
|
||
*/
|
||
this.id = null;
|
||
Base.prototype.init.call(this, settings);
|
||
};
|
||
/**
|
||
* Class type
|
||
* @type {String}
|
||
*/
|
||
Base.prototype.type = 'Base';
|
||
/**
|
||
* Class family
|
||
* @type {String}
|
||
*/
|
||
Base.prototype.family = 'Core';
|
||
/**
|
||
* Initialize the object
|
||
* @param {Object} settings Settings for Base Class
|
||
* @return {String} the generated id
|
||
* @private
|
||
*/
|
||
Base.prototype.init = function (settings) {
|
||
var defaults = {
|
||
id: 'pmui-' + PMUI.generateUniqueId()
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setID(defaults.id);
|
||
};
|
||
/**
|
||
* Set the id property for the object
|
||
* @param {String} id
|
||
* @chainable
|
||
*/
|
||
Base.prototype.setID = function (id) {
|
||
this.id = id;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the id property from the object
|
||
* @return {String} [description]
|
||
*/
|
||
Base.prototype.getID = function () {
|
||
return this.id;
|
||
};
|
||
/**
|
||
* Returns the object's type
|
||
* @return {String}
|
||
*/
|
||
Base.prototype.getType = function () {
|
||
return this.type;
|
||
};
|
||
/**
|
||
* Return's the object's family name
|
||
* @return {String}
|
||
*/
|
||
Base.prototype.getFamily = function () {
|
||
return this.family;
|
||
};
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = Base;
|
||
}
|
||
|
||
PMUI.extendNamespace('PMUI.core.Base', Base);
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.core.Element
|
||
* Base class to handle objects that have a visual representation (HTML representation).
|
||
* @extends PMUI.core.Base
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var element;
|
||
*
|
||
* element = new PMUI.core.Element({
|
||
* x: 10,
|
||
* y: 20,
|
||
* positionMode: "absolute",
|
||
* width: 200,
|
||
* height: 200,
|
||
* style: {
|
||
* cssProperties: {
|
||
* "background-color": "red"
|
||
* },
|
||
* cssClasses: [".square"]
|
||
* }
|
||
* });
|
||
*
|
||
* document.body.appendChild(element.getHTML());
|
||
*
|
||
* @constructor
|
||
* Create a new instace of the class 'Element'
|
||
* @param {Object} options
|
||
*
|
||
* @cfg {String} [elementTag="div"] The html tag for the object's HTML element.
|
||
* @cfg {String} [positionMode="relative"] The css position for the object's HTML element. It can take one of the
|
||
* following values "static", "absolute", "fixed", "relative", "inherit" or "". Please read about the css "position"
|
||
* property to know about how each value impacts in the html.
|
||
* @cfg {Object} [style={cssProperties:{}, cssClasses:[]}] A JSON object which will contain the css properties for
|
||
* the object's html.
|
||
*
|
||
* This object can have optionally two properties:
|
||
*
|
||
* - cssProperties: another JSON object in which each property can be a css property (if the css property has any
|
||
* special character like "-" enclose the property name between quotes), the value can be any valid css value for
|
||
* the property.
|
||
* - cssClasses: An array where each element is a String, this String is the css class name.
|
||
*
|
||
* @cfg {Number} [x=0] The position coordinate in the x axis for the object's HTML, please note that the visual
|
||
* position will depend on the {@link PMUI.core.Element#cfg-positionMode positionMode option}.
|
||
* @cfg {Number} [y=0] The position coordinate in the y axis for the object's HTML, please note that the visual
|
||
* position will depend on the {@link PMUI.core.Element#cfg-positionMode positionMode option}.
|
||
* @cfg {Number|String} [width="auto"] The width for the object's HTML, it can be a Number or an String. In the
|
||
* latter case the value must be "auto" or "inherit" or have one of the following formats:
|
||
*
|
||
* - "##px".
|
||
* - "##%".
|
||
* - "##em"
|
||
*
|
||
* Note that ## is a number.
|
||
* @cfg {Number|String} [height="auto"] The height for the object's HTML, the values that can take are the same
|
||
* specified in the {@link PMUI.core.Element#cfg-width}.
|
||
* @cfg {Number|String} [zOrder="auto"] The position in the z axis for the object's HTML, it can be a Number or a
|
||
* String, in the latter case the value only can be "auto" or "inherit".
|
||
* @cfg {Boolean} [visible=true] If the object will be visible or not.
|
||
* @cfg {Number} [proportion=1] A numeric value that specifies the final width of the object's HTML in case to be
|
||
* contained by a {@link PMUI.core.Container Container} which is applying a {@link PMUI.layout.Layout Layout}.
|
||
* @cfg {String} [display=""] The display property specifies the type of box used for an HTML element.
|
||
* find out more about the css display property
|
||
* @cfg {Function} [onBeforeContextMenu=null] description here.
|
||
*/
|
||
var Element = function (settings) {
|
||
Element.superclass.call(this, settings);
|
||
/**
|
||
* HTML element.
|
||
* @type {HTMLElement}
|
||
* @readonly
|
||
*/
|
||
this.html = null;
|
||
/**
|
||
* @property {Object|PMUI.util.Style} [style={
|
||
cssProperties: {},
|
||
cssClasses: []
|
||
}]
|
||
* A {@link PMUI.util.Style Style} object or a JSON object with the settings to create a new
|
||
* {@link PMUI.util.Style Style} object for the current's HTML element.
|
||
* @readonly
|
||
*/
|
||
this.style = null;
|
||
/**
|
||
* X coordinate for the HTML element.
|
||
* @type {Number}
|
||
* @readonly
|
||
*/
|
||
this.x = null;
|
||
/**
|
||
* @property {Number} [y=0]
|
||
* Y Coordinate for the HTML element.
|
||
* @readonly
|
||
*/
|
||
this.y = null;
|
||
/**
|
||
* Width for the HTML element, it can be a number or a string with the following format:
|
||
##px when ## is a number.
|
||
* @type {Number|String}
|
||
* @readonly
|
||
*/
|
||
this.width = null;
|
||
/**
|
||
* Height for the HTML element, it can be a number or a string with the following format:
|
||
##px when ## is a number.
|
||
* @type {Number|String}
|
||
* @readonly
|
||
*/
|
||
this.height = null;
|
||
/**
|
||
* A boolean value that indicates if the HTML element is visible or not.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.visible = null;
|
||
/**
|
||
* A Number that indicates the HTML element's position on the Z axis.
|
||
* @type {Number}
|
||
* @readonly
|
||
*/
|
||
this.zOrder = null;
|
||
/**
|
||
* @property {String} [elementTag="div"]
|
||
* Tag name for the element to be created, it defaults to "div".
|
||
* @readonly
|
||
*/
|
||
this.elementTag = null;
|
||
/**
|
||
* @property {String} [positionMode="relative"]
|
||
* Position for the object's html element, it must be a valid value for the "position" CSS property.
|
||
* @readonly
|
||
*/
|
||
this.positionMode = null;
|
||
/**
|
||
* Defines the proportion of the html.
|
||
* @type {Number}
|
||
*/
|
||
this.proportion = null;
|
||
/**
|
||
* @property {String} [display=""] The display mode for the element. It is set by the
|
||
* {@link #cfg-display display} config option and the {@link #method-setDisplay setDisplay} method.
|
||
* @readonly
|
||
*/
|
||
this.display = null;
|
||
/**
|
||
* Defines the menu component for the element
|
||
* @type {PMUI.ui.Menu}
|
||
*/
|
||
this.menu = null;
|
||
/**
|
||
* Defines an object to handle/register events.
|
||
* @type {Object}
|
||
*/
|
||
this.events = {};
|
||
/**
|
||
* @property {Boolean} eventsDefined If the events were defined or not
|
||
*/
|
||
this.eventsDefined = false;
|
||
/**
|
||
* [onContextMenu description]
|
||
* @type {Boolean}
|
||
*/
|
||
this.onContextMenu = false;
|
||
/**
|
||
* [onBeforeContextMenu description]
|
||
* @type {Boolean}
|
||
*/
|
||
this.onBeforeContextMenu = false;
|
||
/**
|
||
* The element's parent Container.
|
||
* @type {PMUI.core.Element}
|
||
*/
|
||
this.parent = null;
|
||
/**
|
||
* The HTML area in which some activities, actions can be performed (like display the context menu).
|
||
* @type {HTMLElement}
|
||
* @private
|
||
*/
|
||
this.actionHTML = null;
|
||
|
||
Element.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Base', Element);
|
||
/**
|
||
* The Object's type.
|
||
* @type {String}
|
||
*/
|
||
Element.prototype.type = 'Element';
|
||
/**
|
||
* Initialize the object.
|
||
* @param {Object} settings A JSON object with the settings to create the new class instance.
|
||
* @private
|
||
*/
|
||
Element.prototype.init = function (settings) {
|
||
var defaults = {
|
||
elementTag: "div",
|
||
positionMode: "relative",
|
||
menu: null,
|
||
style: {
|
||
cssProperties: {},
|
||
cssClasses: []
|
||
},
|
||
x: 0,
|
||
y: 0,
|
||
width: "auto",
|
||
height: "auto",
|
||
zOrder: "auto",
|
||
display: "",
|
||
visible: true,
|
||
proportion: 1,
|
||
onContextMenu: null,
|
||
onBeforeContextMenu: null
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setElementTag(defaults.elementTag)
|
||
.setStyle(defaults.style)
|
||
.setPositionMode(defaults.positionMode)
|
||
.setDisplay(defaults.display)
|
||
.setX(defaults.x)
|
||
.setY(defaults.y)
|
||
.setWidth(defaults.width)
|
||
.setHeight(defaults.height)
|
||
.setZOrder(defaults.zOrder)
|
||
.setVisible(defaults.visible)
|
||
.setProportion(defaults.proportion)
|
||
.setContextMenu(defaults.menu)
|
||
.setOnBeforeContextMenu(defaults.onBeforeContextMenu)
|
||
.setOnContextMenuHandler(defaults.onContextMenu);
|
||
};
|
||
/**
|
||
* [setOnBeforeContextMenu description]
|
||
*/
|
||
Element.prototype.setOnBeforeContextMenu = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnBeforeContextMenu(): The parameter must be a function or null.");
|
||
}
|
||
this.onBeforeContextMenu = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* [setOnContextMenuHandler description]
|
||
* @param {[type]} handler [description]
|
||
*/
|
||
Element.prototype.setOnContextMenuHandler = function (handler) {
|
||
if (typeof handler === 'function' || null) {
|
||
this.onContextMenu = handler;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the display mode for the Element.
|
||
* @param {String} display It can take one of the following values:
|
||
*
|
||
* - ""
|
||
* - "block"
|
||
* - "inline"
|
||
* - "inline-block"
|
||
* - "none"
|
||
*
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setDisplay = function (display) {
|
||
if (display === "" || display === 'block' || display === 'inline'
|
||
|| display === 'inline-block' || display === 'none') {
|
||
this.display = display;
|
||
this.applyStyle();
|
||
} else {
|
||
throw new Error('The setDisplay() method only accepts one od the following options: ' +
|
||
' "", "block", "inline", "inline-block", "none"');
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the position mode for the Element.
|
||
* @param {String} position It can take one ot the following values:
|
||
*
|
||
* - "static"
|
||
* - "asolute"
|
||
* - "fixed"
|
||
* - "relative"
|
||
* - "inherit"
|
||
*
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setPositionMode = function (position) {
|
||
if (position === 'static' || position === 'absolute' || position === 'fixed' || position === 'relative' ||
|
||
position === 'inherit' || position === "") {
|
||
this.positionMode = position;
|
||
this.applyStyle();
|
||
} else {
|
||
throw new Error('The setPosition() method only accepts one of the following options:' +
|
||
' "static", "absolute", "fixed", "relative", "inherit" or an empty string.');
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Set the HTML tag for the HTML element to be created, note that it'll only work when its html property
|
||
is still not set.
|
||
* @param {String} tag a HTML tag
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setElementTag = function (tag) {
|
||
if (!this.html && typeof tag === 'string') {
|
||
this.elementTag = tag;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* [addCSSClasses description]
|
||
* @param {[type]} classes [description]
|
||
*/
|
||
Element.prototype.addCSSClasses = function (classes) {
|
||
this.style.addClasses(classes);
|
||
return this;
|
||
};
|
||
/**
|
||
* [addCSSProperties description]
|
||
* @param {[type]} properties [description]
|
||
*/
|
||
Element.prototype.addCSSProperties = function (properties) {
|
||
this.style.addProperties(properties);
|
||
return this;
|
||
};
|
||
/**
|
||
* [removeCSSClasses description]
|
||
* @param {[type]} classes [description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
Element.prototype.removeCSSClasses = function (classes) {
|
||
this.style.removeClasses(classes);
|
||
return this;
|
||
};
|
||
/**
|
||
* [removeCSSProperties description]
|
||
* @param {[type]} properties [description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
Element.prototype.removeCSSProperties = function (properties) {
|
||
this.style.removeProperties(properties);
|
||
return this;
|
||
};
|
||
/**
|
||
* Set the style properties for the HTML element.
|
||
* @param {Object|null} style an JSON structure with attributes cssProperties (another object) and cssClasses
|
||
* (array). It also can be null, in this case no custom styles will be applied to the the element.
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setStyle = function (style) {
|
||
style = style || {};
|
||
if (this.style && this.html) {
|
||
this.style.unapplyStyle();
|
||
}
|
||
if (style instanceof PMUI.util.Style) {
|
||
this.style = style;
|
||
style.belongsTo = this;
|
||
} else if (typeof style === 'object') {
|
||
style.belongsTo = this;
|
||
this.style = new PMUI.util.Style(style);
|
||
}
|
||
this.applyStyle();
|
||
return this;
|
||
};
|
||
/**
|
||
* Set the x position coordinate for the HTML element.
|
||
* @chainable
|
||
* @param {Number} x
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setX = function (x) {
|
||
if (typeof x === 'number') {
|
||
this.x = x;
|
||
} else if (/^\d+(\.\d+)?px$/.test(x)) {
|
||
this.x = parseInt(x, 10);
|
||
} else {
|
||
throw new Error('setX: x param is not a number');
|
||
}
|
||
this.style.addProperties({left: this.x});
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the x position coordinate for the HTML element
|
||
* @return {Number}
|
||
*/
|
||
Element.prototype.getX = function () {
|
||
return this.x;
|
||
};
|
||
/**
|
||
* Set the y position coordinate for the HTML element.
|
||
* @param {Number} y
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setY = function (y) {
|
||
if (typeof y === 'number') {
|
||
this.y = y;
|
||
} else if (/^\d+(\.\d+)?px$/.test(y)) {
|
||
this.y = parseInt(y, 10);
|
||
} else {
|
||
throw new Error('setY: y param is not a number');
|
||
}
|
||
this.style.addProperties({top: this.y});
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the y position coordinate for the HTML element
|
||
* @return {Number}
|
||
*/
|
||
Element.prototype.getY = function () {
|
||
return this.y;
|
||
};
|
||
/**
|
||
* Set the width for the HTML element
|
||
* @param {Number|String} width height it can be a number or a string.
|
||
In case of using a String you only can use 'auto' or ##px or ##% or ##em when ## is a number.
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setWidth = function (width) {
|
||
if (typeof width === 'number') {
|
||
this.width = width;
|
||
} else if (/^\d+(\.\d+)?px$/.test(width)) {
|
||
this.width = parseInt(width, 10);
|
||
} else if (/^\d+(\.\d+)?%$/.test(width)) {
|
||
this.width = width;
|
||
} else if (/^\d+(\.\d+)?em$/.test(width)) {
|
||
this.width = width;
|
||
} else if (width === 'auto') {
|
||
this.width = width;
|
||
} else {
|
||
throw new Error('setWidth: width param is not a number');
|
||
}
|
||
this.style.addProperties({width: this.width});
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the HTML element's width
|
||
* @return {Number}
|
||
*/
|
||
Element.prototype.getWidth = function () {
|
||
return this.width;
|
||
};
|
||
/**
|
||
* Set the height for the HTML element
|
||
* @param {Number|String} height it can be a number or a string.
|
||
In case of using a String you only can use 'auto' or 'inherit' or ##px or ##% or ##em when ## is a number.
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setHeight = function (height) {
|
||
if (typeof height === 'number') {
|
||
this.height = height;
|
||
} else if (/^\d+(\.\d+)?px$/.test(height)) {
|
||
this.height = parseInt(height, 10);
|
||
} else if (/^\d+(\.\d+)?%$/.test(height)) {
|
||
this.height = height;
|
||
} else if (/^\d+(\.\d+)?em$/.test(height)) {
|
||
this.height = height;
|
||
} else if (height === 'auto' || height === 'inherit') {
|
||
this.height = height;
|
||
} else {
|
||
throw new Error('setHeight: height param is not a number');
|
||
}
|
||
this.style.addProperties({height: this.height});
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the HTML element's height.
|
||
* @return {Number}
|
||
*/
|
||
Element.prototype.getHeight = function () {
|
||
return this.height;
|
||
};
|
||
/**
|
||
* Set the position index om the z axis for the object's HTML element.
|
||
* @param {Number|String} zOrder it can be a Number or a String.
|
||
In case of using a String you only can use 'auto' or 'inherit'.
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setZOrder = function (zOrder) {
|
||
if (typeof zOrder === 'number') {
|
||
this.zOrder = parseInt(zOrder, 10);
|
||
} else if (zOrder === 'auto' || zOrder === 'inherit') {
|
||
this.zOrder = zOrder;
|
||
} else {
|
||
throw new Error('setZOrder: zOrder param is not a number');
|
||
}
|
||
if (this.html) {
|
||
this.style.addProperties({"z-index": this.zOrder});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the HTML element's zOrder.
|
||
* @return {Number}
|
||
*/
|
||
Element.prototype.getZOrder = function () {
|
||
return this.zOrder;
|
||
};
|
||
/**
|
||
* Set if the HTML element is visible or not.
|
||
* @param {Boolean} visible
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setVisible = function (visible) {
|
||
visible = !!visible;
|
||
this.visible = visible;
|
||
if (this.html) {
|
||
this.style.addProperties({"display": this.visible ? this.display : "none"});
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns a boolean value that indicates if the HTML element is visible or not.
|
||
* @return {Boolean} [description]
|
||
*/
|
||
Element.prototype.isVisible = function () {
|
||
return this.visible;
|
||
};
|
||
/**
|
||
* Set the HTML element's position.
|
||
* @param {Object} position an object with x and y properties, both of them are Numbers
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setPosition = function (position) {
|
||
this.setX(position.x);
|
||
this.setY(position.y);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns and object which contains the x and y positions from the HTML element.
|
||
* @return {Object}
|
||
*/
|
||
Element.prototype.getPosition = function () {
|
||
return {
|
||
x: this.getX(),
|
||
y: this.getY()
|
||
};
|
||
};
|
||
/**
|
||
* Set the HTML element's dimension (width and height).
|
||
* @param {Object} dimension
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setDimension = function (dimension) {
|
||
this.setWidth(dimension.width);
|
||
this.setHeight(dimension.height);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the HTML element's dimension.
|
||
* @return {Object} and object with width and height properties.
|
||
*/
|
||
Element.prototype.getDimension = function () {
|
||
return {
|
||
width: this.getWidth(),
|
||
height: this.getHeight()
|
||
};
|
||
};
|
||
/**
|
||
* Applies the css classes and ptoperties to the element's html which the object is related.
|
||
* @chainable
|
||
*/
|
||
Element.prototype.applyStyle = function () {
|
||
if (this.html) {
|
||
this.style.applyStyle();
|
||
|
||
this.style.addProperties({
|
||
display: this.visible ? this.display : "none",
|
||
position: this.positionMode,
|
||
left: this.x,
|
||
top: this.y,
|
||
width: this.width,
|
||
height: this.height,
|
||
zIndex: this.zOrder
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the object's HTML element.
|
||
* @return {HTMLElement} returns a HTML element
|
||
*/
|
||
Element.prototype.createHTML = function () {
|
||
var html;
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
html = PMUI.createHTMLElement(this.elementTag || "div");
|
||
html.id = this.id;
|
||
PMUI.linkToPMUIObject(html, this);
|
||
this.html = html;
|
||
this.actionHTML = html;
|
||
this.applyStyle();
|
||
if (this.eventsDefined) {
|
||
this.defineEvents();
|
||
}
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Returns the object's HTML element, if it doesn't exist it's created then it is returned.
|
||
* @return {HTMLElement}
|
||
*/
|
||
Element.prototype.getHTML = function () {
|
||
if (!this.html) {
|
||
this.html = this.createHTML();
|
||
}
|
||
return this.html;
|
||
};
|
||
|
||
/**
|
||
* Set the proportion of the html element.
|
||
* @param {Number} p Proportion value.
|
||
* @chainable
|
||
*/
|
||
Element.prototype.setProportion = function (p) {
|
||
this.proportion = p;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Creates and Instanciate an event.
|
||
* @param {String} type Event type.
|
||
* @param {String} [alias] Registered Name.
|
||
* @return {PMUI.event.Event}
|
||
*/
|
||
Element.prototype.addEvent = function (type, alias) {
|
||
var factory = new PMUI.event.EventFactory(),
|
||
newEvent = factory.make(type),
|
||
registerName = alias || PMUI.generateUniqueId();
|
||
this.events[registerName] = newEvent;
|
||
return newEvent;
|
||
};
|
||
|
||
/**
|
||
* @abstract
|
||
* Defines the events associated with the element.
|
||
* @chainable
|
||
* @abstract
|
||
*/
|
||
Element.prototype.defineEvents = function () {
|
||
var that = this;
|
||
this.removeEvents();
|
||
this.addEvent('contextmenu').listen(this.actionHTML, function (e) {
|
||
if (typeof that.onBeforeContextMenu === 'function') {
|
||
that.onBeforeContextMenu(that);
|
||
}
|
||
if (typeof that.onContextMenu === 'function') {
|
||
that.onContextMenu(that);
|
||
}
|
||
if (that.menu) {
|
||
e.stopPropagation();
|
||
e.preventDefault();
|
||
that.menu.show(e.pageX, e.pageY);
|
||
}
|
||
});
|
||
this.eventsDefined = true;
|
||
return this;
|
||
};
|
||
/**
|
||
* Remove a specific event attached to the object.
|
||
* @param {String} identifier The id or alias used in the moment of event addition.
|
||
* @chainable
|
||
*/
|
||
Element.prototype.removeEvent = function (identifier) {
|
||
if (this.events[identifier]) {
|
||
this.events[identifier].unlisten();
|
||
delete this.events[identifier];
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes events attached to the object.
|
||
* @chainable
|
||
*/
|
||
Element.prototype.removeEvents = function () {
|
||
var k;
|
||
for (k in this.events) {
|
||
this.removeEvent(k);
|
||
}
|
||
;
|
||
return this;
|
||
};
|
||
/**
|
||
* Calculates the width size of the container.
|
||
*
|
||
* @param {String} text
|
||
* @param {String} font
|
||
* @chainable
|
||
*/
|
||
Element.prototype.calculateWidth = function (text, font) {
|
||
//TODO Improve the div creation (maybe we can use a singleton for this)
|
||
var f = font || '12px arial',
|
||
$o = $(PMUI.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;
|
||
};
|
||
/**
|
||
* Sets the context menu for the component and the menu will be contained on the {@link PMUI.core.Element#menu menu} property.
|
||
*
|
||
* If the settings parameter is not a valid json the {@link PMUI.core.Element#menu menu} property will be an simple empty object.
|
||
*
|
||
* The example below shows the appropriate way to send a basic settings parameter.
|
||
*
|
||
* component = new Class();
|
||
* component.setContextMenu({
|
||
* id: "id", //optional
|
||
* items: [
|
||
* {
|
||
* text: "Option 1"
|
||
* },
|
||
* {
|
||
* text: "Option 2"
|
||
* }
|
||
* ]
|
||
* });
|
||
*
|
||
* For more details about the context menu, the documentation is on the {@link PMUI.ui.Menu Menu} class.
|
||
*
|
||
* @param {Object} settings Configuration or config options for the context {@link PMUI.ui.Menu menu}.
|
||
* @return {Object} this Represents the component of the class.
|
||
*/
|
||
Element.prototype.setContextMenu = function (menuItems) {
|
||
var contextMenu;
|
||
this.removeContextMenu();
|
||
if (menuItems !== null) {
|
||
if (jQuery.isArray(menuItems)) {
|
||
contextMenu = new PMUI.menu.Menu({items: menuItems});
|
||
} else if (menuItems instanceof PMUI.menu.Menu) {
|
||
contextMenu = menuItems;
|
||
} else if (typeof menuItems === 'object') {
|
||
contextMenu = new PMUI.menu.Menu(menuItems);
|
||
}
|
||
if (contextMenu) {
|
||
this.menu = contextMenu.setTargetElement(this);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* [removeContextMenu description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
Element.prototype.removeContextMenu = function () {
|
||
if (this.menu) {
|
||
this.menu.setTargetElement(null);
|
||
this.menu = null;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the elemnent's parent container.
|
||
* @return {PMUI.core.Element|null} The parent container.
|
||
*/
|
||
Element.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
/**
|
||
* Shows the context menu for the element provided that the element contains an object that represent a
|
||
* {@link PMUI.ui.Menu Menu}.
|
||
*
|
||
* If the {@link PMUI.core.Element#menu menu} property is an empty object the context menu will
|
||
* never appear on the page.
|
||
*
|
||
* By default the context menu will appear after to do right click on the element.
|
||
*/
|
||
Element.prototype.showContextMenu = function () {
|
||
if (this.menu) {
|
||
this.menu.show();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Return true if the object's events were defined, otherwise it returns false.
|
||
* @return {Boolean}
|
||
*/
|
||
Element.prototype.eventsAreDefined = function () {
|
||
return this.eventsDefined;
|
||
};
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = Element;
|
||
}
|
||
|
||
PMUI.extendNamespace('PMUI.core.Element', Element);
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.core.Container
|
||
* Handles HTML elements that have a container behavior (they can be contain {Element} objects)
|
||
* @abstract
|
||
* @extend PMUI.core.Element
|
||
* * Usage example (only for subclasses since this is an abstract class):
|
||
*
|
||
* @example
|
||
* //Remember, this is an abstract class so it shouldn't be instantiate,
|
||
* //anyway we are instantiating it just for this example
|
||
* c = new PMUI.core.Container({
|
||
* x: 10,
|
||
* y: 20,
|
||
* positionMode: "absolute",
|
||
* width: 300,
|
||
* height: 100,
|
||
* style: {
|
||
* cssProperties: {
|
||
* "background-color": "yellow"
|
||
* },
|
||
* cssClasses: [".square"]
|
||
* },
|
||
* items : [
|
||
* new PMUI.core.Element({
|
||
* y : 0,
|
||
* width: 100,
|
||
* height: 100,
|
||
* style: {
|
||
* cssProperties: {
|
||
* "background-color": "red"
|
||
* },
|
||
* cssClasses: [".square"]
|
||
* }
|
||
* }),
|
||
* new PMUI.core.Element({
|
||
* y : 100,
|
||
* width: 100,
|
||
* height: 100,
|
||
* style: {
|
||
* cssProperties: {
|
||
* "background-color": "yellow"
|
||
* },
|
||
* cssClasses: [".square"]
|
||
* }
|
||
* })
|
||
* ]
|
||
* });
|
||
* document.body.appendChild(c.getHTML());
|
||
*
|
||
* @constructor
|
||
* Creates a new instance
|
||
* @param {Object} settings
|
||
*
|
||
* @cfg {Array} [items=[]] An array with the items to be added to tyhe container. If the
|
||
* {@link PMUI.core.Container#cfg-dataItems dataItems config option} is specified then this config option will be
|
||
* ignored.
|
||
*
|
||
* Each array's item can be:
|
||
*
|
||
* - A JSON object with the config options required by an {@link PMUI.core.Element Element object}.
|
||
* - An instance of the {@link PMUI.core.Element Element class}.
|
||
*
|
||
* @cfg {String} [behavior='nobehavior'] A string that specifies the behavior for the container and its items.
|
||
* The accepted values are the same ones that the specified ones for the
|
||
* {@link PMUI.core.Container#method-setBehavior setBehavior() method}.
|
||
*
|
||
* @cfg {Array} [dataItems=null] An array in which each element is the data for the items that will be contained by
|
||
* the container. If this config option is specfied the {@link PMUI.core.Container#cfg-items items config option}
|
||
* will be ignored.
|
||
*
|
||
* @cfg {Function} [onDrop=null] The callback function to be executed everytime a draggable item is dropped on the
|
||
* container. This callback can return a boolean value or not return anything. If it returns "false" then the drop
|
||
* action will be cancelled. For info about the parameters sent to the callback function please read the
|
||
* {@link PMUI.core.Container#event-onDrop onDrop} event documentation.
|
||
*
|
||
* @cfg {Function} [onSort=null] The callback function to be executed everytime a container's item order changes.
|
||
* For info about the parameters sent to the callback function please read the
|
||
* {@link PMUI.core.Container#event-onSort onSort} event documentation.
|
||
*
|
||
* @cfg {String} [sortableItems=null] Specifies which items inside the element should be sortable in case a
|
||
* sort behavior is applied. It must be a jQuery selector.
|
||
*
|
||
* @cfg {Boolean} [disabled=false] If the interactive functions like the drag, drop, sort behaviors will be
|
||
* disabled or not.
|
||
*
|
||
* @cfg {Function|null} [onBeforeDrop=null] The callback to be executed before a draggable item that was dropped
|
||
* on the container is added.
|
||
*
|
||
* @cfg {Function|null} [onDropOut=null] The callback to be executed everytime a draggable item is drop out from
|
||
* the container to another one. To know the parameters sent to the callback function read the documentation for
|
||
* the {@link #event-onDropOut onDropOut} event.
|
||
*
|
||
* @cfg {Function|null} [onDragStart=null] The callback function to be executed everytime any of its draggable items
|
||
* starts to be dragged. For info about the parameters sent to the callback function read the documentation for
|
||
* the {@link #event-onDropOut onDropOut} event.
|
||
*
|
||
* @cfg {Function|null} [onAdd=null] The callback function be executed eveytime the {@link #event-onAdd onAdd event}.
|
||
*/
|
||
var Container = function (settings) {
|
||
Container.superclass.call(this, settings);
|
||
/**
|
||
* @property {PMUI.util.ArrayList} items
|
||
* An ArrayList object that contains all the child Items
|
||
*/
|
||
this.items = null;
|
||
/**
|
||
* @property {PMUI.util.Factory} factory
|
||
* X
|
||
*/
|
||
this.factory = null;
|
||
/**
|
||
* @property {PMUI.behavior.ContainerItemBehavior} behaviorObject The container's behavior object.
|
||
* @private
|
||
*/
|
||
this.behaviorObject = null;
|
||
/**
|
||
* @property {String} behavior The behavior's pmType being used by the object.
|
||
* @readonly
|
||
*/
|
||
this.behavior = null;
|
||
/**
|
||
* @property {HTMLElement} containmentArea The HTML area in which the items HTML will be append
|
||
* @readonly
|
||
*/
|
||
this.containmentArea = null;
|
||
/**
|
||
* @event onDragStart
|
||
* Fired when the dragging is starting on any ot its items.
|
||
* @param {PMUI.core.Container} container The container from which the draggable is starting to be dragged.
|
||
* @param {PMUI.core.Element} draggableItem The item thais starting to be dragged.
|
||
*/
|
||
this.onDragStart = null;
|
||
/**
|
||
* @event onDrop
|
||
* Fired everytime a draggable item is dropped on the container.
|
||
* @param {PMUI.core.Container} container The container on which the draggable item was dropped.
|
||
* @param {PMUI.core.Element} draggableItem The item that was dropped on the container.
|
||
* @param {Number} index The order index in which the new element was dropped.
|
||
*/
|
||
this.onDrop = null;
|
||
/**
|
||
* @event onDropOut
|
||
* Fired when a draggable item is drop out from the container to another one.
|
||
* @param {PMUI.core.Element} draggable The draggable PMUI object involved in the action.
|
||
* @param {PMUI.core.Container} origin The container the draggable item was drag from.
|
||
* @param {PMUI.core.Container} destiny The container the draggable was dropped on.
|
||
*/
|
||
this.onDropOut = null;
|
||
/**
|
||
* @event
|
||
* Fired before an item is added to the container by dropping.
|
||
* @param {PMUI.core.Element} draggableItem The container.
|
||
* @param {PMUI.core.Element} draggableItem The item that was dropped and is ready to be appended to the
|
||
* container.
|
||
* @param {Number} index The new element's order index in which it will be added.
|
||
*/
|
||
this.onBeforeDrop = null;
|
||
/**
|
||
* @event onSort
|
||
* Fired everytime a container's item order changes.
|
||
* @param {PMUI.core.Container} container The container on which the sort occur.
|
||
* @param {PMUI.core.Element} orderedElement The element which was ordered.
|
||
* @param {Number} index The new element's order index.
|
||
*/
|
||
this.onSort = null;
|
||
/**
|
||
* Specifies which items inside the element should be sortable in case a drag/sort behavior is applied.
|
||
* @type {String}
|
||
*/
|
||
this.sortableItems = null;
|
||
/**
|
||
* If the container is disabled or not. Set by the {@link #cfg-disabled disabled} config option and the
|
||
* {@link #method-disable disable()} method.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.disabled = null;
|
||
/**
|
||
* If the container's behavior is disabled or not. Set by the {@link #cfg-disabledBehavio disabledBehavior} config option and the
|
||
* {@link #method-disableBehavior disableBehavior()} method.
|
||
* @type {Boolean}
|
||
*/
|
||
this.disabledBehavior = null;
|
||
/**
|
||
* A flag that indicates if actually a massive action is being performed.
|
||
* @private
|
||
* @type {Boolean}
|
||
*/
|
||
this.massiveAction = false;
|
||
/**
|
||
* @event onAdd
|
||
* Fired everytime an item is added to the object.
|
||
* @param {PMUI.core.Container} container The container in which the item was added to.
|
||
* @param {PMUI.core.Element} item The item that was added.
|
||
* @param {Number} index The index in which the item was added.
|
||
*/
|
||
this.onAdd = null;
|
||
/**
|
||
* @property {String} dragDropBehaviorScope A draggable/droppable container with the same scope value as
|
||
* another droppable/draggable container's item will be accepted by the behavior.
|
||
*/
|
||
this.dragDropBehaviorScope = null;
|
||
|
||
this.onSortStart = null;
|
||
this.onStopDrag = null;
|
||
/**
|
||
* Restricts dragging/sorting from starting unless the mousedown occurs on the specified element(s). Only
|
||
* elements that descend from the draggable element are permitted.
|
||
* @type {String}
|
||
*/
|
||
this.dragHandler = null;
|
||
Container.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', Container);
|
||
|
||
Container.prototype.type = 'Container';
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} settings A JSON object with the config options.
|
||
* @private
|
||
*/
|
||
Container.prototype.init = function (settings) {
|
||
var defaults = {
|
||
items: [],
|
||
behavior: 'nobehavior',
|
||
dataItems: null,
|
||
onDragStart: null,
|
||
onBeforeDrop: null,
|
||
onDrop: null,
|
||
onDropOut: null,
|
||
onSort: null,
|
||
sortableItems: '> *',
|
||
disabled: false,
|
||
onAdd: null,
|
||
onSortStart: null,
|
||
onStopDrag: null,
|
||
dragDropBehaviorScope: 'pmui-containeritem-behavior',
|
||
dragHandler: null
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.items = new PMUI.util.ArrayList();
|
||
|
||
this.setFactory(defaults.factory)
|
||
.setOnAddHandler(defaults.onAdd);
|
||
|
||
if (jQuery.isArray(defaults.dataItems)) {
|
||
this.setDataItems(defaults.dataItems);
|
||
} else {
|
||
this.setItems(defaults.items);
|
||
}
|
||
|
||
this.setSortableItems(defaults.sortableItems)
|
||
.setDragHandler(defaults.dragHandler)
|
||
.setDragDropBehaviorScope(defaults.dragDropBehaviorScope)
|
||
.setBehavior(defaults.behavior)
|
||
.setOnDragStartHandler(defaults.onDragStart)
|
||
.setOnBeforeDropHandler(defaults.onBeforeDrop)
|
||
.setOnDropHandler(defaults.onDrop)
|
||
.setOnDropOutHandler(defaults.onDropOut)
|
||
.setOnSortHandler(defaults.onSort);
|
||
this.setOnSortStartHandler(defaults.onSortStart);
|
||
this.setOnStopDragHandler(defaults.onStopDrag);
|
||
if (this.disabled) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
};
|
||
/**
|
||
* If specified, restricts dragging/sorting from starting unless the mousedown occurs on the specified element(s).
|
||
* Only elements that descend from the draggable element are permitted.
|
||
* @param {String} handler The selector for the handler.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.setDragHandler = function (handler) {
|
||
if (!(typeof handler === 'string' || handler === null)) {
|
||
throw new Error("The parameter must be a string or null");
|
||
}
|
||
this.dragHandler = handler;
|
||
this.setBehavior(this.behavior);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the {@link #property-dragDropBehaviorScope dragDropBehaviorScope} property.
|
||
* @param {String} scope Any string that represents a scope.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.setDragDropBehaviorScope = function (scope) {
|
||
if (typeof scope !== 'string') {
|
||
throw new Error("setDragDropBehaviorScope(): The parameter must be a string.");
|
||
}
|
||
this.dragDropBehaviorScope = scope;
|
||
this.setBehavior(this.behavior);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the handler to be executed everytime the {@link #event-onAdd onAdd} event is fired.
|
||
* @param {Function|null} handler The handler to execute, it also can be null.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.setOnAddHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error('setOnAddHandler(): The parameter ust be a function or null.');
|
||
}
|
||
this.onAdd = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback function to be executed everytime any of its draggable items stop to be dragged.
|
||
* @param {Function|null} handler It can be a function or null.
|
||
*/
|
||
Container.prototype.setOnStopDragHandler = function (handler) {
|
||
if (handler !== null && typeof handler !== 'function') {
|
||
throw new Error('setOnStopDragHandler(): the parameter must be a function or null.');
|
||
}
|
||
this.onStopDrag = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback function to be executed everytime any of its draggable items starts to be dragged. For info
|
||
* about the parameters sent to the callback function read the documentation for
|
||
* the {@link #event-onDropOut onDropOut} event.
|
||
* @param {Function|null} handler It can be a function or null.
|
||
*/
|
||
Container.prototype.setOnDragStartHandler = function (handler) {
|
||
if (!(typeof handler === 'function' || handler === null)) {
|
||
throw new Error('setOnDragStartHandler(): the parameter must be a function or null.');
|
||
}
|
||
this.onDragStart = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback function to be executed when a draggable item is dragged from the container and dropped on
|
||
* another container. This callback can return a boolean value or not return anything. If it returns "false" then
|
||
* the drop action will be cancelled. For info about the parameters sent to the callback function please read the
|
||
* {@link PMUI.core.Container#event-onDrop onDrop} event documentation.
|
||
* @param {Function|null} handler
|
||
* @chainable
|
||
*/
|
||
Container.prototype.setOnDropOutHandler = function (handler) {
|
||
if (!(typeof handler === 'function' || handler === null)) {
|
||
throw new Error('setOnDropOutHandler(): the parameter must be a function or null.');
|
||
}
|
||
this.onDropOut = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables the container's behavior.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.disableBehavior = function () {
|
||
this.disabledBehavior = true;
|
||
this.behaviorObject.disable();
|
||
return this;
|
||
};
|
||
/**
|
||
* Enables the container's behavior.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.enableBehavior = function () {
|
||
this.disabledBehavior = false;
|
||
this.behaviorObject.enable();
|
||
this.disabled = false;
|
||
this.style.removeClasses(['pmui-disabled']);
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables interactive functions like the drag, drop, sort behaviors.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.disable = function () {
|
||
this.disabled = true;
|
||
this.style.addClasses(['pmui-disabled']);
|
||
return this.disableBehavior();
|
||
};
|
||
/**
|
||
* Enables interactive functions like the drag, drop, sort behaviors.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.enable = function () {
|
||
this.disabled = false;
|
||
this.style.removeClasses(['pmui-disabled']);
|
||
return this.enableBehavior();
|
||
};
|
||
/**
|
||
* Specifies which items inside the element should be sortable in case a drag/sort behavior is applied.
|
||
* @param {String} selector A jQuery selector.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.setSortableItems = function (selector) {
|
||
this.sortableItems = selector;
|
||
return this.setBehavior(this.behavior);
|
||
};
|
||
/**
|
||
* Sets the callback function to be executed everytime a container's item order changes.
|
||
* @param {Function} handler It can be a function or null. For info about the parameters sent to the callback
|
||
* function please read the {@link PMUI.core.Container#event-onSort onSort} event documentation.
|
||
*/
|
||
Container.prototype.setOnSortHandler = function (handler) {
|
||
if (handler !== null && typeof handler !== 'function') {
|
||
throw new Error('setOnSortHandler(): the parameter must be a function or null.');
|
||
}
|
||
this.onSort = handler;
|
||
return this;
|
||
};
|
||
|
||
Container.prototype.setOnSortStartHandler = function (handler) {
|
||
if (handler !== null && typeof handler !== 'function') {
|
||
throw new Error('setOnSortStartHandler(): the parameter must be a function or null.');
|
||
}
|
||
this.onSortStart = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback function to be executed before a draggable item is added to the container by dropping.
|
||
* @param {Function} handler It can be a function or null. For info about the parameters sent to the callback
|
||
* function please read the {@link PMUI.core.Container#event-onBeforeDrop onBeforeDrop} event documentation.
|
||
*/
|
||
Container.prototype.setOnBeforeDropHandler = function (handler) {
|
||
if (handler !== null && typeof handler !== 'function') {
|
||
throw new Error('setOnDropHandler(): the parameter must be a function or null.');
|
||
}
|
||
this.onBeforeDrop = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback function to be executed everytime a draggable item is dropped on the container.
|
||
* @param {Function} handler It can be a function or null. For info about the parameters sent to the callback
|
||
* function please read the {@link PMUI.core.Container#event-onDrop onDrop} event documentation.
|
||
*/
|
||
Container.prototype.setOnDropHandler = function (handler) {
|
||
if (handler !== null && typeof handler !== 'function') {
|
||
throw new Error('setOnDropHandler(): the parameter must be a function or null.');
|
||
}
|
||
this.onDrop = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a new item but using raw data to create it.
|
||
* @param {Object} dataItem A JSON object with the data to create the new object.
|
||
* @param {Number} [index] The position index in which the data item will be inserted.
|
||
*/
|
||
Container.prototype.addDataItem = function (dataItem, index) {
|
||
var args,
|
||
i;
|
||
if (typeof dataItem !== 'object') {
|
||
throw new Error('addDataItem(): The parameter must be an object.');
|
||
}
|
||
args = [{
|
||
data: dataItem
|
||
}];
|
||
for (i = 1; i < arguments.length; i += 1) {
|
||
args.push(arguments[i]);
|
||
}
|
||
this.addItem.apply(this, args);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the data toi be used to create every item to be contained by the object.
|
||
* @param {Array} dataItems An array in which each element is an object with the data for each of the items.
|
||
*/
|
||
Container.prototype.setDataItems = function (dataItems) {
|
||
var i;
|
||
if (jQuery.isArray(dataItems)) {
|
||
this.clearItems();
|
||
this.massiveAction = true;
|
||
for (i = 0; i < dataItems.length; i += 1) {
|
||
this.addDataItem(dataItems[i]);
|
||
}
|
||
this.massiveAction = false;
|
||
this.paintItems();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the html element in which the items are appended.
|
||
* @return {HTMLElement}
|
||
*/
|
||
Container.prototype.getContainmentArea = function () {
|
||
this.getHTML();
|
||
return this.containmentArea;
|
||
};
|
||
/**
|
||
* Returns all the container's items the behavior will be applied on.
|
||
* @return {Array} An array of items.
|
||
* @private
|
||
*/
|
||
Container.prototype.getBehavioralItems = function () {
|
||
return this.getItems();
|
||
};
|
||
/**
|
||
* Enables/disables one, two, all of the following behaviors:
|
||
*
|
||
* - "drag", allows to drag items from the object, also them can be dropped on another containers that have enables
|
||
* the "drop" behavior.
|
||
* - "drop", allows to drop draggable items from another container on the object.
|
||
* - "sort", allows reorder the items in the object. Combined with "drop" behavior makes the object capable to
|
||
* receive objects (drop) in a specific position.
|
||
* @param {String} behavior The behavior to be set, the accepted values are:
|
||
*
|
||
* - "drag", enables the dragging functionality.
|
||
* - "dragclone", enables the clone-dragging functionality.
|
||
* - "drop", enables the dropping functionality.
|
||
* - "sort", enabled the sorting functionality.
|
||
* - "dragdrop", enables both dragging and dropping functionality.
|
||
* - "dragsort", enables both dragging and sorting functionality.
|
||
* - "dropsort", enables both dropping and sorting functionality.
|
||
* - "dragdropsort", enables the three behaviors: dragging, dropping and sorting.
|
||
* - "nobehavior", disables all the behaviors.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.setBehavior = function (behavior, index) {
|
||
var obj,
|
||
behaviorObject,
|
||
factory;
|
||
|
||
if (typeof behavior === 'string') {
|
||
factory = new PMUI.behavior.ContainerItemBehaviorFactory();
|
||
obj = {
|
||
pmType: behavior,
|
||
targetObject: this,
|
||
scope: this.dragDropBehaviorScope,
|
||
handle: this.dragHandler
|
||
};
|
||
if (this.behaviorObject) {
|
||
this.behaviorObject.detachBehavior();
|
||
}
|
||
behaviorObject = factory.make(obj);
|
||
if (behaviorObject) {
|
||
this.behaviorObject = behaviorObject;
|
||
this.behavior = behavior;
|
||
}
|
||
if (this.html) {
|
||
if (index !== undefined) {
|
||
this.behaviorObject.attachBehavior(index);
|
||
} else {
|
||
this.behaviorObject.attachBehavior();
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Container.prototype.addingBehaviorsElement = function (behavior, index) {
|
||
var obj,
|
||
behaviorObject,
|
||
factory;
|
||
|
||
if (typeof behavior === 'string') {
|
||
factory = new PMUI.behavior.ContainerItemBehaviorFactory();
|
||
obj = {
|
||
pmType: behavior,
|
||
targetObject: this,
|
||
scope: this.dragDropBehaviorScope,
|
||
handle: this.dragHandler
|
||
};
|
||
if (this.behaviorObject) {
|
||
this.behaviorObject.detachBehavior();
|
||
}
|
||
behaviorObject = factory.make(obj);
|
||
if (behaviorObject) {
|
||
this.behaviorObject = behaviorObject;
|
||
this.behavior = behavior;
|
||
}
|
||
if (this.html) {
|
||
if (index !== undefined) {
|
||
this.behaviorObject.attachBehavior(index);
|
||
} else {
|
||
this.behaviorObject.attachBehavior();
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the "factory" property with a {PMUI.util.Factory} object
|
||
* @param {Object} factory
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
Container.prototype.setFactory = function (factory) {
|
||
if (factory instanceof PMUI.util.Factory) {
|
||
this.factory = factory;
|
||
} else {
|
||
this.factory = new PMUI.util.Factory(factory);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Removes a child element from the object
|
||
* @param {PMUI.core.Element|String|Number} item It can be a string (id of the child to remove),
|
||
a number (index of the child to remove) or a {Element} object.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.removeItem = function (item) {
|
||
var itemToRemove,
|
||
parent;
|
||
if (item instanceof PMUI.core.Element) {
|
||
itemToRemove = item;
|
||
} else {
|
||
if (typeof item === 'string') {
|
||
itemToRemove = this.items.find("id", item.id);
|
||
} else if (typeof item === 'number') {
|
||
itemToRemove = this.items.get(item);
|
||
}
|
||
}
|
||
if (itemToRemove) {
|
||
parent = itemToRemove.parent;
|
||
if (parent) {
|
||
parent.items.remove(itemToRemove);
|
||
} else {
|
||
this.items.remove(itemToRemove);
|
||
}
|
||
itemToRemove.parent = null;
|
||
if (this.html) {
|
||
jQuery(itemToRemove.html).detach();
|
||
}
|
||
}
|
||
if (!this.items.getSize()) {
|
||
this.style.addClasses(['pmui-empty']);
|
||
}
|
||
if (this.massiveAction) {
|
||
return this;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes all the child items
|
||
* @chainable
|
||
*/
|
||
Container.prototype.clearItems = function () {
|
||
this.massiveAction = true;
|
||
while (this.items.getSize() > 0) {
|
||
this.removeItem(0);
|
||
}
|
||
this.massiveAction = false;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns true if the item, used as the unique method parameter, is a direct child of the current Container object,
|
||
otherwise returns false
|
||
* @param {PMUI.core.Element} item The target child object
|
||
* @return {Boolean}
|
||
*/
|
||
Container.prototype.isDirectParentOf = function (item) {
|
||
return this.items.indexOf(item) >= 0;
|
||
};
|
||
/**
|
||
* Returns true if the supplied argument can be accepted as an item of the container.
|
||
* @param {PMUI.core.Element} obj The element to be evaluated.
|
||
* @return {Boolean}
|
||
*/
|
||
Container.prototype.canContain = function (obj) {
|
||
return obj instanceof PMUI.core.Element ? this.factory.isValidClass(obj) : false;
|
||
};
|
||
/**
|
||
* Paint a container's item (puts its HTML into the container's HTML).
|
||
* @param {PMUI.core.Element} item The item to add.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
Container.prototype.paintItem = function (item, index) {
|
||
var referenceItem;
|
||
if (this.html) {
|
||
if (index !== null && index !== undefined) {
|
||
referenceItem = this.items.get(index + 1);
|
||
if (referenceItem) {
|
||
this.containmentArea.insertBefore(item.getHTML(), referenceItem.getHTML());
|
||
} else {
|
||
this.containmentArea.appendChild(item.getHTML());
|
||
}
|
||
} else {
|
||
this.containmentArea.appendChild(item.getHTML());
|
||
}
|
||
if (this.eventsDefined) {
|
||
item.defineEvents();
|
||
}
|
||
index = this.items.indexOf(item);
|
||
this.setBehavior(this.behavior, index);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Paint all the container items.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
Container.prototype.paintItems = function () {
|
||
var items,
|
||
i;
|
||
if (this.containmentArea) {
|
||
items = this.items.asArray()
|
||
for (i = 0; i < items.length; i += 1) {
|
||
this.paintItem(items[i]);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds an child item to the object.
|
||
* @param {PMUI.core.Element|Object} item It can be one of the following data types:
|
||
* - {PMUI.core.Element} the object to add.
|
||
* - {Object} a JSON object with the settings for the Container to be added.
|
||
* @param {Number} [index] An index in which the item will be added.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.addItem = function (item, index) {
|
||
var itemToBeAdded;
|
||
if (this.factory) {
|
||
itemToBeAdded = this.factory.make(item);
|
||
}
|
||
if (itemToBeAdded && !this.isDirectParentOf(itemToBeAdded)) {
|
||
if (index !== null && index !== undefined) {
|
||
this.items.insertAt(itemToBeAdded, index);
|
||
} else {
|
||
this.items.insert(itemToBeAdded);
|
||
}
|
||
itemToBeAdded.parent = this;
|
||
if (!this.massiveAction) {
|
||
this.paintItem(itemToBeAdded, index);
|
||
}
|
||
if (typeof this.onAdd === 'function') {
|
||
index = typeof index === 'number' ? index : this.items.getSize() - 1;
|
||
this.onAdd(this, this.getItem(index), index);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Clear all the object's current child items and add new ones
|
||
* @param {Array} items An array where each element can be a {Element} object or a JSON object
|
||
where is specified the setting for the child item to be added
|
||
* @chainable
|
||
*/
|
||
Container.prototype.setItems = function (items) {
|
||
var i;
|
||
if (jQuery.isArray(items)) {
|
||
this.clearItems();
|
||
this.massiveAction = false;
|
||
for (i = 0; i < items.length; i += 1) {
|
||
this.addItem(items[i]);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns an array with all the child elements
|
||
* @return {Array}
|
||
*/
|
||
Container.prototype.getItems = function () {
|
||
return this.items.asArray();
|
||
};
|
||
/**
|
||
* Returns one single item based on the id or index position
|
||
* @param {String|Number} id If the parameter is a string then
|
||
it will be take as the id for the element to find and return,
|
||
but if the element is a Number it returns the object iwth that
|
||
index position
|
||
* @return {PMUI.core.Element}
|
||
*/
|
||
Container.prototype.getItem = function (i) {
|
||
var t;
|
||
if (typeof i === 'number') {
|
||
t = this.items.get(i);
|
||
} else if (typeof i === 'string') {
|
||
t = this.items.find('id', i);
|
||
} else if (this.items.indexOf(i) >= 0) {
|
||
t = i;
|
||
}
|
||
return t;
|
||
};
|
||
/**
|
||
* Returns the index for the specified item.
|
||
* @param {PMUI.core.Element|String} item It can be:
|
||
*
|
||
* - {@link PMUI.core.Element}
|
||
* - String, it will be interpreted as the items's id.
|
||
* @return {Number}
|
||
*/
|
||
Container.prototype.getItemIndex = function (item) {
|
||
var evaluatedItem;
|
||
|
||
if (item instanceof PMUI.core.Element) {
|
||
evaluatedItem = item;
|
||
} else if (typeof item === 'number') {
|
||
evaluatedItem = this.items.get(item);
|
||
} else if (typeof item === 'string') {
|
||
evaluatedItem = this.items.find("id", item);
|
||
}
|
||
|
||
return this.items.indexOf(evaluatedItem);
|
||
};
|
||
/**
|
||
* Creates the object's HTML element
|
||
* @return {HTMLElement}
|
||
*/
|
||
Container.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
Container.superclass.prototype.createHTML.call(this);
|
||
this.containmentArea = this.html;
|
||
this.paintItems();
|
||
this.style.applyStyle();
|
||
this.setBehavior(this.behavior);
|
||
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Moves an object's item from a position to another.
|
||
* @param {PMUI.core.Element} item The item to move.
|
||
* @param {Number} index The index position in which the item will be moved.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.moveItem = function (item, index) {
|
||
var items = this.items,
|
||
currentIndex,
|
||
referenceObject;
|
||
|
||
item = this.getItem(item);
|
||
|
||
if (item instanceof PMUI.core.Element && this.isDirectParentOf(item)) {
|
||
currentIndex = items.indexOf(item);
|
||
items = items.asArray();
|
||
referenceObject = this.items.get(index + (currentIndex < index ? 1 : 0));
|
||
item = items.splice(currentIndex, 1)[0];
|
||
this.items.remove(item);
|
||
this.items.insertAt(item, index);
|
||
if (this.html) {
|
||
if (index === this.items.getSize() - 1) {
|
||
this.containmentArea.appendChild(item.getHTML());
|
||
} else {
|
||
this.containmentArea.insertBefore(item.getHTML(), referenceObject.getHTML());
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the function to be executed when an accepted draggable is dragged over the droppable area.
|
||
* @return {Function}
|
||
*/
|
||
Container.prototype.onDragOver = function () {
|
||
return function () {
|
||
};
|
||
};
|
||
/**
|
||
* Returns the function to be executed when the items order has been changed.
|
||
* @return {Function}
|
||
* @private
|
||
*/
|
||
Container.prototype.onSortingChange = function () {
|
||
var that = this;
|
||
return function (e, ui) {
|
||
var itemHTML = ui.item.get(0),
|
||
item = PMUI.getPMUIObject(itemHTML),
|
||
newIndex;
|
||
newIndex = jQuery(that.getContainmentArea()).find('>*').index(itemHTML);
|
||
|
||
that.moveItem(item, newIndex);
|
||
if (typeof that.onSort === 'function') {
|
||
that.onSort(that, item, newIndex);
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Handler to be executed everytime the mouse enter a position over any container's draggable/sortable item.
|
||
* @param {PMUI.core.Element} draggable The draggable PMUI object.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.onDraggableMouseOver = function (draggable) {
|
||
return this;
|
||
};
|
||
/**
|
||
* Handler to be executed everytime the mouse leaves a position over any container's draggable/sortable item.
|
||
* @param {PMUI.core.Element} draggable The draggable PMUI object.
|
||
* @chainable
|
||
*/
|
||
Container.prototype.onDraggableMouseOut = function (draggable) {
|
||
return this;
|
||
};
|
||
/**
|
||
* Executes children events defined
|
||
* @return {PMUI.core.Container}
|
||
* @chainable
|
||
*/
|
||
Container.prototype.defineEvents = function () {
|
||
var j,
|
||
children,
|
||
that = this;
|
||
Container.superclass.prototype.defineEvents.call(this);
|
||
if (that.items.getSize() > 0) {
|
||
children = that.getItems();
|
||
for (j = 0; j < children.length; j += 1) {
|
||
children[j].defineEvents();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.core.Container', Container);
|
||
|
||
// Publish to NodeJS environment
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Container;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.core.Item
|
||
* @extends PMUI.core.Container
|
||
* Create a items container
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class
|
||
* @param {Object} options Contructor object
|
||
*/
|
||
var Item = function (options) {
|
||
Item.superclass.call(this, options);
|
||
|
||
/**
|
||
* Parent object associated to this item
|
||
* @type {Object}
|
||
*/
|
||
this.parent = null;
|
||
Item.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Container', Item);
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
Item.prototype.type = "Item";
|
||
|
||
/**
|
||
* Defines the object's family
|
||
* @type {String}
|
||
*/
|
||
Item.prototype.family = "Item";
|
||
|
||
/**
|
||
* @private
|
||
* Initializes the object with default values
|
||
* @param {Object} options
|
||
*/
|
||
Item.prototype.init = function (options) {
|
||
var defaults = {
|
||
parent: null
|
||
};
|
||
jQuery.extend(true, defaults, options);
|
||
this.setParent(defaults.parent);
|
||
};
|
||
|
||
/**
|
||
* Sets the parent object of the current item
|
||
* @param {Object} parent Parent object
|
||
*/
|
||
Item.prototype.setParent = function (parent) {
|
||
this.parent = parent;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the parent object pointer
|
||
* @return {Object}
|
||
*/
|
||
Item.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
/**
|
||
* Removes the item from its parent container.
|
||
* @chainable
|
||
*/
|
||
Item.prototype.remove = function () {
|
||
if (this.parent) {
|
||
this.parent.removeItem(this);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.core.Item', Item);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Item;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.core.Panel
|
||
* Handles panels to be inserted into containers, it is composed by three main elements: header, body and footer
|
||
* @abstract
|
||
* @extends {PMUI.core.Container}
|
||
*
|
||
* //Remember, this is an abstract class so it shouldn't be instantiate,
|
||
* //anyway we are instantiating it just for this example
|
||
* var p1, p2, panel;
|
||
* p1 = new PMUI.core.Panel({
|
||
* height : 140,
|
||
* width : 90,
|
||
* display : 'inline-block',
|
||
* style : {
|
||
* cssProperties : {
|
||
* 'background-color':'red'
|
||
* }
|
||
* }
|
||
* });
|
||
* p2 = new PMUI.core.Panel({
|
||
* height : 140,
|
||
* width : 90,
|
||
* display : 'inline-block',
|
||
* style : {
|
||
* cssProperties : {
|
||
* 'background-color':'yellow'
|
||
* }
|
||
* }
|
||
* });
|
||
* panel = new PMUI.core.Panel({
|
||
* height : 150,
|
||
* width : 200,
|
||
* display : 'block',
|
||
* items : [
|
||
* p1,
|
||
* p2
|
||
* ],
|
||
* layout : 'vbox',
|
||
* padding : "5px",
|
||
* borderWidth : "1px",
|
||
* border : true
|
||
* });
|
||
* document.body.appendChild(panel.getHTML());
|
||
*
|
||
* @constructor
|
||
* Creates a new instacne of the object
|
||
* @param {Object} settings
|
||
*
|
||
* @cfg {Object|PMUI.core.Panel|null} [panel=null] The panel to be appended into the current Panel. It can be an
|
||
* object literal with the {@link PMUI.core.Panel config options for Panel} or an instance of
|
||
* {@link PMUI.core.Panel Panel} or null.
|
||
* @cfg {PMUI.core.Container} [parent=null] The panel's parent element.
|
||
* @cfg {String|PMUI.layout.Layout} [layout='box'] The layout to be applied to the panel, the layout determines the
|
||
* render position for the panel's items. The possible layouts are:
|
||
*
|
||
* - box: this applies no layout to the panel. To set the layout to box if you use a string as value for the config
|
||
* option use "box", in the other case, if you use an object, use an instance of {@link PMUI.layout.Box Box}.
|
||
* - hbox: this applies a layout that renders the panel's items side by side using the items's
|
||
* {@link PMUI.core.Element#property-propotion proportion property} to calculate the width for each item. To set
|
||
* this layout to the panel, if you are using a string as the value for the config option, use "hbox", in the other
|
||
* case, if you are using an object use an instance of {@link PMUI.layout.HBox HBox}.
|
||
* - vbox: this applies a layout that renders the panel's items in vertical position using the items's
|
||
* {@link PMUI.core.Element#property-propotion proportion property} to calculate the height for each item. To set
|
||
* this layout to the panel, if you are using a string as the value for the config option, use "vbox", in the other
|
||
* case, if you are using an object use an instance of {@link PMUI.layout.VBox VBox}.
|
||
* @cfg {String|Number} [padding=""] Sets the css padding property for the panel. It can be a number or and string
|
||
* with the format ##px or an empty string. If you use an empty string as the parameter, the padding will be set
|
||
* dinamically from the used css file.
|
||
* @cfg {String|Number} [borderWidth=""] Sets the border width for the panel. It can be a number or a string with
|
||
* the format '##px' or an empty string. If you use an empty string as the parameter, the border width will be set
|
||
* dinamically from the used css file.
|
||
*/
|
||
var Panel = function (settings) {
|
||
Panel.superclass.call(this, settings);
|
||
/**
|
||
* The child {Panel} object
|
||
* @type {PMUI.core.Panel}
|
||
*/
|
||
this.panel = null;
|
||
/**
|
||
* The Panel's parent object
|
||
* @type {PMUI.core.Container}
|
||
*/
|
||
this.parent = null;
|
||
/**
|
||
* A {Layout} object which handles the position layout for the object's direct child elements
|
||
* @property {PMUI.layout.Layout}
|
||
*/
|
||
this.layout = null;
|
||
/**
|
||
* @property {String} [topPadding=""]
|
||
* The value for the css padding-top property to be applied to the object's html.
|
||
* @readonly
|
||
*/
|
||
this.topPadding = null;
|
||
/**
|
||
* @property {String} [leftPadding=""]
|
||
* The value for the css padding-left property to be applied to the object's html.
|
||
* @readonly
|
||
*/
|
||
this.leftPadding = null;
|
||
/**
|
||
* @property {String} [bottomPadding=""]
|
||
* The value for the css padding-bottom property to be applied to the object's html.
|
||
* @readonly
|
||
*/
|
||
this.bottomPadding = null;
|
||
/**
|
||
* @property {String} [rightPadding=""]
|
||
* The value for the css padding-right property to be applied to the object's html.
|
||
* @readonly
|
||
*/
|
||
this.rightPadding = null;
|
||
/**
|
||
* @property {String} [borderWidth=""] A string with the format ##px (where ## is a number).
|
||
* It determines the panel's border width.
|
||
* @readonly
|
||
*/
|
||
this.borderWidth = null;
|
||
/**
|
||
* @property {Boolean} [border=false] If the border is being shown.
|
||
* @readonly
|
||
*/
|
||
this.border = null;
|
||
Panel.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Container', Panel);
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
Panel.prototype.type = 'Panel';
|
||
|
||
/**
|
||
* @private
|
||
* Initializes the object with default values
|
||
* @param {Object} options
|
||
*/
|
||
Panel.prototype.init = function (settings) {
|
||
var defaults = {
|
||
panel: null,
|
||
parent: null,
|
||
layout: 'box',
|
||
padding: "",
|
||
borderWidth: ""
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setPanel(defaults.panel)
|
||
.setParent(defaults.parent)
|
||
.setLayout(defaults.layout)
|
||
.setPadding(defaults.padding)
|
||
.setBorderWidth(defaults.borderWidth);
|
||
|
||
};
|
||
/**
|
||
* Applies the css classes and ptoperties to the element's html which the object is related
|
||
* @chainable
|
||
*/
|
||
Panel.prototype.applyStyle = function () {
|
||
if (this.html) {
|
||
this.style.applyStyle();
|
||
|
||
this.style.addProperties({
|
||
display: this.visible ? this.display : "none",
|
||
position: this.positionMode,
|
||
left: this.x,
|
||
top: this.y,
|
||
width: this.width,
|
||
height: this.height,
|
||
zIndex: this.zOrder,
|
||
"padding-top": this.topPadding,
|
||
"padding-right": this.rightPadding,
|
||
"padding-bottom": this.bottomPadding,
|
||
"padding-left": this.leftPadding,
|
||
"border-width": this.borderWidth,
|
||
"border-style": this.borderWidth !== "" ? "solid" : "",
|
||
"box-sizing": "border-box"
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the border width for the panel
|
||
* @param {String|Number} width It can be a number or a string with the format '##px' or an empty string.
|
||
* If you use an empty string as the parameter, the border width will be set dinamically from the used css file.
|
||
*/
|
||
Panel.prototype.setBorderWidth = function (width) {
|
||
var error = false;
|
||
if (typeof width === 'number') {
|
||
this.borderWidth = width + "px";
|
||
} else if (typeof width === 'string') {
|
||
width = jQuery.trim(width);
|
||
if (/^\d+(\.\d+)?px$/.test(width) || width === "") {
|
||
this.borderWidth = width;
|
||
} else {
|
||
error = true;
|
||
}
|
||
} else {
|
||
error = false;
|
||
}
|
||
|
||
if (error) {
|
||
throw new Error("setBorderWidth(): invalid parameter.");
|
||
} else {
|
||
this.applyStyle();
|
||
if (this.layout) {
|
||
this.layout.applyLayout();
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the border width from the object
|
||
* @return {String}
|
||
*/
|
||
Panel.prototype.getBorderWidth = function () {
|
||
return this.borderWidth || this.style.getProperty("border-width");
|
||
};
|
||
/**
|
||
* Sets the padding values for the panel.
|
||
* @param {String|Number} padding It can be a number or and string with the format ##px or an empty string.
|
||
* If you use an empty string as the parameter, the padding will be set dinamically from the used css file.
|
||
*/
|
||
Panel.prototype.setPadding = function (padding) {
|
||
var error = false;
|
||
if (typeof padding === 'string') {
|
||
padding = jQuery.trim(padding);
|
||
padding = padding.split(/\s+/).join(" ");
|
||
if (/^(\d+(\.\d+)?(px|%)\s)+$/.test(padding + " ")) {
|
||
padding = padding.match(/\d+(\.\d+)?(px|%)/g);
|
||
switch (padding.length) {
|
||
case 4:
|
||
this.topPadding = padding[0];
|
||
this.rightPadding = padding[1];
|
||
this.bottomPadding = padding[2];
|
||
this.leftPadding = padding[3];
|
||
break;
|
||
case 3:
|
||
this.topPadding = padding[0];
|
||
this.rightPadding = this.leftPadding = padding[1];
|
||
this.bottomPadding = padding[2];
|
||
break;
|
||
case 2:
|
||
this.topPadding = this.bottomPadding = padding[0];
|
||
this.rightPadding = this.leftPadding = padding[1];
|
||
break;
|
||
case 1:
|
||
this.topPadding = this.rightPadding = this.bottomPadding = this.leftPadding = padding[0];
|
||
break;
|
||
}
|
||
} else if (padding === "") {
|
||
this.topPadding = this.rightPadding = this.bottomPadding = this.leftPadding = "";
|
||
} else {
|
||
error = true;
|
||
}
|
||
} else if (typeof padding === 'number') {
|
||
this.topPadding = this.rightPadding = this.bottomPadding = this.leftPadding = padding + "px";
|
||
} else {
|
||
error = true;
|
||
}
|
||
|
||
if (error) {
|
||
throw new Error("setPadding(): Invalid parameter.");
|
||
} else {
|
||
this.applyStyle();
|
||
if (this.layout) {
|
||
this.layout.applyLayout();
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns an array with the padding values in the following order: [top, right, bottom, left].
|
||
* @return {Array}
|
||
*/
|
||
Panel.prototype.getPadding = function () {
|
||
return [
|
||
this.topPadding || this.style.getProperty("padding-top"),
|
||
this.rightPadding || this.style.getProperty("padding-right"),
|
||
this.bottomPadding || this.style.getProperty("padding-bottom"),
|
||
this.leftPadding || this.style.getProperty("padding-left")
|
||
];
|
||
};
|
||
/**
|
||
* Sets the panel object
|
||
* @param {Object} panel Panel object
|
||
*/
|
||
Panel.prototype.setPanel = function (panel) {
|
||
if (panel) {
|
||
if (panel instanceof Panel) {
|
||
this.panel = panel;
|
||
} else if (typeof panel === 'object') {
|
||
this.panel = new Panel(panel);
|
||
}
|
||
|
||
if (this.html) {
|
||
jQuery(this.html).empty().append(panel.getHTML());
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the object's html usable width.
|
||
* @return {Number|String} It can return a Number or an String with a css property like "auto".
|
||
*/
|
||
Panel.prototype.getUsableWidth = function () {
|
||
var padding = this.getPadding(), border = parseInt(this.getBorderWidth(), 10) * 2;
|
||
if (isNaN(this.getWidth())) {
|
||
return this.getWidth();
|
||
}
|
||
return this.getWidth() - (parseInt(padding[1], 10) || 0) - (parseInt(padding[3], 10) || 0) - (border || 0);
|
||
};
|
||
/**
|
||
* Returns the object's html usable height
|
||
* @return {Number|String} It can return a Number or an String with a css property like "auto".
|
||
*/
|
||
Panel.prototype.getUsableHeight = function () {
|
||
var padding = this.getPadding(), border = parseInt(this.getBorderWidth(), 10) * 2;
|
||
if (isNaN(this.getHeight())) {
|
||
return this.getHeight();
|
||
}
|
||
return this.getHeight() - (parseInt(padding[0], 10) || 0) - (parseInt(padding[2], 10) || 0) - (border || 0);
|
||
};
|
||
/**
|
||
* Sets the parent object
|
||
* @param {Object} parent
|
||
*/
|
||
Panel.prototype.setParent = function (parent) {
|
||
this.parent = parent;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the layout for the panel.
|
||
* @param {Object|String} layout Layout object
|
||
*/
|
||
Panel.prototype.setLayout = function (layout) {
|
||
var factory = new PMUI.layout.LayoutFactory();
|
||
if (!(typeof layout === "string")) {
|
||
throw new Error("setLayout(): Property values sent an invalid, expected 'box' , 'vbox' or 'hbox'");
|
||
}
|
||
this.layout = factory.make(layout);
|
||
this.layout.setContainer(this);
|
||
if (this.html) {
|
||
this.layout.applyLayout();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Add an item to the panel.
|
||
* @param {PMUI.core.Element|Object} item.
|
||
* @param {Number} [index] The index position in which the item will be appended.
|
||
* It can be a valid JSON object or an object that inherits from {@link PMUI.core.Element Element}.
|
||
* @chainable
|
||
*/
|
||
Panel.prototype.addItem = function (item, index) {
|
||
Panel.superclass.prototype.addItem.call(this, item, index);
|
||
if (this.layout) {
|
||
this.layout.applyLayout();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the width for the Panel's HTML element
|
||
* @param {Number|String} width It can be a number or a string.
|
||
* In case of using a String you only can use 'auto' or 'inherit' or ##px or ##% or ##em when ## is a number
|
||
* @chainable
|
||
*/
|
||
Panel.prototype.setWidth = function (width) {
|
||
Panel.superclass.prototype.setWidth.call(this, width);
|
||
if (this.layout) {
|
||
this.layout.applyLayout();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the height for the Panel's HTML element
|
||
* @param {Number|String} height It can be a number or a string.
|
||
* In case of using a String you only can use 'auto' or 'inherit' or ##px or ##% or ##em when ## is a number
|
||
* @chainable
|
||
*/
|
||
Panel.prototype.setHeight = function (height) {
|
||
Panel.superclass.prototype.setHeight.call(this, height);
|
||
if (this.layout) {
|
||
this.layout.applyLayout();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the object pointed to the parent
|
||
* @return {Object}
|
||
*/
|
||
Panel.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
/**
|
||
* Creates the HTML element for the Panel
|
||
* @return {HTMLElement}
|
||
*/
|
||
Panel.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
Panel.superclass.prototype.createHTML.call(this);
|
||
this.applyStyle();
|
||
if (this.layout) {
|
||
this.layout.applyLayout();
|
||
}
|
||
|
||
return this.html;
|
||
};
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = Panel;
|
||
}
|
||
|
||
PMUI.extendNamespace('PMUI.core.Panel', Panel);
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.control.Control
|
||
* Class that encapsulates the basic bahavior for a form control.
|
||
* Since this class is abstract it shouldn't be instantiated.
|
||
* @extends PMUI.core.Element
|
||
* @abstract
|
||
*
|
||
* Usage example (only for subclasses since this is an abstract class):
|
||
*
|
||
* //Remember, this is an abstract class so it shouldn't be instantiate,
|
||
* //anyway we are instantiating it just for this example
|
||
* var myControl = new PMUI.control.Control({
|
||
* name: "phrase",
|
||
* value: "Sometimes the sun goes down!",
|
||
* disabled: false,
|
||
* onChange: function(currentValue, previousValue) {
|
||
* console.log(this.name + " has changed!");
|
||
* console.log("Its previous value was: " + previousValue);
|
||
* console.log("Its current value is: " + currentValue);
|
||
* }
|
||
* });
|
||
*
|
||
* @constructor
|
||
* While it is true that this class must not be instantiated,
|
||
* it is useful to mention the settings parameter for the constructor
|
||
* function (which will be used for the non abstract subclasses).
|
||
* The parameter for the constructor will be a JSON object whose properties are specified in the
|
||
* {@link PMUI.control.Control#cfg-disabled Config Options section}.
|
||
*
|
||
* @cfg {String} [name=The object's ID] The name for the control. If it is not specified then the object's id is
|
||
* used.
|
||
* @cfg {String} [value=""] The initial value to be set to the control.
|
||
* @cfg {PMUI.form.Field} [field=null] The parent {@link PMUI.form.Field Field} object for the control.
|
||
* @cfg {Boolean} [disabled=false] A boolean value which determines if the control will be enabled or not.
|
||
* @cfg {Function} [onChange=null] A callback function to be invoked when the control changes. For info about the
|
||
* received parameters please read the {@link PMUI.control.Control#event-onChange onChange event} section.
|
||
* @cfg {Function} [onBeforeChange=null] A callback function to be invoked after the control's value changes. The
|
||
* function can return false to avoid the value changing. For info about the received parameter please read the
|
||
* {@link #event-onBeforeChange onBeforeChange event} documentation.
|
||
*/
|
||
var Control = function (settings) {
|
||
Control.superclass.call(this, settings);
|
||
/**
|
||
* @property {String} [name=id] The control's name, it defaults to null.
|
||
* @readonly
|
||
*/
|
||
this.name = null;
|
||
/**
|
||
* @property {String} [value=""] The control's value.
|
||
* @readonly
|
||
*/
|
||
this.value = null;
|
||
/**
|
||
* @property {PMUI.form.Field} [field=null] The {@link PMUI.form.Field Field}
|
||
object the current object belongs to.
|
||
* @readonly
|
||
*/
|
||
this.field = null;
|
||
/**
|
||
* @property {Boolean} [disabled=false] If the control is disabled or not.
|
||
* @readonly
|
||
*/
|
||
this.disabled = null;
|
||
/**
|
||
* @event onChange
|
||
* Fired when the control's value is changed.
|
||
* @param {String} newValue The new control's value.
|
||
* @param {String} prevValue The previous control's value.
|
||
*/
|
||
this.onChange = null;
|
||
/**
|
||
* @event onBeforeChange
|
||
* Fired after the control's value changes.
|
||
* @param {String} newValue The new control's value.
|
||
* @param {String} prevValue The previous vontrol's value.
|
||
*/
|
||
this.onBeforeChange = null;
|
||
Control.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', Control);
|
||
|
||
Control.prototype.type = "Control";
|
||
/**
|
||
* Initialize the object.
|
||
* @param {Object} settings The config options.
|
||
*/
|
||
Control.prototype.init = function (settings) {
|
||
var defaults = {
|
||
name: this.id,
|
||
value: "",
|
||
field: null,
|
||
disabled: false,
|
||
onBeforeChange: null,
|
||
onChange: null
|
||
};
|
||
|
||
$.extend(true, defaults, settings);
|
||
|
||
this.setName(defaults.name)
|
||
.setValue(defaults.value)
|
||
.setField(defaults.field)
|
||
.disable(defaults.disabled)
|
||
.setOnBeforeChangeHandler(defaults.onBeforeChange)
|
||
.setOnChangeHandler(defaults.onChange);
|
||
};
|
||
/**
|
||
* Sets the callback function to be executed when the {@link #event-onBeforeChange onBeforeChange event} fires.
|
||
* @param {Function|null} handler
|
||
* @chainable
|
||
*/
|
||
Control.prototype.setOnBeforeChangeHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error('setOnBeforeChangeHandler(): The parameter must be a function or null.');
|
||
}
|
||
this.onBeforeChange = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the control's name.
|
||
* @param {String} name
|
||
* @chainable
|
||
*/
|
||
Control.prototype.setName = function (name) {
|
||
if (typeof name === "string" || typeof name === "number") {
|
||
this.name = name.toString();
|
||
if (this.html) {
|
||
this.html.setAttribute("name", name);
|
||
}
|
||
} else {
|
||
throw new Error("The setName() method only accepts string or number values");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the control's name.
|
||
* @return {String}
|
||
*/
|
||
Control.prototype.getName = function () {
|
||
return this.name;
|
||
};
|
||
/**
|
||
* Sets the control's value.
|
||
* @param {String} value
|
||
* @chainable
|
||
*/
|
||
Control.prototype.setValue = function (value) {
|
||
if (typeof value !== 'undefined') {
|
||
this.value = value.toString();
|
||
} else {
|
||
throw new Error("setValue(): a parameter is required.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the control's value.
|
||
* @return {String}
|
||
*/
|
||
Control.prototype.getValue = function () {
|
||
return this.value;
|
||
};
|
||
/**
|
||
* Sets the control's parent {@link PMUI.form.Field Field} object.
|
||
* @param {PMUI.form.Field}
|
||
* @chainable
|
||
*/
|
||
Control.prototype.setField = function (field) {
|
||
if (field instanceof PMUI.form.Field) {
|
||
this.field = field;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the control's parent {@link PMUI.form.Field Field} object.
|
||
* @return {PMUI.form.Field}
|
||
*/
|
||
Control.prototype.getField = function () {
|
||
return this.field;
|
||
};
|
||
/**
|
||
* Disables/enables the control.
|
||
* @param {Boolean} disable If the value is evaluated as true then the control is disabled,
|
||
otherwise the control is enabled.
|
||
* @chainable
|
||
*/
|
||
Control.prototype.disable = function (disable) {
|
||
this.disabled = !!disable;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns true if the control is enabled, if it don't then it returns false
|
||
* @return {Boolean}
|
||
*/
|
||
Control.prototype.isEnabled = function () {
|
||
return !this.disabled;
|
||
};
|
||
/**
|
||
* Sets the callback function which will be executed everytime the control changes (using the interface).
|
||
*
|
||
* The callback function will receive two parameters:
|
||
*
|
||
* - first argument: the current control's value.
|
||
* - second argument: the previous control's value.
|
||
*
|
||
*
|
||
* //Remember, this is an abstract class so it shouldn't be instantiate,
|
||
* //anyway we are instantiating it just for this example
|
||
* var myControl = new PMUI.control.Control({
|
||
* name: "phrase",
|
||
* value: "Sometimes the sun goes down!",
|
||
* disabled: false
|
||
* });
|
||
*
|
||
* myControl.setOnChangeHandler(function(currentValue, previousValue) {
|
||
* console.log(this.name + " has changed!");
|
||
* console.log("Its previous value was: " + previousValue);
|
||
* console.log("Its current value is: " + currentValue);
|
||
* });
|
||
*
|
||
* @chainable
|
||
*/
|
||
Control.prototype.setOnChangeHandler = function (handler) {
|
||
if (typeof handler === 'function') {
|
||
this.onChange = handler;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the control's value directly from the control's HTML element.
|
||
*
|
||
* This method is used internally by the object, so in most of the cases you won't need to invocated.
|
||
* To get the control's value please use the {@link PMUI.control.Control#getValue getValue()} method.
|
||
*
|
||
* Since this is an abstract method, it must be implemented in its non-abstract subclasses
|
||
* @return {String}
|
||
* @abstract
|
||
*/
|
||
Control.prototype.getValueFromRawElement = function () {
|
||
throw new Error("Calling getValueFromRawElement() from PMUI.control.Control: this is an abstract method!");
|
||
};
|
||
/**
|
||
* A method which is called everytime the control changes.
|
||
*
|
||
* This method is used internally by the object, so in most of the cases you won't need to invocated.
|
||
* To execute instructions when the control changes, please use the
|
||
{@link PMUI.control.Control#setOnChangeHandler setOnChangeHandler()} method.
|
||
*
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
Control.prototype.onChangeHandler = function () {
|
||
var prevValue = this.value, newValue = this.getValueFromRawElement(), resCallback;
|
||
if (typeof this.onBeforeChange === 'function' && newValue !== prevValue) {
|
||
resCallback = this.onBeforeChange(newValue, prevValue);
|
||
if (resCallback === false) {
|
||
newValue = prevValue;
|
||
this.setValue(newValue);
|
||
}
|
||
}
|
||
this.value = newValue;
|
||
if (typeof this.onChange === 'function' && this.value !== prevValue) {
|
||
this.onChange(this.value, prevValue);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Attach the event listeners for the control's HTML element.
|
||
*
|
||
* Since this is an abstract method, it must be implemented in its non-abstract subclasses
|
||
* @abstract
|
||
* @chainable
|
||
*/
|
||
Control.prototype.attachListeners = function () {
|
||
throw new Error("Calling attachListeners() from PMUI.control.Control: this is an abstract method!");
|
||
};
|
||
/**
|
||
* Creates the HTML element for the control.
|
||
*
|
||
* Since this is an abstract method, it must be implemented in its non-abstract subclasses
|
||
* @return {HTMLElement}
|
||
* @abstract
|
||
*/
|
||
Control.prototype.createHTML = function () {
|
||
Control.superclass.prototype.createHTML.call(this);
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Returns the HTML element for the control
|
||
* @return {HTMLElement}
|
||
*/
|
||
Control.prototype.getHTML = function () {
|
||
if (!this.html) {
|
||
this.html = this.createHTML();
|
||
}
|
||
|
||
return this.html;
|
||
};
|
||
/**
|
||
* @method setFocus
|
||
* set the focus on control
|
||
* @chainable
|
||
*/
|
||
Control.prototype.setFocus = function () {
|
||
if (this.html && this.html.focus) {
|
||
this.html.focus();
|
||
}
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.control.Control', Control);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = Control;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.control.HTMLControl
|
||
* Class that encapsulates the HTML native control's behavior.
|
||
* Since this class is abstract it shouldn't be instantiated.
|
||
* @extends PMUI.control.Control
|
||
* @abstract
|
||
*
|
||
* @constructor
|
||
* While it is true that this class must not be instantiated,
|
||
* it is useful to mention that the settings parameter for the constructor function
|
||
* has the same structure that the one for the superclass
|
||
* (for more info see the {@link PMUI.control.Control#constructor constructor} method for Control class).
|
||
* @param {Object} [settings=null] A JSON object with the config options.
|
||
*/
|
||
var HTMLControl = function (settings) {
|
||
HTMLControl.superclass.call(this, settings);
|
||
/**
|
||
* @property {String} [elementTag='input'] The tag for the HTML element to be created.
|
||
* @private
|
||
*/
|
||
this.elementTag = 'input';
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.control.Control', HTMLControl);
|
||
|
||
HTMLControl.prototype.type = "HTMLControl";
|
||
|
||
/**
|
||
* Sets the value for the control
|
||
* @param {String} value
|
||
* @chainable
|
||
*/
|
||
HTMLControl.prototype.setValue = function (value) {
|
||
HTMLControl.superclass.prototype.setValue.call(this, value);
|
||
if (this.html && this.html.value !== this.value) {
|
||
this.html.value = this.value;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Disables/enables the control
|
||
* @param {Boolean} disable If the value is evaluated as true then the control
|
||
is disabled, otherwise the control is enabled.
|
||
* @chainable
|
||
*/
|
||
HTMLControl.prototype.disable = function (disable) {
|
||
HTMLControl.superclass.prototype.disable.call(this, disable);
|
||
if (this.html) {
|
||
this.html.disabled = this.disabled;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the control's value directly from the control's HTML element.
|
||
*
|
||
* This method is used internally by the object, so in most of the cases you won't need to invocated.
|
||
* To get the control's value please use the {@link PMUI.control.Control#getValue getValue()} method.
|
||
* @return {String}
|
||
*/
|
||
HTMLControl.prototype.getValueFromRawElement = function () {
|
||
return this.html.value;
|
||
};
|
||
/**
|
||
* Attach the event listeners for the control's HTML element
|
||
* @chainable
|
||
*/
|
||
HTMLControl.prototype.defineEvents = function () {
|
||
var that = this;
|
||
HTMLControl.superclass.prototype.defineEvents.call(this);
|
||
if (this.html) {
|
||
this.addEvent('blur').listen(this.html, function () {
|
||
that.onChangeHandler();
|
||
});
|
||
this.addEvent('keydown').listen(this.html, function (e) {
|
||
if (e.which === PMUI.keyCodeF5) {
|
||
this.blur();
|
||
e.preventDefault();
|
||
window.location.reload(true);
|
||
}
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the HTML element for the control.
|
||
* @return {HTMLElement}
|
||
*/
|
||
HTMLControl.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
HTMLControl.superclass.prototype.createHTML.call(this);
|
||
this.setName(this.name)
|
||
.setValue(this.value)
|
||
.disable(this.disabled);
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.control.HTMLControl', HTMLControl);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = HTMLControl;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.control.TextControl
|
||
* Class for handle the HTML native text input control.
|
||
* @extends PMUI.control.HTMLControl
|
||
*
|
||
* Quick usage example:
|
||
*
|
||
* @example
|
||
* myTextbox = new PMUI.control.TextControl({
|
||
* name: "my_name",
|
||
* value: "John Doe",
|
||
* maxLength: 12,
|
||
* placeholder: "insert your name here",
|
||
* disabled: false,
|
||
* onChange: function(currentValue, previousValue) {
|
||
* if(previousValue !== "") {
|
||
* alert("Your name is not \"" + previousValue + "\" anymore.\nNow it's \"" + currentValue + "\"");
|
||
* } else {
|
||
* alert("Now your name is " + currentValue);
|
||
* }
|
||
* }
|
||
* });
|
||
*
|
||
* document.body.appendChild(myTextbox.getHTML());
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the TextControl object.
|
||
* @param {Object} [settings=null] A JSON object with the config options.
|
||
*
|
||
* @cfg {String} [placeholder=""] A string to be used as the control's placeholder.
|
||
* @cfg {Number} [maxLength=524288] A number which specifies the maximum character length the control can accept.
|
||
* @cfg {Function} [onKeyUp=null] A callback function to be called every time a pressed key is released on the
|
||
* control. For info about the callback parameters please read the
|
||
* {@link PMUI.control.TextControl#event-onKeyUp onKeyUp event} section.
|
||
*/
|
||
var TextControl = function (settings) {
|
||
TextControl.superclass.call(this, settings);
|
||
/**
|
||
* @property {String} [placeholder=""]
|
||
* The control's placeholder (the text to be shown inside the control when there is not any text in it).
|
||
* @readonly
|
||
*/
|
||
this.placeholder = null;
|
||
/**
|
||
* @property {Number} [maxLength=524288] The maximum character length the control accepts.
|
||
* @readonly
|
||
*/
|
||
this.maxLength = null;
|
||
/**
|
||
* @event onKeyUp
|
||
* Fired when a pressed key is released.
|
||
* @param {Object} event The event object.
|
||
*/
|
||
this.onKeyUp = null;
|
||
TextControl.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.control.HTMLControl', TextControl);
|
||
|
||
TextControl.prototype.type = "TextControl";
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} [settings=null] A JSON object with the config options.
|
||
* @private
|
||
*/
|
||
TextControl.prototype.init = function (settings) {
|
||
var defaults = {
|
||
placeholder: "",
|
||
maxLength: 524288,
|
||
onKeyUp: null,
|
||
height: 30
|
||
};
|
||
|
||
$.extend(true, defaults, settings);
|
||
|
||
this.setPlaceholder(defaults.placeholder)
|
||
.setMaxLength(defaults.maxLength)
|
||
.setOnKeyUpHandler(defaults.onKeyUp)
|
||
.setHeight(defaults.height);
|
||
|
||
};
|
||
/**
|
||
* Sets the callback function to be called when the keyup event occurs.
|
||
* @chainable
|
||
*/
|
||
TextControl.prototype.setOnKeyUpHandler = function (handler) {
|
||
if (typeof handler === 'function') {
|
||
this.onKeyUp = handler;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the placeholder test to show in the control when there's not ant value in it.
|
||
* @param {String} placeholder
|
||
* @chainable
|
||
*/
|
||
TextControl.prototype.setPlaceholder = function (placeholder) {
|
||
if (typeof placeholder === 'string') {
|
||
this.placeholder = placeholder;
|
||
if (this.html) {
|
||
this.html.placeholder = placeholder;
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the maximun character number to be accepted in the control.
|
||
* @param {Number} maxLength The number must be an integer.
|
||
* If the value is minor or equal to 0 then the maxLength property is set to the default (524288).
|
||
* @chainable>
|
||
*/
|
||
TextControl.prototype.setMaxLength = function (maxLength) {
|
||
if (typeof maxLength === 'number' && maxLength % 1 === 0) {
|
||
this.maxLength = maxLength;
|
||
if (this.html) {
|
||
this.html.maxLength = maxLength > 0 ? maxLength : 524288;
|
||
}
|
||
} else {
|
||
throw new Error("method setMaxLength() only accepts integer values.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Set a value in the parameter disabled.
|
||
* @param {Boolean} value
|
||
*/
|
||
TextControl.prototype.setDisabled = function (value) {
|
||
if (typeof value === 'boolean') {
|
||
this.disabled = value;
|
||
if (this.html) {
|
||
this.html.disabled = value;
|
||
}
|
||
} else {
|
||
throw new Error("method setDisabled() only accepts boolean values.");
|
||
}
|
||
};
|
||
/**
|
||
* Set the events for the object.
|
||
* @chainable
|
||
*/
|
||
TextControl.prototype.defineEvents = function () {
|
||
var that = this;
|
||
TextControl.superclass.prototype.defineEvents.call(this);
|
||
if (this.html) {
|
||
this.addEvent('keyup').listen(this.html, function (e) {
|
||
if (typeof that.onKeyUp === 'function') {
|
||
that.onKeyUp(e);
|
||
}
|
||
//if(e.which == 13){
|
||
// that.onChangeHandler();
|
||
//}
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the HTML element for the object
|
||
* @return {HTMLElement}
|
||
*/
|
||
TextControl.prototype.createHTML = function () {
|
||
TextControl.superclass.prototype.createHTML.call(this);
|
||
this.html.type = "text";
|
||
this.setPlaceholder(this.placeholder)
|
||
.setMaxLength(this.maxLength)
|
||
.setReadOnly(this.readonly);
|
||
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Sets if the control will be enabled for read only.
|
||
* @param {Boolean}
|
||
* @chainable
|
||
*/
|
||
TextControl.prototype.setReadOnly = function (readonly) {
|
||
if (typeof readonly !== 'undefined') {
|
||
this.readonly = !!readonly;
|
||
if (this.html) {
|
||
this.html.readOnly = this.readonly;
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns true if the control is enabled for read only.
|
||
* @return {Boolean}
|
||
*/
|
||
TextControl.prototype.isReadOnly = function () {
|
||
return this.readonly;
|
||
};
|
||
|
||
TextControl.prototype.getMaxLength = function () {
|
||
return this.maxLength;
|
||
}
|
||
|
||
PMUI.extendNamespace('PMUI.control.TextControl', TextControl);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = TextControl;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.control.PasswordControl
|
||
* Class for handle the HTML native password input control.
|
||
* @extends PMUI.control.HTMLControl
|
||
*
|
||
* Quick usage example:
|
||
*
|
||
* @example
|
||
* myTextbox = new PMUI.control.PasswordControl({
|
||
* name: "my_name",
|
||
* value: "John Doe",
|
||
* maxLength: 12,
|
||
* disabled: false,
|
||
* onChange: function(currentValue, previousValue) {
|
||
* if(previousValue !== "") {
|
||
* alert("Your name is not \"" + previousValue + "\" anymore.\nNow it's \"" + currentValue + "\"");
|
||
* } else {
|
||
* alert("Now your name is " + currentValue);
|
||
* }
|
||
* }
|
||
* });
|
||
*
|
||
* document.body.appendChild(myTextbox.getHTML());
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the PasswordControl object.
|
||
* @param {Object} [settings=null] A JSON object with the config options.
|
||
*
|
||
* @cfg {Number} [maxLength=524288] A number which specifies the maximum character length the control can accept.
|
||
* @cfg {Function} [onKeyUp=null] A callback function to be called every time a pressed key is released on the
|
||
* control. For info about the callback parameters please read the
|
||
* {@link PMUI.control.PasswordControl#event-onKeyUp onKeyUp event} section.
|
||
*/
|
||
var PasswordControl = function (settings) {
|
||
PasswordControl.superclass.call(this, settings);
|
||
// /**
|
||
// * @property {String} [placeholder=""]
|
||
// * The control's placeholder (the text to be shown inside the control when there is not any text in it).
|
||
// * @readonly
|
||
// */
|
||
// this.placeholder = null;
|
||
/**
|
||
* @property {Number} [maxLength=524288] The maximum character length the control accepts.
|
||
* @readonly
|
||
*/
|
||
this.maxLength = null;
|
||
/**
|
||
* @event onKeyUp
|
||
* Fired when a pressed key is released.
|
||
* @param {Object} event The event object.
|
||
*/
|
||
this.onKeyUp = null;
|
||
PasswordControl.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.control.HTMLControl', PasswordControl);
|
||
|
||
PasswordControl.prototype.type = "PasswordControl";
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} [settings=null] A JSON object with the config options.
|
||
* @private
|
||
*/
|
||
PasswordControl.prototype.init = function (settings) {
|
||
var defaults = {
|
||
maxLength: 524288,
|
||
onKeyUp: null,
|
||
height: 30
|
||
};
|
||
|
||
$.extend(true, defaults, settings);
|
||
|
||
this.setMaxLength(defaults.maxLength)
|
||
.setOnKeyUpHandler(defaults.onKeyUp)
|
||
.setHeight(defaults.height);
|
||
};
|
||
/**
|
||
* Sets the callback function to be called when the keyup event occurs.
|
||
* @chainable
|
||
*/
|
||
PasswordControl.prototype.setOnKeyUpHandler = function (handler) {
|
||
if (typeof handler === 'function') {
|
||
this.onKeyUp = handler;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the maximun character number to be accepted in the control.
|
||
* @param {Number} maxLength The number must be an integer.
|
||
* If the value is minor or equal to 0 then the maxLength property is set to the default (524288).
|
||
* @chainable>
|
||
*/
|
||
PasswordControl.prototype.setMaxLength = function (maxLength) {
|
||
if (typeof maxLength === 'number' && maxLength % 1 === 0) {
|
||
this.maxLength = maxLength;
|
||
if (this.html) {
|
||
this.html.maxLength = maxLength > 0 ? maxLength : 524288;
|
||
}
|
||
} else {
|
||
throw new Error("method setMaxLength() only accepts integer values.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Set the events for the object.
|
||
* @chainable
|
||
*/
|
||
PasswordControl.prototype.defineEvents = function () {
|
||
var that = this;
|
||
|
||
PasswordControl.superclass.prototype.defineEvents.call(this);
|
||
this.addEvent('keyup').listen(this.html, function (e) {
|
||
if (typeof that.onKeyUp === 'function') {
|
||
that.onKeyUp(e);
|
||
}
|
||
});
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the HTML element for the object
|
||
* @return {HTMLElement}
|
||
*/
|
||
PasswordControl.prototype.createHTML = function () {
|
||
PasswordControl.superclass.prototype.createHTML.call(this);
|
||
this.html.type = "password";
|
||
this.setMaxLength(this.maxLength);
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.control.PasswordControl', PasswordControl);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = PasswordControl;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.control.DropDownListControl
|
||
* @extends PMUI.control.HTMLControl
|
||
* Class to handle the Select HTML form element.
|
||
*
|
||
* Example usage:
|
||
*
|
||
* @example
|
||
* var control;
|
||
* $(function() {
|
||
* var settings = {
|
||
* name: "myList",
|
||
* options: [
|
||
* {
|
||
* label: "one",
|
||
* value: 1
|
||
* },
|
||
* {
|
||
* label: "two",
|
||
* value: 2,
|
||
* disabled: true
|
||
* },
|
||
* {
|
||
* label: "three",
|
||
* value: 3,
|
||
* selected: true
|
||
* },
|
||
* {
|
||
* label: "Letters",
|
||
* options: [
|
||
* {
|
||
* value: "A"
|
||
* },
|
||
* {
|
||
* value: "B"
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* label: "months",
|
||
* disabled: true,
|
||
* options: [
|
||
* {
|
||
* value: "january"
|
||
* },
|
||
* {
|
||
* value: "february"
|
||
* }
|
||
* ]
|
||
* }
|
||
* ],
|
||
* value: 2
|
||
* };
|
||
* control = new PMUI.control.DropDownListControl(settings);
|
||
* document.body.appendChild(control.getHTML());
|
||
* });
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the DropDownListControl.
|
||
* @param {Object} [settings=null] An JSON object with the config options.
|
||
*/
|
||
/**
|
||
* @cfg {Array} [options=[]]
|
||
* An array with all the options to be contained by the control.
|
||
*
|
||
* Each element in the array is a JSON object, this JSON object can represent an option group
|
||
* or an option item.
|
||
*
|
||
* In case to represent an option item it can contain the next properties:
|
||
*
|
||
* - value {String} (required): the value for the option.
|
||
* - label {String} (optional): the label for the option, if isn't specified the value is used instead.
|
||
* - selected {Boolean} (optional): if the option is selected. #Note. If the configuration object has the
|
||
* "value" propery set then this "selected" property will be
|
||
* - disabled {Boolean} (optional): if the option is disabled or not.
|
||
*
|
||
* On the other hand, in case to represent an option group, it can contain the next properties:
|
||
*
|
||
* - label {String} (required): The name for the option group.
|
||
* - disabled {Boolean} (optional): If the group is disabled or not.
|
||
* - options {Array} (required): An array in which each element is a JSON object representing an option item,
|
||
* so every item must have the structure explained above (for represent option items). #Note. This propery makes
|
||
* the difference between an option and a option group. If the "options" property is not specified or if it isn't
|
||
* an array then it will treated like a option item.
|
||
* @cfg {String|Number} [value=null] The value of the option that is wanted to be selected. It must be one of the values
|
||
* of the list options, otherwise it will be set to "".
|
||
*/
|
||
var DropDownListControl = function (settings) {
|
||
DropDownListControl.superclass.call(this, settings);
|
||
/**
|
||
* @property {Array} [options] An array with all the options/option groups form the control.
|
||
* @private
|
||
*/
|
||
this.options = [];
|
||
/**
|
||
* @property {String} [elementTag='input'] The tag for the HTML element to be created.
|
||
* @private
|
||
*/
|
||
this.elementTag = 'select';
|
||
DropDownListControl.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.control.HTMLControl', DropDownListControl);
|
||
|
||
DropDownListControl.prototype.type = "DropDownListControl";
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Oject} [settings=null] A JSON opbject with the config options.
|
||
* @private
|
||
*/
|
||
DropDownListControl.prototype.init = function (settings) {
|
||
var defaults = {
|
||
options: [],
|
||
value: null,
|
||
height: 30
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setOptions(defaults.options);
|
||
this.setHeight(defaults.height);
|
||
|
||
if (defaults.value !== null) {
|
||
this.setValue(defaults.value);
|
||
}
|
||
};
|
||
/**
|
||
* Clear all the options from the control.
|
||
* @chainable
|
||
*/
|
||
DropDownListControl.prototype.clearOptions = function () {
|
||
this.options = [];
|
||
if (this.html) {
|
||
jQuery(this.html).empty();
|
||
}
|
||
this.value = "";
|
||
return this;
|
||
};
|
||
/**
|
||
* Enables or disables one or more options/option groups.
|
||
* @param {Boolean} disabled If the function will disable (use true) or enable (use false)
|
||
* the options/option groups.
|
||
* @param {String|Number|Object} option It can be a string, a number or a JSON object.
|
||
*
|
||
* - In case to be a String, it will be enabled/disabled the options that match the string in its value and the
|
||
* option groups that match the string in its label. In this case more than one single item can be
|
||
* enabled/disabled.
|
||
* - In case to be a Number, it will be enabled/disabled the option/option group which index position matches the
|
||
* number. Obviously, in this case only one item will be enabled/disabled.
|
||
* - In case to be an object you can specify if the change will be applied only to options or option groups,
|
||
* it should have two properties:
|
||
* - criteria {String}: The value (in case of options) or the label (in case of option groups) the items needs
|
||
* to match for apply the changes.
|
||
* - applyTo {String} (optional), it can take the following values:
|
||
* - "groups", the change will be applied only to the option groups.
|
||
* - "options", the change will be applied only to the options (direct child of the object).
|
||
* - [any other string value], the default value, it indicates that the change will be applied to both
|
||
* options/option groups that matches the criteria in its value/label respectly.
|
||
*
|
||
* @param {String} [group] It it is specified must be an String making reference to an existing option group label.
|
||
* Using this parameter, the elements to be match by the second parameter will be search only in the option groups
|
||
* that match this parameter in its label.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
DropDownListControl.prototype.enableDisableOption = function (disabled, option, group) {
|
||
var dataGroupTarget = this,
|
||
htmlGroupTarget = jQuery(this.html),
|
||
i,
|
||
j,
|
||
suboptions,
|
||
objectDefaults = {
|
||
applyTo: 'all'
|
||
};
|
||
disabled = !!disabled;
|
||
|
||
if (group) {
|
||
for (i = 0; i < this.options.length; i += 1) {
|
||
if (this.options[i].isGroup && this.options[i].label === group) {
|
||
dataGroupTarget = this.options[i];
|
||
break;
|
||
}
|
||
}
|
||
if (dataGroupTarget === this.options) {
|
||
throw new Error('disableOption(): the group "' + group + '" wasn\'t found.');
|
||
}
|
||
htmlGroupTarget = jQuery(this.html).find('>optgroup[label="' + group + '"]');
|
||
}
|
||
|
||
if (typeof option === 'number') {
|
||
dataGroupTarget.options[option].disabled = disabled;
|
||
htmlGroupTarget.find(">*").eq(option).attr("disabled", disabled);
|
||
} else if (typeof option === 'string') {
|
||
for (i = 0; i < dataGroupTarget.options.length; i += 1) {
|
||
if (!dataGroupTarget.options[i].isGroup && dataGroupTarget.options[i].value === option) {
|
||
dataGroupTarget.options[i].disabled = disabled;
|
||
} else if (dataGroupTarget.options[i].isGroup && dataGroupTarget.options[i].label === option) {
|
||
dataGroupTarget.options[i].disabled = disabled;
|
||
suboptions = dataGroupTarget.options[i].options;
|
||
for (j = 0; j < suboptions.length; j += 1) {
|
||
if (suboptions[j].value === option) {
|
||
suboptions[j].disabled = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
jQuery(htmlGroupTarget).find('option[value="' + option + '"]').add('optgroup[label="' + option + '"]')
|
||
.attr("disabled", disabled);
|
||
} else if (typeof option === 'object') {
|
||
jQuery.extend(true, objectDefaults, option);
|
||
if (objectDefaults.applyTo === 'groups') {
|
||
for (i = 0; i < dataGroupTarget.options.length; i += 1) {
|
||
if (dataGroupTarget.options[i].isGroup && dataGroupTarget.options[i].label === option.criteria) {
|
||
dataGroupTarget.options[i].disabled = disabled;
|
||
}
|
||
}
|
||
jQuery(htmlGroupTarget).find('optgroup[label="' + option.criteria + '"]').attr("disabled", disabled);
|
||
} else if (objectDefaults.applyTo === 'options') {
|
||
for (i = 0; i < dataGroupTarget.options.length; i += 1) {
|
||
if (!dataGroupTarget.options[i].isGroup && dataGroupTarget.options[i].value === option.criteria) {
|
||
dataGroupTarget.options[i].disabled = disabled;
|
||
}
|
||
}
|
||
jQuery(htmlGroupTarget).find('option[value="' + option.criteria + '"]')
|
||
.attr("disabled", disabled.criteria);
|
||
} else {
|
||
option = option.criteria;
|
||
for (i = 0; i < dataGroupTarget.options.length; i += 1) {
|
||
if (!dataGroupTarget.options[i].isGroup && dataGroupTarget.options[i].value === option) {
|
||
dataGroupTarget.options[i].disabled = disabled;
|
||
} else if (dataGroupTarget.options[i].isGroup && dataGroupTarget.options[i].label === option) {
|
||
dataGroupTarget.options[i].disabled = disabled;
|
||
suboptions = dataGroupTarget.options[i].options;
|
||
for (j = 0; j < suboptions.length; j += 1) {
|
||
if (suboptions[j].value === option) {
|
||
suboptions[j].disabled = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
jQuery(htmlGroupTarget).find('option[value="' + option + '"]').add('optgroup[label="' + option + '"]')
|
||
.attr("disabled", disabled);
|
||
}
|
||
} else {
|
||
throw new Error('disableOption(): the first parameter must be a Number or a String.');
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables one or more options/option groups.
|
||
* @param {String|Number|Object} option It can be a string, a number or a JSON object.
|
||
*
|
||
* - In case to be a String, it will be disabled the options that match the string in its value and the option
|
||
* groups which match the string in its label. In this case more than one single item can be disabled.
|
||
* - In case to be a Number, it will be disabled the option/option group which index position matches the number.
|
||
* Obviously, in this case only one item will be disabled.
|
||
* - In case to be an object you can specify if the change will be applied only to options or option groups,
|
||
* it should have two properties:
|
||
* - criteria {String}: The value (in case of options) or the label (in case of option groups) the items needs
|
||
* to match for apply the changes.
|
||
* - applyTo {String} (optional), it can take the following values:
|
||
* - "groups", the change will be applied only to the option groups.
|
||
* - "options", the change will be applied only to the options (direct child of the object).
|
||
* - [any other string value], the default value, it indicates that the change will be applied to both
|
||
* options/option groups that matches the criteria in its value/label respectly.
|
||
*
|
||
* @param {String} [group] It it is specified must be an String making reference to an existing option group label.
|
||
* Using this parameter, the elements to be match by the first parameter will be search only in the option groups
|
||
* that match this parameter in its label.
|
||
* @chainable
|
||
*/
|
||
DropDownListControl.prototype.disableOption = function (option, group) {
|
||
return this.enableDisableOption(true, option, group);
|
||
};
|
||
/**
|
||
* Enables one or more options/option groups.
|
||
* @param {String|Number|Object} option It can be a string, a number or a JSON object.
|
||
*
|
||
* - In case to be a String, it will be enabled the options that match the string in its value and the option
|
||
* groups which match the string in its label. In this case more than one single item can be enabled.
|
||
* - In case to be a Number, it will be enabled the option/option group which index position matches the number.
|
||
* Obviously, in this case only one item will be enabled.
|
||
* - In case to be an object you can specify if the change will be applied only to options or option groups,
|
||
* it should have two properties:
|
||
* - criteria {String}: The value (in case of options) or the label (in case of option groups) the items needs
|
||
* to match for apply the changes.
|
||
* - applyTo {String} (optional), it can take the following values:
|
||
* - "groups", the change will be applied only to the option groups.
|
||
* - "options", the change will be applied only to the options (direct child of the object).
|
||
* - [any other string value], the default value, it indicates that the change will be applied to both
|
||
* options/option groups that matches the criteria in its value/label respectly.
|
||
*
|
||
* @param {String} [group] It it is specified must be an String making reference to an existing option group label.
|
||
* Using this parameter, the elements to be match by the first parameter will be search only in the option groups
|
||
* that match this parameter in its label.
|
||
* @chainable
|
||
*/
|
||
DropDownListControl.prototype.enableOption = function (option, group) {
|
||
return this.enableDisableOption(false, option, group);
|
||
};
|
||
/**
|
||
* Removes one or more option/option groups.
|
||
* @param {String|Number|Object} option It can be a string, a number or a JSON object.
|
||
*
|
||
* - In case to be a String, it will be removed the options that match the string in its value and the option
|
||
* groups which match the string in its label. In this case more than one single item can be removed.
|
||
* - In case to be a Number, it will be removed the option/option group which index position matches the number.
|
||
* Obviously, in this case only one item will be removed.
|
||
* - In case to be an object you can specify if the change will be applied only to options or option groups,
|
||
* it should have two properties:
|
||
* - criteria {String}: The value (in case of options) or the label (in case of option groups) the items needs
|
||
* to match for apply the changes.
|
||
* - applyTo {String} (optional), it can take the following values:
|
||
* - "groups", the change will be applied only to the option groups.
|
||
* - "options", the change will be applied only to the options (direct child of the object).
|
||
* - [any other string value], the default value, it indicates that the change will be applied to both
|
||
* options/option groups that matches the criteria in its value/label respectly.
|
||
*
|
||
* @param {String} [group] It it is specified must be an String making reference to an existing option group label.
|
||
* Using this parameter, the elements to be match by the first parameter will be search only in the option groups
|
||
* that match this parameter in its label.
|
||
*
|
||
* ##Note. Removing an option group implies removing all its child options.
|
||
* @chainable
|
||
*/
|
||
DropDownListControl.prototype.removeOption = function (option, group) {
|
||
var dataGroupTarget = this, htmlGroupTarget = jQuery(this.html), i, j, suboptions,
|
||
objectDefaults = {
|
||
applyTo: 'all'
|
||
};
|
||
|
||
if (group) {
|
||
for (i = 0; i < this.options.length; i += 1) {
|
||
if (this.options[i].isGroup && this.options[i].label === group) {
|
||
dataGroupTarget = this.options[i];
|
||
break;
|
||
}
|
||
}
|
||
if (dataGroupTarget === this.options) {
|
||
throw new Error('disableOption(): the group "' + group + '" wasn\'t found.');
|
||
}
|
||
htmlGroupTarget = jQuery(this.html).find('>optgroup[label="' + group + '"]');
|
||
}
|
||
|
||
if (typeof option === 'number') {
|
||
dataGroupTarget.options.splice(option, 1);
|
||
htmlGroupTarget.find(">*").eq(option).remove();
|
||
} else if (typeof option === 'string') {
|
||
for (i = 0; i < dataGroupTarget.options.length; i += 1) {
|
||
if (!dataGroupTarget.options[i].isGroup && dataGroupTarget.options[i].value === option) {
|
||
dataGroupTarget.options.splice(i, 1);
|
||
i -= 1;
|
||
} else if (dataGroupTarget.options[i].isGroup && dataGroupTarget.options[i].label === option) {
|
||
suboptions = dataGroupTarget.options[i].options;
|
||
for (j = 0; j < suboptions.length; j += 1) {
|
||
if (suboptions[j].value === option) {
|
||
suboptions.splice(j, 1);
|
||
j -= 1;
|
||
}
|
||
}
|
||
dataGroupTarget.options.splice(i, 1);
|
||
i -= 1;
|
||
}
|
||
}
|
||
jQuery(htmlGroupTarget).find('option[value="' + option + '"]').add('optgroup[label="' + option + '"]')
|
||
.remove();
|
||
} else if (typeof option === 'object') {
|
||
jQuery.extend(true, objectDefaults, option);
|
||
if (objectDefaults.applyTo === 'groups') {
|
||
for (i = 0; i < dataGroupTarget.options.length; i += 1) {
|
||
if (dataGroupTarget.options[i].isGroup && dataGroupTarget.options[i].label === option.criteria) {
|
||
dataGroupTarget.options.splice(i, 1);
|
||
i -= 1;
|
||
}
|
||
}
|
||
jQuery(htmlGroupTarget).find('optgroup[label="' + option.criteria + '"]').remove();
|
||
} else if (objectDefaults.applyTo === 'options') {
|
||
for (i = 0; i < dataGroupTarget.options.length; i += 1) {
|
||
if (!dataGroupTarget.options[i].isGroup && dataGroupTarget.options[i].value === option.criteria) {
|
||
dataGroupTarget.options.splice(i, 1);
|
||
i -= 1;
|
||
}
|
||
}
|
||
jQuery(htmlGroupTarget).find('option[value="' + option.criteria + '"]').remove();
|
||
} else {
|
||
option = option.criteria;
|
||
for (i = 0; i < dataGroupTarget.options.length; i += 1) {
|
||
if ((!dataGroupTarget.options[i].isGroup && dataGroupTarget.options[i].value === option) ||
|
||
(dataGroupTarget.options[i].isGroup && dataGroupTarget.options[i].label === option)) {
|
||
dataGroupTarget.options.splice(i, 1);
|
||
i -= 1;
|
||
}
|
||
}
|
||
jQuery(htmlGroupTarget).find('option[value="' + option + '"]').add('optgroup[label="' + option + '"]')
|
||
.remove();
|
||
}
|
||
} else {
|
||
throw new Error('disableOption(): the first parameter must be a Number or a String.');
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a new option group to the control
|
||
* @param {Object} optionGroup A JSON object with the following properties:
|
||
*
|
||
* - label {String} (required): the label for the option group.
|
||
* - disabled {Boolean}(optional): if the option group will be disabled or not.
|
||
* it defaults to false.
|
||
* - options {Array} (optional): An array of JSON object, each one represents an option and
|
||
* should have the same structure than the "option" paremeter for the
|
||
* {@link PMUI.control.DropDownListControl#addOption addOption() method}.
|
||
* @chainable
|
||
*/
|
||
DropDownListControl.prototype.addOptionGroup = function (optionGroup) {
|
||
var newOptionGroup = {},
|
||
optionGroupHTML,
|
||
i;
|
||
|
||
if (!optionGroup.label) {
|
||
throw new Error("addOptionGroup(): a label for the new option group is required!");
|
||
}
|
||
|
||
newOptionGroup.label = optionGroup.label;
|
||
newOptionGroup.disabled = !!optionGroup.disabled;
|
||
newOptionGroup.isGroup = true;
|
||
newOptionGroup.options = [];
|
||
|
||
this.options.push(newOptionGroup);
|
||
|
||
if (this.html) {
|
||
optionGroupHTML = PMUI.createHTMLElement('optgroup');
|
||
optionGroupHTML.label = newOptionGroup.label;
|
||
optionGroupHTML.disabled = newOptionGroup.disabled;
|
||
this.html.appendChild(optionGroupHTML);
|
||
}
|
||
if (!jQuery.isArray(optionGroup.options)) {
|
||
optionGroup.options = [];
|
||
}
|
||
for (i = 0; i < optionGroup.options.length; i += 1) {
|
||
this.addOption(optionGroup.options[i], newOptionGroup.label);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a new option to the control or to an option group.
|
||
* @param {Object} option An object with ther settings for the new option.
|
||
* this object can have the following properties:
|
||
*
|
||
* - value {String} (required): the value for the option.
|
||
* - label {String} (optional): the label for the option, if isn't specified the value is used instead.
|
||
* - selected {Boolean} (optional): if the option is selected. #Note. If the configuration object has the
|
||
* "value" propery set then this "selected" property will be
|
||
* - disabled {Boolean} (optional): if the option is disabled or not.
|
||
*
|
||
* @param {String} group The name of the option group in which the new option will be added. If it doesn't exist
|
||
* it will be created.
|
||
*
|
||
* @chainable
|
||
*/
|
||
DropDownListControl.prototype.addOption = function (option, group) {
|
||
var newOption = {},
|
||
optionHTML,
|
||
i,
|
||
groupHTML,
|
||
flag = false;
|
||
|
||
newOption.value = option.value !== null && option.value !== undefined && option.value.toString ? option.value : (option.label || "");
|
||
newOption.value = newOption.value.toString();
|
||
newOption.label = option.label || newOption.value;
|
||
newOption.label = newOption.label.toString();
|
||
newOption.disabled = !!option.disabled;
|
||
newOption.isGroup = false;
|
||
|
||
if (!group) {
|
||
this.options.push(newOption);
|
||
} else {
|
||
for (i = 0; i < this.options.length; i += 1) {
|
||
if (this.options[i].isGroup && this.options[i].label === group) {
|
||
this.options[i].options.push(newOption);
|
||
flag = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!flag) {
|
||
this.addOptionGroup({
|
||
label: group
|
||
});
|
||
this.options[this.options.length - 1].options.push(newOption);
|
||
}
|
||
}
|
||
|
||
if (this.html) {
|
||
optionHTML = PMUI.createHTMLElement('option');
|
||
optionHTML.value = newOption.value;
|
||
optionHTML.selected = !!option.selected;
|
||
optionHTML.label = newOption.label;
|
||
optionHTML.disabled = newOption.disabled;
|
||
optionHTML.textContent = optionHTML.label;
|
||
|
||
if (group) {
|
||
groupHTML = jQuery(this.html).find('optgroup[label="' + group + '"]');
|
||
if (groupHTML.length) {
|
||
groupHTML.get(0).appendChild(optionHTML);
|
||
} else {
|
||
throw new Error("addOption(): the optiongroup \"" + group + "\" wasn't found");
|
||
}
|
||
} else {
|
||
jQuery(this.html).append(optionHTML);
|
||
}
|
||
}
|
||
|
||
if (option.selected) {
|
||
this.value = newOption.value;
|
||
}
|
||
if (this.getOptions().length == 1) {
|
||
this.value = newOption.value;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the label from the option currently selected.
|
||
* @return {String}
|
||
*/
|
||
DropDownListControl.prototype.getSelectedLabel = function () {
|
||
var i;
|
||
if (this.html) {
|
||
return jQuery(this.html).find('option:selected').attr('label');
|
||
}
|
||
for (i = 0; i < this.options.length; i += 1) {
|
||
if (this.options[i].value === this.value) {
|
||
return this.options[i].label;
|
||
}
|
||
}
|
||
|
||
return "";
|
||
};
|
||
/**
|
||
* Determines if a value exists in any of the list options.
|
||
* @param {String|Number} value The value to be searched
|
||
* @return {Boolean} It returns true if the value was found in any of the list options, otherwise it returns false.
|
||
*/
|
||
DropDownListControl.prototype.valueExistsInOptions = function (value) {
|
||
var i,
|
||
j,
|
||
options,
|
||
optionsLength,
|
||
subOptions,
|
||
subOptionsLength;
|
||
|
||
optionsLength = (options = this.options || []).length;
|
||
for (i = 0; i < optionsLength; i += 1) {
|
||
if (options[i].isGroup) {
|
||
subOptionsLength = (subOptions = options[i].options || []).length;
|
||
for (j = 0; j < subOptionsLength; j += 1) {
|
||
if (subOptions[j].value == value) {
|
||
return true;
|
||
}
|
||
}
|
||
} else if (options[i].value == value) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
/**
|
||
* Returns the first available option in the list.
|
||
* @return {Object|null} It returns a object literal with the label and value properties from the found option.
|
||
* @private
|
||
*/
|
||
DropDownListControl.prototype.getFirstAvailableOption = function () {
|
||
var i,
|
||
j,
|
||
options,
|
||
optionsLength,
|
||
subOptions,
|
||
subOptionsLength;
|
||
|
||
optionsLength = (options = this.options || []).length;
|
||
for (i = 0; i < optionsLength; i += 1) {
|
||
if (options[i].isGroup) {
|
||
return (options[i].options.length && options[i].options[0]) || null;
|
||
} else {
|
||
return options[i];
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
/**
|
||
* Sets the options/option groups for the control.
|
||
* @param {Array} options An array with the same structure that the
|
||
* {@link PMUI.control.DropDownListControl#cfg-options "options"} property in the
|
||
* Config options section.
|
||
* @chainable
|
||
*/
|
||
DropDownListControl.prototype.setOptions = function (options) {
|
||
var i,
|
||
valueExists,
|
||
firstOption;
|
||
if (jQuery.isArray(options)) {
|
||
this.clearOptions();
|
||
for (i = 0; i < options.length; i += 1) {
|
||
if (jQuery.isArray(options[i].options)) {
|
||
this.addOptionGroup(options[i]);
|
||
} else {
|
||
this.addOption(options[i]);
|
||
}
|
||
}
|
||
if (!this.valueExistsInOptions(this.value)) {
|
||
firstOption = this.getFirstAvailableOption();
|
||
this.value = (firstOption && firstOption.value) || "";
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the options/option groups from the field
|
||
* @param {Boolean} [includeGroups=false] If it's evaluated as true then it will include
|
||
* the option groups with its child elements, otherwise it will return only the option items.
|
||
* @return {Array}
|
||
*
|
||
* example
|
||
* list.getOptions(false);
|
||
* [La Paz][Cochabamba][Santa Cruz][Buenos Aires][Santa Fe][Cordoba][Santiago][.][.][Mexico D.F]
|
||
*
|
||
* list.getOptions(true)
|
||
* [BOLIVIA
|
||
* [La Paz][Cochabamba][SantaCruz]
|
||
* ]
|
||
* [ARGENTINA
|
||
* [Buenos Aires][Santa Fe][Cordoba]
|
||
* ]
|
||
* [CHILE
|
||
* [x][y][z]
|
||
* ]
|
||
* [New York]
|
||
* [Mexico D.F.]
|
||
*/
|
||
DropDownListControl.prototype.getOptions = function (includeGroups) {
|
||
var options = [],
|
||
i,
|
||
j;
|
||
if (includeGroups) {
|
||
return this.options.slice(0);
|
||
}
|
||
for (i = 0; i < this.options.length; i += 1) {
|
||
if (!this.options[i].isGroup) {
|
||
options.push(this.options[i]);
|
||
} else {
|
||
for (j = 0; j < this.options[i].options.length; j += 1) {
|
||
options.push(this.options[i].options[j]);
|
||
}
|
||
}
|
||
}
|
||
|
||
return options;
|
||
};
|
||
/**
|
||
* Defines the events for the control
|
||
* @chainable
|
||
*/
|
||
DropDownListControl.prototype.defineEvents = function () {
|
||
var that = this;
|
||
DropDownListControl.superclass.superclass.prototype.defineEvents.call(this);
|
||
if (this.html) {
|
||
this.addEvent('change').listen(this.html, function () {
|
||
that.onChangeHandler();
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the selected option in the dropdown.
|
||
* @param {String|Number} value The value of the option that is wanted to be selected. It must be one of the values
|
||
* of the list options, otherwise it will be set to "".
|
||
*/
|
||
DropDownListControl.prototype.setValue = function (value) {
|
||
var firstOption;
|
||
if (!this.valueExistsInOptions(value)) {
|
||
firstOption = this.getFirstAvailableOption();
|
||
value = (firstOption && firstOption.value) || "";
|
||
}
|
||
return DropDownListControl.superclass.prototype.setValue.call(this, value);
|
||
};
|
||
/**
|
||
* Creates the HTML element for the control.
|
||
* @return {HTMLElement}
|
||
*/
|
||
DropDownListControl.prototype.createHTML = function () {
|
||
var value;
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
value = this.value;
|
||
DropDownListControl.superclass.prototype.createHTML.call(this);
|
||
this.setOptions(this.options.slice(0))
|
||
.setValue(value);
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.control.DropDownListControl', DropDownListControl);
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.control.TextAreaControl
|
||
* Class to handle a HTML TextArea control.
|
||
* @extends PMUI.control.TextControl
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var myTextArea;
|
||
* $(function() {
|
||
* myTextArea = new PMUI.control.TextAreaControl({
|
||
* name: "some_text",
|
||
* value: "John Doe",
|
||
* maxLength: 12,
|
||
* readonly: false,
|
||
* width: 300,
|
||
* height: 200,
|
||
* placeholder: "insert some text",
|
||
* disabled: false,
|
||
* onChange: function(currentValue, previousValue) {
|
||
* if(previousValue !== "") {
|
||
* alert("the text is not \"" + previousValue + "\" anymore.\nNow it's \""
|
||
* + currentValue + "\"");
|
||
* } else {
|
||
* alert("Now your name is " + currentValue);
|
||
* }
|
||
* }
|
||
* });
|
||
*
|
||
* document.body.appendChild(myTextArea.getHTML());
|
||
*
|
||
* myTextArea.defineEvents();
|
||
* });
|
||
*
|
||
* @constructor
|
||
* Creates a new instance
|
||
* @param {Object} [settings] A JSON object that can contain the properties specified in the
|
||
* config options section.
|
||
*
|
||
* @cfg {Boolean} [readonly=false] If the control will be readonly.
|
||
*/
|
||
var TextAreaControl = function (settings) {
|
||
TextAreaControl.superclass.call(this, settings);
|
||
/**
|
||
* @property {Boolean} readonly A Boolean that specifies if the control is enabled for read only.
|
||
* @readonly
|
||
*/
|
||
this.readonly = null;
|
||
/**
|
||
* @property {String} [elementTag='input'] The tag for the HTML element to be created.
|
||
* @private
|
||
*/
|
||
this.elementTag = 'textarea';
|
||
TextAreaControl.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.control.TextControl', TextAreaControl);
|
||
|
||
TextAreaControl.prototype.type = "TextAreaControl";
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} [settings=null] A JSON object with the config options.
|
||
* @private
|
||
*/
|
||
TextAreaControl.prototype.init = function (settings) {
|
||
var defaults = {
|
||
readonly: false
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setReadOnly(defaults.readonly);
|
||
};
|
||
/**
|
||
* Creates the HTML element for the object
|
||
* @return {HTMLElement}
|
||
*/
|
||
TextAreaControl.prototype.createHTML = function () {
|
||
TextAreaControl.superclass.prototype.createHTML.call(this);
|
||
|
||
this.setReadOnly(this.readonly);
|
||
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Sets the maximun character number to be accepted in the control.
|
||
* @param {Number} maxLength The number must be an integer.
|
||
* If the value is minor or equal to 0 then the maxLength property is set to the default (524288).
|
||
* @chainable>
|
||
*/
|
||
TextAreaControl.prototype.setMaxLength = function (maxLength) {
|
||
var that = this;
|
||
|
||
if (typeof maxLength === 'number' && maxLength % 1 === 0) {
|
||
this.maxLength = maxLength;
|
||
if (this.html) {
|
||
this.html.maxLength = maxLength > 0 ? maxLength : 524288;
|
||
}
|
||
} else {
|
||
throw new Error("method setMaxLength() only accepts integer values.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
PMUI.extendNamespace('PMUI.control.TextAreaControl', TextAreaControl);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = TextAreaControl;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.control.SelectableControl
|
||
* A checkbox is a graphical component that can be in either an "on" (true) or "off" (false) state.
|
||
* Clicking on a check box changes its state from "on" to "off," or from "off" to "on."
|
||
* @extends PMUI.control.HTMLControl
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var a;
|
||
* $(function() {
|
||
* a = new PMUI.control.SelectableControl({
|
||
* name: "music",
|
||
* label: "Do you like music?",
|
||
* value: true,
|
||
* mode: 'checkbox', //it also can be "radio"
|
||
* onSelect: function() {
|
||
* console.log("checked");
|
||
* },
|
||
* onDeselect: function() {
|
||
* console.log("unchecked");
|
||
* }
|
||
* });
|
||
* document.body.appendChild(a.getHTML());
|
||
* a.defineEvents();
|
||
* });
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the SelectableControl class.
|
||
* @param {Object} [settings=null] A JSON object with the config options.
|
||
*
|
||
* @cfg {Boolean} [selected=false] If the control will be selected initially.
|
||
* @cfg {String} [label=""] The label for the control.
|
||
* @cfg {String} [value=""] The value for the control.
|
||
* @cfg {Function} [onSelect=null] The function to be call when the item will be selected. For info about the
|
||
* parameters please read the {@link PMUI.control.SelectableControl#event-onSelect onSelect event} documentation.
|
||
* @cfg {Function} [onDeselect=null] The function to be call when the item will be deselected
|
||
* (only supported when the mode is set to "checkbox"). For info about the callback parameters please read the
|
||
* {@link PMUI.control.SelectableControl#event-onDeselect onDeselect event} documentation.
|
||
* @cfg {String} [mode="checkbox"] The mode for the control, it can be: "checkbox" (default)
|
||
* for a checkbox control or "radio" for a readio button.
|
||
*/
|
||
var SelectableControl = function (settings) {
|
||
SelectableControl.superclass.call(this, settings);
|
||
/**
|
||
* If the control is selected or not.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.selected = null;
|
||
/**
|
||
* The control's label.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.label = null;
|
||
/**
|
||
* @event onSelect
|
||
* Fired when the control is selected.
|
||
*/
|
||
this.onSelect = null;
|
||
/**
|
||
* @event onDeselect
|
||
* Fired when the control is deselected.
|
||
*/
|
||
this.onDeselect = null;
|
||
/**
|
||
* The control's selection mode.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.mode = null;
|
||
/**
|
||
* The interactive control's HTML element.
|
||
* @type {HTMLElement}
|
||
* @private
|
||
*/
|
||
this.control = null;
|
||
/**
|
||
* The control's HTML element that will contain the label text.
|
||
* @type {[type]}
|
||
*/
|
||
this.textContainer = null;
|
||
SelectableControl.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.control.HTMLControl', SelectableControl);
|
||
/**
|
||
* The object's type.
|
||
* @type {String}
|
||
*/
|
||
SelectableControl.prototype.type = 'SelectableControl';
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} [settings=null] A JSON object with the config options.
|
||
* @private
|
||
*/
|
||
SelectableControl.prototype.init = function (settings) {
|
||
var defaults = {
|
||
selected: false,
|
||
mode: 'checkbox',
|
||
label: '',
|
||
value: "",
|
||
onSelect: null,
|
||
onDeselect: null
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
if (defaults.mode === 'checkbox' || defaults.mode === 'radio') {
|
||
this.mode = defaults.mode;
|
||
} else {
|
||
throw new Error('SelectableControl: it only accepts "checkbox" and "radio" as value for the "mode"'
|
||
+ ' property');
|
||
}
|
||
this.onSelect = defaults.onSelect;
|
||
this.onDeselect = defaults.onDeselect;
|
||
|
||
this.setLabel(defaults.label);
|
||
|
||
if (defaults.selected) {
|
||
this.select();
|
||
} else {
|
||
this.deselect();
|
||
}
|
||
};
|
||
/**
|
||
* Sets the control's name
|
||
* @param {String} name
|
||
* @chainable
|
||
*/
|
||
SelectableControl.prototype.setName = function (name) {
|
||
SelectableControl.superclass.prototype.setName.call(this, name);
|
||
if (this.control) {
|
||
this.control.name = name;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the value for the control
|
||
* @param {String|Boolean|Number} setValue This param value is evaluated as boolean.
|
||
* @chainable
|
||
*/
|
||
SelectableControl.prototype.setValue = function (value) {
|
||
SelectableControl.superclass.superclass.prototype.setValue.call(this, value);
|
||
if (this.control) {
|
||
this.control.value = value;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns a boolean that specifies if the checkbox/radio button is selected.
|
||
* @return {Boolean}
|
||
*/
|
||
SelectableControl.prototype.isSelected = function () {
|
||
if (this.html) {
|
||
this.selected = jQuery(this.control).is(':checked');
|
||
}
|
||
return this.selected;
|
||
};
|
||
/**
|
||
* Sets deselected the checkbox/radio button.
|
||
* @chainable
|
||
*/
|
||
SelectableControl.prototype.deselect = function () {
|
||
this.selected = false;
|
||
|
||
if (this.control) {
|
||
this.control.checked = false;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets selected the checkbox/radio button.
|
||
* @chainable
|
||
*/
|
||
SelectableControl.prototype.select = function () {
|
||
this.selected = true;
|
||
|
||
if (this.control) {
|
||
this.control.checked = true;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* A method which is called everytime the checked state from the control changes.
|
||
*
|
||
* This method is used internally by the object, so in most of the cases you won't need to invocated.
|
||
* To execute instructions when the control changes, please use the
|
||
{@link PMUI.control.Control#setOnChangeHandler setOnChangeHandler()} method.
|
||
*
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
SelectableControl.prototype.onChangeHandler = function () {
|
||
this.selected = $(this.control).is(":checked");
|
||
if (typeof this.onChange === 'function') {
|
||
this.onChange(this.value, this.value);
|
||
}
|
||
if (this.selected && typeof this.onSelect === 'function') {
|
||
this.onSelect();
|
||
} else if (!this.selected && typeof this.onDeselect === 'function') {
|
||
this.onDeselect();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the label for the control.
|
||
* @param {String} label
|
||
* @chainable
|
||
*/
|
||
SelectableControl.prototype.setLabel = function (label) {
|
||
if (typeof label !== 'string') {
|
||
throw new Error("setLabel(): it only accepts string type values.");
|
||
}
|
||
this.label = label;
|
||
if (this.html) {
|
||
this.textContainer.textContent = label;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables/enables the control
|
||
* @param {Boolean} disable If the value is evaluated as true then the control
|
||
is disabled, otherwise the control is enabled.
|
||
* @chainable
|
||
*/
|
||
SelectableControl.prototype.disable = function (disable) {
|
||
SelectableControl.superclass.superclass.prototype.disable.call(this, disable);
|
||
if (this.html) {
|
||
this.control.disabled = this.disabled;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritDoc
|
||
*/
|
||
SelectableControl.prototype.defineEvents = function () {
|
||
var that = this,
|
||
stopPropagation = function (e) {
|
||
e.stopPropagation();
|
||
};
|
||
this.removeEvents();
|
||
this.eventsDefined = true;
|
||
if (this.html) {
|
||
this.addEvent('change').listen(this.html, function () {
|
||
that.onChangeHandler();
|
||
});
|
||
this.addEvent('keydown').listen(this.html, function (e) {
|
||
if (e.which === PMUI.keyCodeF5) {
|
||
this.blur();
|
||
e.preventDefault();
|
||
window.location.reload(true);
|
||
}
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the HTML element for the control.
|
||
* @return {HTMLElement}
|
||
*/
|
||
SelectableControl.prototype.createHTML = function () {
|
||
var label,
|
||
textContainer,
|
||
control;
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
label = PMUI.createHTMLElement('label');
|
||
control = PMUI.createHTMLElement('input');
|
||
control.type = this.mode;
|
||
textContainer = PMUI.createHTMLElement('span');
|
||
textContainer.contentText = this.label;
|
||
|
||
label.appendChild(control);
|
||
label.appendChild(textContainer);
|
||
this.control = control;
|
||
this.textContainer = textContainer;
|
||
this.html = label;
|
||
|
||
this.html.id = this.id;
|
||
|
||
this.setName(this.name)
|
||
.setValue(this.value)
|
||
.disable(this.disabled)
|
||
.setLabel(this.label);
|
||
|
||
if (this.selected) {
|
||
this.select();
|
||
} else {
|
||
this.deselect();
|
||
}
|
||
|
||
this.applyStyle();
|
||
|
||
return this.html;
|
||
};
|
||
|
||
SelectableControl.prototype.setFocus = function () {
|
||
if (this.html) {
|
||
this.control.focus();
|
||
}
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.control.SelectableControl', SelectableControl);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = SelectableControl;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.control.HiddenControl
|
||
* The HTML input tag with the type attribute set to "hidden".
|
||
* @extends PMUI.control.HTMLControl
|
||
*
|
||
* Usage example:
|
||
*
|
||
* var hiddenControl = new PMUI.control.HiddenControl();
|
||
*
|
||
* document.body.appendChild(hiddenControl.getHTML());
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the HiddenControl class.
|
||
* @param {Object} [settings=null] A JSON object with the config options.
|
||
*/
|
||
var HiddenControl = function (settings) {
|
||
HiddenControl.superclass.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.control.HTMLControl', HiddenControl);
|
||
|
||
HiddenControl.prototype.type = "HiddenControl";
|
||
|
||
/**
|
||
* Creates the HTML element for the control.
|
||
* @return {HTMLElement}
|
||
*/
|
||
HiddenControl.prototype.createHTML = function () {
|
||
HiddenControl.superclass.prototype.createHTML.call(this);
|
||
this.html.type = 'hidden';
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.control.HiddenControl', HiddenControl);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = HiddenControl;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.control.DateTimeControl
|
||
* A control to handle dates and times.
|
||
* @extends {PMUI.control.HTMLControl}
|
||
*
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var dateTimePicker;
|
||
*
|
||
* $(function() {
|
||
* dateTimePicker = new PMUI.control.DateTimeControl({
|
||
* dateFormat: 'M dd yy',
|
||
* minDate: -90,
|
||
* maxDate: "+1y -1m -4d",
|
||
* firstDay: 1,
|
||
* months: {
|
||
* "january": {
|
||
* name: "Enero",
|
||
* shortname: "Ene"
|
||
* },
|
||
* "february": {
|
||
* name: "Febrero",
|
||
* shortname: "Feb"
|
||
* },
|
||
* "march": {
|
||
* name: "Marzo",
|
||
* shortname: "Mar"
|
||
* },
|
||
* "april": {
|
||
* name: "Abril",
|
||
* shortname: "Abr"
|
||
* },
|
||
* "may": "May",
|
||
* "june": "Junio",
|
||
* "july": "July",
|
||
* "august": "Agosto",
|
||
* "september": "Septiembre",
|
||
* "october": "Octubre",
|
||
* "november": "Noviembre",
|
||
* "december": "Diciembre"
|
||
* },
|
||
* days: {
|
||
* "sunday": {
|
||
* name: "Domingo",
|
||
* shortname: "Do"
|
||
* },
|
||
* "monday": {
|
||
* name: "Lunes",
|
||
* shortname: "Lu"
|
||
* },
|
||
* "tuesday": {
|
||
* name: "Martes",
|
||
* shortname: "Ma"
|
||
* },
|
||
* "wednesday": {
|
||
* name: "Miércoles",
|
||
* shortname: "Mi"
|
||
* },
|
||
* "thursday": {
|
||
* name: "Jueves",
|
||
* shortname: "Ju"
|
||
* },
|
||
* "friday": "Viernes",
|
||
* "saturday": "Sábado"
|
||
* }
|
||
* });
|
||
* document.body.appendChild(dateTimePicker.getHTML());
|
||
* dateTimePicker.defineEvents();
|
||
* });
|
||
*
|
||
* @cfg {Boolean} [datetime=false] If the control will have time supporting.
|
||
* @cfg {String} [dateFormat="yy-mm-dd HH:ii:ss"|"yy-mm-dd"] The format for the date to show in the text box.
|
||
* It defaults to:
|
||
*
|
||
* - "yy-mm-dd HH:ii:ss" if {@link PMUI.control.DateTimeControl#cfg-datetime datetime} is set to true.
|
||
* - "yy-mm-dd" if {@link PMUI.control.DateTimeControl#cfg-datetime datetime} is set to false.
|
||
*
|
||
* You can set a customized date format using the following wildcards:
|
||
*
|
||
* - d, day of month (no leading zero).
|
||
* - dd, day of month (two digit).
|
||
* - o, day of the year (no leading zeros).
|
||
* - oo, day of the year (three digit).
|
||
* - D, day name short.
|
||
* - DD, day name long.
|
||
* - m, month of year (no leading zero).
|
||
* - mm, month of year (two digit).
|
||
* - M, month name short.
|
||
* - MM, month name long.
|
||
* - y, year (two digit).
|
||
* - yy, year (four digit).
|
||
* - P, period (AM or PM).
|
||
* - H, hours (0-23).
|
||
* - HH, hours (00-23).
|
||
* - h, hours (1-12).
|
||
* - hh, hours (01-12).
|
||
* - i, minutes (0-59).
|
||
* - ii, minutes (00-59).
|
||
* - s, seconds (0-59).
|
||
* - ss, seconds (00-59).
|
||
* - @, Unix timestamp (ms since 01/01/1970).
|
||
* - !, Windows ticks (100ns since 01/01/0001).
|
||
* - '...', literal text.
|
||
* - '', single quote.
|
||
* - anything else, literal text.
|
||
*
|
||
* The wildcards can be used together in the same string.
|
||
*
|
||
* @cfg {Object} [months={"january": "January", "february": "February", "march": "March", "april": "April",
|
||
* "may": "May", "june": "June", "july": "July", "august": "August", "september": "September",
|
||
* "october": "October", "november": "November", "december": "December"}]
|
||
* A JSON object to set the names and shortnames for every month in year. Each property of this object can be:
|
||
*
|
||
* - A string, in this case the name for the month is set to this string, and the shortname is set using
|
||
* the first 3 characters of the string.
|
||
* - A JSON object, in this case the JSON may have two properties:
|
||
* - "name", will be used as the name for the month.
|
||
* - "shortname", will be used as the shortname for the month, if it is not specified the the shortname for
|
||
* the month will be set using the first 3 characters of the object's "name" property.
|
||
*
|
||
* @cfg {Object} [days={"sunday": "Sunday","monday": "Monday","tuesday": "Tuesday","wednesday": "Wednesday",
|
||
* "thursday": "Thursday","friday": "Friday","saturday": "Saturday"}]
|
||
* A JSON object to set the name and shortname for every day of week. Each property of this object can be:
|
||
*
|
||
* - A string, in this case the name for the day is set to this string, and the shortname is set using
|
||
* the first 3 characters of the string.
|
||
* - A JSON object, in this case the JSON may have two properties:
|
||
* - "name", will be used as the name for the day.
|
||
* - "shortname", will be used as the shortname for the day, if it is not specified the the shortname for
|
||
* the day will be set using the first 3 characters of the object's "name" property.
|
||
*
|
||
* @cfg {String|Number} [minDate=-365] A value which sets the minimum selectable date for the calendar. It can be:
|
||
*
|
||
* - a Date object.
|
||
* - a String with the following format: "([+-]\d+[dmyw]\s)?". It will represent an addition or substraction of
|
||
* time units to the current date, for example the expression "+1y -2m +3d" means
|
||
* "the current date plus 1 year, minus 2 months plus 3 days". The prefixes you can use are:
|
||
* - "d" for days.
|
||
* - "w" for weeks.
|
||
* - "m" for months.
|
||
* - "y" for years.
|
||
*
|
||
* You can also use one single unit, i.e. "+3y", "-1m", or a combination of two: "-2y +3d", etc.
|
||
* - a Number, in this case the number is taken as the number of days that will be sum/substracted from the
|
||
* current date. This number can be positive (for add days) or negative (for substract days).
|
||
* - an Object, in this case the object must have the following structure:
|
||
*
|
||
* {
|
||
* year: 2013,
|
||
* month: 5,
|
||
* day: 4,
|
||
* hours: 20,
|
||
* minutes: 15,
|
||
* seconds: 3,
|
||
* millisenconds
|
||
* }
|
||
*
|
||
* In this case only year and month are required.
|
||
*
|
||
* @cfg {String|Number} [maxDate=365] A value which sets the maximum selectable date for the calendar. It can take
|
||
* the same type of values that the {@link PMUI.contriol.DateTimeControl#cfg-minDate minDate config option}.
|
||
*
|
||
* - a Date object.
|
||
* - a String with the following format: "([+-]\d+[dmyw]\s)?". It will represent an addition or substraction of
|
||
* time units to the current date, for example the expression "+1y -2m +3d" means
|
||
* "the current date plus 1 year, minus 2 months plus 3 days". The prefixes you can use are:
|
||
* - "d" for days.
|
||
* - "w" for weeks.
|
||
* - "m" for months.
|
||
* - "y" for years.
|
||
*
|
||
* You can also use one single unit, i.e. "+3y", "-1m", or a combination of two: "-2y +3d", etc.
|
||
* - a Number, in this case the number is taken as the number of days that will be sum/substracted from the
|
||
* current date. This number can be positive (for add days) or negative (for substract days).
|
||
* - an Object, in this case the object must have the following structure:
|
||
*
|
||
* {
|
||
* year: 2013,
|
||
* month: 5,
|
||
* day: 4,
|
||
* hours: 20,
|
||
* minutes: 15,
|
||
* seconds: 3,
|
||
* millisenconds
|
||
* }
|
||
*
|
||
* In this case only year and month are required.
|
||
*
|
||
* @cfg {Number} [firstDay=0] Sets the first day of week. You can use numbers from 0 to 6, 0 means Sunday,
|
||
* 1 means Monday and so on.
|
||
*/
|
||
var DateTimeControl = function (settings) {
|
||
DateTimeControl.superclass.call(this, settings);
|
||
/**
|
||
* @property {Object} dom A JSON object that contains the control's DOM elements.
|
||
* @private
|
||
*/
|
||
this.dom = {};
|
||
/**
|
||
* @property {Boolean} datetime If the calendar has time supporting.
|
||
* @readonly
|
||
*/
|
||
this.datetime = null;
|
||
/**
|
||
* @property {String} dateFormat The format for the date to be shown on the control's textbox.
|
||
* @readonly
|
||
*/
|
||
this.dateFormat = null;
|
||
/**
|
||
* @property {Date} dateObject The control's date object.
|
||
* @private
|
||
*/
|
||
this.dateObject = null;
|
||
/**
|
||
* @property {Date} minDate The minimum selectable date.
|
||
* @private
|
||
*/
|
||
this.minDate = null;
|
||
/**
|
||
* @property {Date} maxDate The maximum selectable date.
|
||
* @private
|
||
*/
|
||
this.maxDate = null;
|
||
/**
|
||
* @property {Number} firstDay The first day of the week beginning with 0: Sunday and ending with 6: Saturday.
|
||
* @readonly
|
||
*/
|
||
this.firstDay = null;
|
||
DateTimeControl.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.control.HTMLControl', DateTimeControl);
|
||
|
||
DateTimeControl.prototype.type = "DateTimeControl";
|
||
|
||
/**
|
||
* An array with the name of each day of the week.
|
||
* @type {Array}
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.daysOrder = [
|
||
"sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"
|
||
];
|
||
/**
|
||
* An array with the name fo the months of year.
|
||
* @type {Array}
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.monthsOrder = [
|
||
"january", "february", "march", "april", "may", "june", "july", "august", "september", "october",
|
||
"november", "december"
|
||
];
|
||
/**
|
||
* An Object that contains the name, shortname and code for the days of the week.
|
||
* @type {Object}
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.days = {
|
||
"sunday": {
|
||
value: 0
|
||
},
|
||
"monday": {
|
||
value: 1
|
||
},
|
||
"tuesday": {
|
||
value: 2
|
||
},
|
||
"wednesday": {
|
||
value: 3
|
||
},
|
||
"thursday": {
|
||
value: 4
|
||
},
|
||
"friday": {
|
||
value: 5
|
||
},
|
||
"saturday": {
|
||
value: 6
|
||
}
|
||
};
|
||
/**
|
||
* An Object that contains the name, shortname and code for the months of year.
|
||
* @type {Object}
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.months = {
|
||
"january": {
|
||
value: 0
|
||
},
|
||
"february": {
|
||
value: 1
|
||
},
|
||
"march": {
|
||
value: 2
|
||
},
|
||
"april": {
|
||
value: 3
|
||
},
|
||
"may": {
|
||
value: 4
|
||
},
|
||
"june": {
|
||
value: 5
|
||
},
|
||
"july": {
|
||
value: 6
|
||
},
|
||
"august": {
|
||
value: 7
|
||
},
|
||
"september": {
|
||
value: 8
|
||
},
|
||
"october": {
|
||
value: 9
|
||
},
|
||
"november": {
|
||
value: 10
|
||
},
|
||
"december": {
|
||
value: 11
|
||
}
|
||
};
|
||
/**
|
||
* Initialize the object.
|
||
* @param {Object} settings An object with the config options.
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.init = function (settings) {
|
||
var defaults = {
|
||
datetime: false,
|
||
dateFormat: settings && settings.datetime ? 'yy-mm-dd HH:ii:ss' : 'yy-mm-dd',
|
||
months: {
|
||
"january": "January",
|
||
"february": "February",
|
||
"march": "March",
|
||
"april": "April",
|
||
"may": "May",
|
||
"june": "June",
|
||
"july": "July",
|
||
"august": "August",
|
||
"september": "September",
|
||
"october": "October",
|
||
"november": "November",
|
||
"december": "December"
|
||
},
|
||
days: {
|
||
"sunday": "Sunday",
|
||
"monday": "Monday",
|
||
"tuesday": "Tuesday",
|
||
"wednesday": "Wednesday",
|
||
"thursday": "Thursday",
|
||
"friday": "Friday",
|
||
"saturday": "Saturday"
|
||
},
|
||
minDate: -365,
|
||
maxDate: 365,
|
||
firstDay: 0,
|
||
height: 30
|
||
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setFirstDay(defaults.firstDay)
|
||
.setDateFormat(defaults.dateFormat)
|
||
.setMonths(defaults.months)
|
||
.setDays(defaults.days)
|
||
.setMinDate(defaults.minDate)
|
||
.setMaxDate(defaults.maxDate)
|
||
.visibleDateTime(defaults.datetime)
|
||
.setHeight(defaults.height);
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
DateTimeControl.prototype.setID = function (id) {
|
||
DateTimeControl.superclass.prototype.setID.call(this, id);
|
||
if (this.dom) {
|
||
this.dom.calendar.id = 'pmui-datepicker-calendar-' + this.id;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the day index of the first day of week.
|
||
* @return {Number} A number refering a day: 0 for Sunday, 1 for Monday and so on.
|
||
*/
|
||
DateTimeControl.prototype.getFirstDay = function () {
|
||
return this.firstDay;
|
||
};
|
||
/**
|
||
* Returns the control's minimum selectable date.
|
||
* @param {String} [format="UTC"] The format to applied to the returning date.
|
||
* @return {String} The minimum selectable date in string format.
|
||
*/
|
||
DateTimeControl.prototype.getMinDate = function (format) {
|
||
return this.formatDate(this.minDate, format || "UTC");
|
||
};
|
||
/**
|
||
* Returns the control's maximum selectable date.
|
||
* @param {String} [format="UTC"] The format to applied to the returning date.
|
||
* @return {String} The maximum selectable date in string format.
|
||
*/
|
||
DateTimeControl.prototype.getMaxDate = function (format) {
|
||
return this.formatDate(this.maxDate, format || "UTC");
|
||
};
|
||
/**
|
||
* Enables/disabled the calendar's time supporting.
|
||
* @param {Boolean} visible If it's true, then the time supporting is enabled, otherwise it's disabled.
|
||
* @chainable
|
||
*/
|
||
DateTimeControl.prototype.visibleDateTime = function (visible) {
|
||
visible = !!visible;
|
||
this.datetime = visible;
|
||
if (this.html) {
|
||
this.dom.footer.style.display = this.datetime ? 'block' : 'none';
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* @method setValue
|
||
* Sets the value for the Control.
|
||
* @param {Date|Number|String} value The date to set to the control, it can be:
|
||
*
|
||
* - A Date object, is used the date set in this object.
|
||
* - A Number, the number is used as the timestamp for the date (set in UTC).
|
||
* - A String, in this case the string must have one of the following formats:
|
||
*
|
||
* - "" (empty string), the value is set to empty.
|
||
* - "\d", the value is parsed to a number to be used as the timestamp for the date.
|
||
* - "\d{4}\-\d{2}\-\d{2}", this date is taken as "yyyy-mm-dd" and it's parsed.
|
||
* - "\d{4}\-\d{2}\-\d{2}T\d{2}\:\d{2}\:\d{2}[\\+\-]\d{2}\:\d{2}", the date is taken as
|
||
* "yyyy-mm-ddTHH:ii:ss+HH:ii" (the timezone offset is used).
|
||
*
|
||
* @param {Boolean} [utc=false] If the date will be set as a UTC date.
|
||
* (Only applicable if the first parameter is String and has the format "\d{4}\-\d{2}\-\d{2}").
|
||
* @chainable
|
||
*/
|
||
DateTimeControl.prototype.setValue = function (value, utc) {
|
||
var newDate, aux, aux2, y, m, d, h, i, s, hd, id, datetime = false, error = false;
|
||
if (value instanceof Date) {
|
||
newDate = value;
|
||
} else if (typeof value === 'number') {
|
||
newDate = new Date(value);
|
||
} else if (typeof value === 'string') {
|
||
if (value === "") {
|
||
this.dateObject = null;
|
||
} else if (/^\d+$/.test(value)) {
|
||
newDate = new Date(parseInt(value, 10));
|
||
} else if (/^\d{4}\-\d{2}\-\d{2}$/.test(value)
|
||
|| /^\d{4}\-\d{2}\-\d{2}T\d{2}\:\d{2}\:\d{2}[\\+\-]\d{2}\:\d{2}$/.test(value)) {
|
||
newDate = new Date();
|
||
aux = value.split(/T|\+|\-(?=\d{2}\:\d{2})/);
|
||
aux2 = aux[0].split("-");
|
||
y = parseInt(aux2[0], 10);
|
||
m = parseInt(aux2[1], 10);
|
||
d = parseInt(aux2[2], 10);
|
||
if (aux[1]) {
|
||
datetime = true;
|
||
aux2 = aux[1].split(":");
|
||
h = parseInt(aux2[0], 10);
|
||
i = parseInt(aux2[1], 10);
|
||
s = parseInt(aux2[2], 10);
|
||
aux2 = aux[2].split(":");
|
||
hd = (value[19] === '+' ? -1 : 1) * parseInt(aux2[0], 10);
|
||
id = (hd < 0 ? -1 : 1) * parseInt(aux2[1], 10);
|
||
} else {
|
||
h = i = s = hd = id = 0;
|
||
}
|
||
|
||
if (!this.isValidDateTime(y, m, d, h, i, s)) {
|
||
throw new Error("setValue(): invalid date time.");
|
||
}
|
||
|
||
newDate.setFullYear(y);
|
||
newDate.setMonth(m - 1);
|
||
newDate.setDate(d);
|
||
newDate.setHours(h);
|
||
newDate.setMinutes(i);
|
||
newDate.setSeconds(s);
|
||
newDate.setMilliseconds(0);
|
||
|
||
newDate.setHours(newDate.getHours() + hd);
|
||
newDate.setMinutes(newDate.getMinutes() + id);
|
||
|
||
if (!this.dateObject) {
|
||
this.dateObject = new Date();
|
||
}
|
||
|
||
if (datetime || utc) {
|
||
this.dateObject.setUTCFullYear(newDate.getFullYear());
|
||
this.dateObject.setUTCMonth(newDate.getMonth());
|
||
this.dateObject.setUTCDate(newDate.getDate());
|
||
this.dateObject.setUTCHours(newDate.getHours());
|
||
this.dateObject.setUTCMinutes(newDate.getMinutes());
|
||
this.dateObject.setUTCSeconds(newDate.getSeconds());
|
||
} else {
|
||
this.dateObject.setFullYear(y);
|
||
this.dateObject.setMonth(m - 1);
|
||
this.dateObject.setDate(d);
|
||
this.dateObject.setHours(h);
|
||
this.dateObject.setMinutes(i);
|
||
this.dateObject.setSeconds(s);
|
||
this.dateObject.setMilliseconds(0);
|
||
}
|
||
newDate = null;
|
||
} else {
|
||
error = true;
|
||
}
|
||
} else {
|
||
error = true;
|
||
}
|
||
|
||
if (error) {
|
||
throw new Error("setValue(): Invalid parameter format/data type.");
|
||
}
|
||
if (value !== "") {
|
||
if (!this.dateObject) {
|
||
this.dateObject = new Date();
|
||
}
|
||
if (newDate) {
|
||
this.dateObject.setFullYear(newDate.getFullYear());
|
||
this.dateObject.setMonth(newDate.getMonth());
|
||
this.dateObject.setDate(newDate.getDate());
|
||
this.dateObject.setHours(newDate.getHours());
|
||
this.dateObject.setMinutes(newDate.getMinutes());
|
||
this.dateObject.setSeconds(newDate.getSeconds());
|
||
}
|
||
}
|
||
|
||
if (this.html) {
|
||
if (this.dateObject) {
|
||
this.html.value = this.formatDate(this.dateObject, this.dateFormat);
|
||
this.dom.hoursInput.value = this.dateObject.getHours();
|
||
this.dom.minutesInput.value = this.dateObject.getMinutes();
|
||
this.dom.secondsInput.value = this.dateObject.getSeconds();
|
||
} else {
|
||
this.html.value = "";
|
||
}
|
||
this.fillYearSelector();
|
||
this.fillMonthSelector();
|
||
this.buildDaysTable();
|
||
}
|
||
this.value = this.getValue('UTC');
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the first day of week.
|
||
* @param {Number} day Use 0 for Sunday, 1 for Monday, 2 for Tuesday and so on!.
|
||
* @chainable
|
||
*/
|
||
DateTimeControl.prototype.setFirstDay = function (day) {
|
||
if (typeof day === 'number') {
|
||
if (day >= 0 && day < 7) {
|
||
this.firstDay = Math.floor(day);
|
||
if (this.html) {
|
||
this.setDays(this.days);
|
||
this.buildDaysTable();
|
||
}
|
||
return this;
|
||
}
|
||
}
|
||
|
||
throw new Error("setFirstDay(): The parameter must be a number between 0 and 6.");
|
||
};
|
||
/**
|
||
* Sets the format for the date to be displayed in the control's textbox.
|
||
* @param {String} dateFormat A string that contains wildcards that represent a date part (day, month, etc.).
|
||
* The valid wildcards are the same ones that are specified in the
|
||
* {@link PMUI.control.DateTimeControl#cfg-dateFormat dateFormat config option}.
|
||
* @chainable
|
||
*/
|
||
DateTimeControl.prototype.setDateFormat = function (dateFormat) {
|
||
if (typeof dateFormat === 'string') {
|
||
this.dateFormat = dateFormat;
|
||
this.updateValue();
|
||
} else {
|
||
throw new Error("setDateFormat(): The parameter must be a string.");
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the date format to be displayed in the control's textbox.
|
||
* @return {String}
|
||
*/
|
||
DateTimeControl.prototype.getDateFormat = function () {
|
||
return this.dateFormat;
|
||
};
|
||
/**
|
||
* Returns the date using the format set by {@link PMUI.control.DateTimeControl#setDateFormat setDateFormat()}
|
||
* method.
|
||
* @return {String}
|
||
*/
|
||
DateTimeControl.prototype.getFormatedDate = function () {
|
||
return this.html.value;
|
||
};
|
||
/**
|
||
* Returns the selected date.
|
||
* @param {String} format Specifies the date format that will be used for the returning date.
|
||
* The valid values are:
|
||
*
|
||
* - "UTC", returns a date in the format: yyyy-mm-ddTHH:ii:ss-HH:mm (i.e. 2013-08-31T00:08:00+04:00).
|
||
* - "@" or "timestamp", returns a date in timestamp format.
|
||
* - [any other valid format string], will return the date using the string as the dateformat. This string can
|
||
* contain any of the wilcards specified in the
|
||
* {@link PMUI.control.DateTimeControl#cfg-dateFormat dateFormat config option}.
|
||
* @return {String}
|
||
*/
|
||
DateTimeControl.prototype.getValue = function (returningFormat) {
|
||
var res;
|
||
returningFormat = returningFormat || "UTC";
|
||
if (this.dateObject) {
|
||
switch (returningFormat) {
|
||
case 'timestamp':
|
||
case '@':
|
||
res = this.formatDate(this.dateObject, '@');
|
||
break;
|
||
default:
|
||
res = this.formatDate(this.dateObject, returningFormat);
|
||
}
|
||
} else {
|
||
res = "";
|
||
}
|
||
|
||
return res;
|
||
};
|
||
/**
|
||
* Returns true if the parameter is a leap year, otherwise returns false.
|
||
* @param {Number} year The year to be evaluated.
|
||
* @return {Boolean}
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.isLeapYear = function (year) {
|
||
if (year % 400 === 0) {
|
||
return true;
|
||
}
|
||
if (year % 100 === 0) {
|
||
return false;
|
||
}
|
||
if (year % 4 === 0) {
|
||
return true;
|
||
}
|
||
return false;
|
||
};
|
||
/**
|
||
* Returns true if the bunch of arguments represents a valid date otherwise it returns false.
|
||
* @param {Number} year
|
||
* @param {Number} month The month number (a number from 1 to 12)
|
||
* @param {Number} day
|
||
* @param {Number} [hours]
|
||
* @param {Number} [minutes]
|
||
* @param {Number} [seconds]
|
||
* @param {Number} [milliseconds]
|
||
* @return {Boolean}
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.isValidDateTime = function (year, month, day, hours, minutes, seconds, milliseconds) {
|
||
if (!(typeof year === 'number' && typeof month === 'number' && typeof day === 'number')) {
|
||
return false;
|
||
}
|
||
|
||
hours = hours || 0;
|
||
minutes = minutes || 0;
|
||
seconds = seconds || 0;
|
||
milliseconds = milliseconds || 0;
|
||
|
||
if (!(typeof hours === 'number' && typeof minutes === 'number' && typeof seconds === 'number'
|
||
&& typeof milliseconds === 'number')) {
|
||
return false;
|
||
}
|
||
|
||
if (!(hours >= 0 && hours <= 23)) {
|
||
return false;
|
||
}
|
||
|
||
if (!(minutes >= 0 && minutes <= 59)) {
|
||
return false;
|
||
}
|
||
|
||
if (!(seconds >= 0 && seconds <= 59)) {
|
||
return false;
|
||
}
|
||
|
||
if (!(milliseconds >= 0 && milliseconds <= 999)) {
|
||
return false;
|
||
}
|
||
|
||
if (day < 1 || day > 31 || month < 1 || month > 12) {
|
||
return false;
|
||
}
|
||
|
||
switch (month) {
|
||
case 4:
|
||
case 6:
|
||
case 9:
|
||
case 11:
|
||
if (day > 30) {
|
||
return false;
|
||
}
|
||
break;
|
||
case 2:
|
||
if (this.isLeapYear(year)) {
|
||
return day <= 29;
|
||
}
|
||
return day <= 28;
|
||
}
|
||
|
||
return true;
|
||
};
|
||
/**
|
||
* It parses the argument into a date.
|
||
* @param {String|Date} date It can be a String or a Date:
|
||
*
|
||
* - Date, in this case the argument isn't parse and it is returned.
|
||
* - String, in this case the string must have the following format: "[-+]\d+[dwmy]". For example "+1y -4m +3d"
|
||
* means that te returning date will be 1 year minus 4 months plus 3 days from today.
|
||
* @return {Date}
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.parseDate = function (date) {
|
||
var startDate,
|
||
aux,
|
||
i,
|
||
amount;
|
||
|
||
if (typeof date === 'number') {
|
||
startDate = new Date();
|
||
startDate.setDate(startDate.getDate() + date);
|
||
} else if (typeof date === 'string') {
|
||
startDate = new Date();
|
||
date = " " + jQuery.trim(date);
|
||
if (/^(\s[\\+|\-]\d+[y|m|d|w])+$/.test(date)) {
|
||
date = date.match(/[\\+|\-]\d+[y|m|d]/g);
|
||
for (i = 0; i < date.length; i += 1) {
|
||
aux = date[i].match(/[\-|\\+]|\d+|[m|d|y]/g);
|
||
amount = parseInt(aux[1], 10);
|
||
if (aux[0] === '-') {
|
||
amount *= -1;
|
||
}
|
||
switch (aux[2]) {
|
||
case 'd':
|
||
startDate.setDate(startDate.getDate() + amount);
|
||
break;
|
||
case 'm':
|
||
startDate.setMonth(startDate.getMonth() + amount);
|
||
break;
|
||
case 'y':
|
||
startDate.setFullYear(startDate.getFullYear() + amount);
|
||
break;
|
||
case 'w':
|
||
startDate.setDate(startDate.getDate() + (amount * 7));
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
} else if (date instanceof Date) {
|
||
startDate = date;
|
||
} else if (typeof date === 'object') {
|
||
startDate = new Date(date.year, date.month - 1, date.day || 1, date.hours || 0, date.minutes || 0, date.seconds || 0,
|
||
date.milliseconds || 0);
|
||
} else {
|
||
throw new Error("parseDate(): invalid parameter.");
|
||
}
|
||
|
||
return startDate;
|
||
};
|
||
/**
|
||
* Sets the minimum date the control can accept as a selectable one.
|
||
* @param {String|Date|Number|Object} date It can be:
|
||
*
|
||
* - a Date object.
|
||
* - a String with the following format: "([+-]\d+[dmyw]\s)?". It will represent an addition or substraction of
|
||
* time units to the current date, for example the expression "+1y -2m +3d" means
|
||
* "the current date plus 1 year, minus 2 months plus 3 days". The prefixes you can use are:
|
||
* - "d" for days.
|
||
* - "w" for weeks.
|
||
* - "m" for months.
|
||
* - "y" for years.
|
||
*
|
||
* You can also use one single unit, i.e. "+3y", "-1m", or a combination of two: "-2y +3d", etc.
|
||
* - a Number, in this case the number is taken as the number of days that will be sum/substracted from the
|
||
* current date. This number can be positive (for add days) or negative (for substract days).
|
||
* - an Object, in this case the object must have the following structure:
|
||
*
|
||
* {
|
||
* year: 2013,
|
||
* month: 5,
|
||
* day: 4,
|
||
* hours: 20,
|
||
* minutes: 15,
|
||
* seconds: 3,
|
||
* millisenconds
|
||
* }
|
||
*
|
||
* In this case only year and month are required.
|
||
*
|
||
* @chainable
|
||
*/
|
||
DateTimeControl.prototype.setMinDate = function (date) {
|
||
var minDate = this.parseDate(date), d;
|
||
|
||
if (this.maxDate) {
|
||
if (minDate > this.maxDate) {
|
||
throw new Error("setMinDate(): The min date can't be major than the max date");
|
||
}
|
||
}
|
||
this.minDate = minDate;
|
||
this.fillYearSelector();
|
||
this.fillMonthSelector();
|
||
this.buildDaysTable();
|
||
|
||
if (this.html) {
|
||
d = new Date();
|
||
this.dom.todayButton.disabled = !(d >= minDate && (this.maxDate && d <= this.maxDate));
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the maximum date the control can accept as a selectable one.
|
||
* @param {String|Date|Number|Object} date It can be:
|
||
*
|
||
* - a Date object.
|
||
* - a String with the following format: "([+-]\d+[dmyw]\s)?". It will represent an addition or substraction of
|
||
* time units to the current date, for example the expression "+1y -2m +3d" means
|
||
* "the current date plus 1 year, minus 2 months plus 3 days". The prefixes you can use are:
|
||
* - "d" for days.
|
||
* - "w" for weeks.
|
||
* - "m" for months.
|
||
* - "y" for years.
|
||
*
|
||
* You can also use one single unit, i.e. "+3y", "-1m", or a combination of two: "-2y +3d", etc.
|
||
* - a Number, in this case the number is taken as the number of days that will be sum/substracted from the
|
||
* current date. This number can be positive (for add days) or negative (for substract days).
|
||
* - an Object, in this case the object must have the following structure:
|
||
*
|
||
* {
|
||
* year: 2013,
|
||
* month: 5,
|
||
* day: 4,
|
||
* hours: 20,
|
||
* minutes: 15,
|
||
* seconds: 3,
|
||
* millisenconds
|
||
* }
|
||
*
|
||
* In this case only year and month are required.
|
||
* @chainable
|
||
*/
|
||
DateTimeControl.prototype.setMaxDate = function (date) {
|
||
var maxDate = this.parseDate(date), d;
|
||
|
||
if (this.minDate) {
|
||
if (maxDate < this.minDate) {
|
||
throw new Error("setMaxDate(): The max date can't be minor than the min date");
|
||
}
|
||
}
|
||
this.maxDate = maxDate;
|
||
this.fillYearSelector();
|
||
this.fillMonthSelector();
|
||
this.buildDaysTable();
|
||
|
||
if (this.html) {
|
||
d = new Date();
|
||
this.dom.todayButton.disabled = !(d <= maxDate && (this.minDate && d >= this.minDate));
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the months names/shortnames to be used by the calendar.
|
||
* @param {Object} months An object with the same structure that the
|
||
* {@link PMUI.control.DateTimeControl#cfg-months months config option}.
|
||
* @chainable
|
||
*/
|
||
DateTimeControl.prototype.setMonths = function (months) {
|
||
var key,
|
||
changed;
|
||
|
||
for (key in this.months) {
|
||
if (this.months.hasOwnProperty(key)) {
|
||
if (months.hasOwnProperty(key)) {
|
||
if (typeof months[key] === 'string') {
|
||
changed = true;
|
||
this.months[key].name = months[key];
|
||
this.months[key].shortname = months[key].charAt(0).toUpperCase() + months[key].slice(1, 3);
|
||
} else if (typeof months[key] === 'object') {
|
||
this.months[key].name = months[key].name;
|
||
this.months[key].shortname = months[key].shortname;
|
||
changed = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (changed) {
|
||
this.fillMonthSelector();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Fills the months selector.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.fillMonthSelector = function () {
|
||
var currentMonth,
|
||
option,
|
||
year,
|
||
i,
|
||
j;
|
||
|
||
if (this.dom.monthSelector) {
|
||
year = this.dom.yearSelector.value;
|
||
currentMonth = (this.dateObject && this.dateObject.getMonth()) || this.dom.monthSelector.value
|
||
|| (new Date()).getMonth().toString();
|
||
jQuery(this.dom.monthSelector).empty();
|
||
i = 0;
|
||
j = this.monthsOrder.length - 1;
|
||
if (year === this.minDate.getFullYear().toString()) {
|
||
i = this.minDate.getMonth();
|
||
}
|
||
if (year === this.maxDate.getFullYear().toString()) {
|
||
j = this.maxDate.getMonth();
|
||
}
|
||
for (i; i <= j; i += 1) {
|
||
option = PMUI.createHTMLElement('option');
|
||
option.label = this.months[this.monthsOrder[i]].name;
|
||
option.textContent = option.label;
|
||
option.value = this.months[this.monthsOrder[i]].value;
|
||
option.selected = currentMonth.toString() === option.value;
|
||
this.dom.monthSelector.appendChild(option);
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the name/shortnames for the days to be used in the calendar.
|
||
* @param {Object} days A JSON object with the same structure than the
|
||
* {@PMUI.control.DateTimeControl#cfg-days days config option}.
|
||
* @chainable
|
||
*/
|
||
DateTimeControl.prototype.setDays = function (days) {
|
||
var key,
|
||
changed,
|
||
i,
|
||
cell,
|
||
daysLength = this.daysOrder.length,
|
||
aux;
|
||
|
||
for (key in this.days) {
|
||
if (this.days.hasOwnProperty(key)) {
|
||
if (days.hasOwnProperty(key)) {
|
||
if (typeof days[key] === 'string') {
|
||
this.days[key].name = days[key];
|
||
this.days[key].shortname = days[key].substr(0, 3);
|
||
} else if (typeof days[key] === 'object') {
|
||
this.days[key].name = days[key].name || this.days[key].name || "";
|
||
this.days[key].shortname = (days[key].shortname && days[key].shortname.substr(0, 3))
|
||
|| (this.days[key].name && this.days[key].name.substr(0, 3)) || "";
|
||
} else {
|
||
throw new Error("setDays(): The argument supplied must be a string or an object.");
|
||
}
|
||
changed = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (changed && this.html) {
|
||
jQuery(this.dom.daysHeader).empty();
|
||
aux = 0;
|
||
i = this.firstDay;
|
||
while (aux < daysLength) {
|
||
if (i === daysLength) {
|
||
i = 0;
|
||
}
|
||
cell = PMUI.createHTMLElement('th');
|
||
cell.textContent = this.days[this.daysOrder[i]].shortname;
|
||
cell.setAttribute("data-value", this.days[this.daysOrder[i]].value);
|
||
this.dom.daysHeader.appendChild(cell);
|
||
i += 1;
|
||
aux += 1;
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Fill the year selector.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.fillYearSelector = function () {
|
||
var minYear,
|
||
maxYear,
|
||
option,
|
||
selectedYear;
|
||
|
||
if (this.dom.yearSelector) {
|
||
selectedYear = (this.dateObject && this.dateObject.getFullYear()) || this.dom.yearSelector.value
|
||
|| (new Date()).getFullYear();
|
||
selectedYear = selectedYear.toString();
|
||
jQuery(this.dom.yearSelector).empty();
|
||
minYear = this.minDate.getFullYear();
|
||
maxYear = this.maxDate.getFullYear();
|
||
for (minYear; minYear <= maxYear; minYear += 1) {
|
||
option = PMUI.createHTMLElement('option');
|
||
option.textContent = option.label = option.value = minYear;
|
||
if (option.value.toString() === selectedYear) {
|
||
option.selected = true;
|
||
}
|
||
this.dom.yearSelector.appendChild(option);
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the number of days in a month
|
||
* @param {Number} y The year (it's necessary to determine the days in February.)
|
||
* @param {Number} m The month
|
||
* @return {Number} The number of days.
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.daysInMonth = function (y, m) {
|
||
if (m < 1 || m > 12) {
|
||
return 0;
|
||
}
|
||
switch (m) {
|
||
case 4:
|
||
case 6:
|
||
case 9:
|
||
case 11:
|
||
return 30;
|
||
case 2:
|
||
if (this.isLeapYear(y)) {
|
||
return 29;
|
||
}
|
||
return 28;
|
||
default:
|
||
return 31;
|
||
}
|
||
};
|
||
/**
|
||
* Returns the day of week for a date.
|
||
* @param {Number} y The year.
|
||
* @param {Number} m The month.
|
||
* @param {Number} d The day of month.
|
||
* @return {Number} A number from 0 to 6. 0 means Sunday, 1, Monday and so on.
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.whichDay = function (y, m, d) {
|
||
var centuryCode,
|
||
monthCode,
|
||
lastTwoYearDigits = y % 100,
|
||
gregorianCenturyCodes = [6, 4, 2, 0],
|
||
i;
|
||
|
||
if (!this.isValidDateTime(y, m, d)) {
|
||
throw new Error("whichDay(): invalid date.");
|
||
}
|
||
|
||
switch (m) {
|
||
case 3:
|
||
case 11:
|
||
monthCode = 3;
|
||
break;
|
||
case 4:
|
||
case 7:
|
||
monthCode = 6;
|
||
break;
|
||
case 5:
|
||
monthCode = 1;
|
||
break;
|
||
case 6:
|
||
monthCode = 4;
|
||
break;
|
||
case 8:
|
||
monthCode = 2;
|
||
break;
|
||
case 9:
|
||
case 12:
|
||
monthCode = 5;
|
||
break;
|
||
case 10:
|
||
monthCode = 0;
|
||
break;
|
||
case 1:
|
||
if (this.isLeapYear(y)) {
|
||
monthCode = -1;
|
||
} else {
|
||
monthCode = 0;
|
||
}
|
||
break;
|
||
case 2:
|
||
if (this.isLeapYear(y)) {
|
||
monthCode = 2;
|
||
} else {
|
||
monthCode = 3;
|
||
}
|
||
break;
|
||
}
|
||
|
||
centuryCode = Math.floor(y / 100);
|
||
|
||
i = 0;
|
||
while (centuryCode % 4 !== 0) {
|
||
centuryCode += 1;
|
||
i += 1;
|
||
}
|
||
if (i === 0) {
|
||
centuryCode = gregorianCenturyCodes[0];
|
||
} else {
|
||
centuryCode = gregorianCenturyCodes[gregorianCenturyCodes.length - i];
|
||
}
|
||
|
||
return (d + monthCode + lastTwoYearDigits + Math.floor(lastTwoYearDigits / 4) + centuryCode ) % 7;
|
||
};
|
||
/**
|
||
* Build the days table for the calendar
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.buildDaysTable = function () {
|
||
var dayOfTheWeek,
|
||
daysInMonth,
|
||
y,
|
||
m,
|
||
i,
|
||
day = 1,
|
||
row,
|
||
cell,
|
||
limit,
|
||
link,
|
||
selectableDate;
|
||
|
||
if (this.dom.yearSelector && this.dom.monthSelector) {
|
||
jQuery(this.dom.tableBody).empty();
|
||
y = parseInt(this.dom.yearSelector.value, 10);
|
||
m = parseInt(this.dom.monthSelector.value, 10) + 1;
|
||
dayOfTheWeek = this.whichDay(y, m, 1) - this.firstDay;
|
||
if (dayOfTheWeek < 0) {
|
||
dayOfTheWeek = 7 + dayOfTheWeek;
|
||
}
|
||
daysInMonth = this.daysInMonth(y, m);
|
||
limit = Math.ceil((dayOfTheWeek + daysInMonth) / 7) * 7;
|
||
row = PMUI.createHTMLElement('tr');
|
||
|
||
for (i = 0; i < limit; i += 1) {
|
||
cell = PMUI.createHTMLElement("td");
|
||
if (i - dayOfTheWeek >= 0 && day <= daysInMonth) {
|
||
selectableDate = true;
|
||
if ((m - 1) === this.maxDate.getMonth() && y === this.maxDate.getFullYear()) {
|
||
if (day > this.maxDate.getDate()) {
|
||
selectableDate = false;
|
||
}
|
||
} else if ((m - 1) === this.minDate.getMonth() && y === this.minDate.getFullYear()) {
|
||
if (day < this.minDate.getDate()) {
|
||
selectableDate = false;
|
||
}
|
||
}
|
||
if (selectableDate) {
|
||
link = PMUI.createHTMLElement("a");
|
||
link.href = "#";
|
||
link.setAttribute("data-date", day);
|
||
link.textContent = day;
|
||
link.className = (this.dateObject && this.dateObject.getFullYear() === y
|
||
&& this.dateObject.getMonth() + 1 === m && this.dateObject.getDate() === day) ? 'selected' : '';
|
||
cell.appendChild(link);
|
||
} else {
|
||
cell.className = 'pmui-datepicker-disabled-date';
|
||
cell.textContent = day;
|
||
}
|
||
day += 1;
|
||
}
|
||
row.appendChild(cell);
|
||
if ((i + 1) % 7 === 0) {
|
||
this.dom.tableBody.appendChild(row);
|
||
row = PMUI.createHTMLElement('tr');
|
||
}
|
||
}
|
||
this.dom.tableBody.appendChild(row);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows the control's calendar.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.showCalendar = function () {
|
||
var position,
|
||
inputHeight,
|
||
maxZIndex;
|
||
|
||
if (this.html) {
|
||
this.fillYearSelector();
|
||
this.fillMonthSelector();
|
||
this.buildDaysTable();
|
||
|
||
position = jQuery(this.html).offset();
|
||
inputHeight = jQuery(this.html).outerHeight();
|
||
|
||
jQuery(document.body).find(">*").each(function () {
|
||
var n;
|
||
|
||
n = parseInt(jQuery(this).css("z-index"));
|
||
if (!isNaN(n)) {
|
||
maxZIndex = n > maxZIndex ? n : maxZIndex;
|
||
}
|
||
});
|
||
|
||
document.body.appendChild(this.dom.calendar);
|
||
this.dom.calendar.style.zIndex = maxZIndex ? maxZIndex + 1 : 999;
|
||
this.dom.calendar.style.left = position.left + 'px';
|
||
this.dom.calendar.style.top = (position.top + inputHeight) + 'px';
|
||
this.dom.calendar.style.display = "";
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Hide's the control's calendar.
|
||
* @return {HTMLElement} The object's html.
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.hideCalendar = function () {
|
||
if (this.html) {
|
||
jQuery(this.dom.calendar).detach();
|
||
}
|
||
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Returns the day number of a date in a whole year.
|
||
* @param {Number} y The year.
|
||
* @param {Number} m The month.
|
||
* @param {Number} d The day of month.
|
||
* @return {Number} The day of year.
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.getDayOfYear = function (y, m, d) {
|
||
var day = 0,
|
||
month = 1;
|
||
|
||
if (!(typeof y === 'number' && typeof m === 'number' && typeof d === 'number')) {
|
||
throw new Error("getDayOfYear(): invalid parameters.");
|
||
}
|
||
if (!this.isValidDateTime(y, m, d)) {
|
||
throw new Error("getDayOfYear(): invalid date.");
|
||
}
|
||
|
||
while (month < m) {
|
||
day += this.daysInMonth(y, m);
|
||
month += 1;
|
||
}
|
||
|
||
day += d;
|
||
|
||
return day;
|
||
};
|
||
/**
|
||
* Formats a date using the specified format string.
|
||
* @param {Date} dateObject a Date object.
|
||
* @param {String} format String that contains wildcards specified in the
|
||
* {@link PMUI.control.DateTimeControl#cfg-dateFormat dateFormat config option}.
|
||
* @return {String} The formatted date as a string.
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.formatDate = function (dateObject, format) {
|
||
var finalValue,
|
||
d = dateObject.getDate(),
|
||
o = this.getDayOfYear(dateObject.getFullYear(), dateObject.getMonth() + 1, dateObject.getDate()),
|
||
m = dateObject.getMonth() + 1,
|
||
h = dateObject.getHours(),
|
||
h12 = h > 12 ? h - 12 : h,
|
||
i = dateObject.getMinutes(),
|
||
s = dateObject.getSeconds(),
|
||
yy = dateObject.getFullYear(),
|
||
formatArray,
|
||
timeOffset,
|
||
timeOffsetString,
|
||
aux;
|
||
|
||
timeOffset = dateObject.getTimezoneOffset();
|
||
|
||
timeOffsetString = timeOffset < 0 ? '+' : '-';
|
||
timeOffset = Math.sqrt(timeOffset * timeOffset);
|
||
aux = Math.floor(timeOffset / 60);
|
||
timeOffset = timeOffset - (aux * 60);
|
||
timeOffsetString += (aux < 10 ? '0' : '') + aux + ':' + (timeOffset < 10 ? '0' : '') + timeOffset;
|
||
|
||
formatArray = [
|
||
{
|
||
regExp: /dd/g,
|
||
value: d < 10 ? "0" + d : d
|
||
},
|
||
{
|
||
regExp: /d/g,
|
||
value: d
|
||
},
|
||
{
|
||
regExp: /oo/g,
|
||
value: o < 10 ? "00" + o : (o < 100 ? "0" + o : o)
|
||
},
|
||
{
|
||
regExp: /o/g,
|
||
value: o
|
||
},
|
||
{
|
||
regExp: /mm/g,
|
||
value: m < 10 ? "0" + m : m
|
||
},
|
||
{
|
||
regExp: /m/g,
|
||
value: m
|
||
},
|
||
{
|
||
regExp: /yy/g,
|
||
value: yy
|
||
},
|
||
{
|
||
regExp: /y/g,
|
||
value: yy % 100
|
||
},
|
||
{
|
||
regExp: /\@/g,
|
||
value: dateObject.getTime()
|
||
},
|
||
{
|
||
regExp: /\!/g,
|
||
value: (dateObject.getTime() * 10000) + 621355968000000000
|
||
},
|
||
{
|
||
regExp: /MM/g,
|
||
value: this.months[this.monthsOrder[dateObject.getMonth()]].name
|
||
},
|
||
{
|
||
regExp: /M/g,
|
||
value: this.months[this.monthsOrder[dateObject.getMonth()]].shortname
|
||
},
|
||
{
|
||
regExp: /HH/g,
|
||
value: (h < 10 ? '0' : '') + h
|
||
},
|
||
{
|
||
regExp: /H/g,
|
||
value: h
|
||
},
|
||
{
|
||
regExp: /hh/g,
|
||
value: (h12 < 10 ? '0' : '') + h12
|
||
},
|
||
{
|
||
regExp: /h/g,
|
||
value: h12
|
||
},
|
||
{
|
||
regExp: /ii/g,
|
||
value: (i < 10 ? '0' : '') + i
|
||
},
|
||
{
|
||
regExp: /i/g,
|
||
value: i
|
||
},
|
||
{
|
||
regExp: /ss/g,
|
||
value: (s < 10 ? '0' : '') + s
|
||
},
|
||
{
|
||
regExp: /s/g,
|
||
value: s
|
||
},
|
||
{
|
||
regExp: /UTC/g,
|
||
value: yy + '-' + (m < 10 ? '0' : '') + m + '-' + (d < 10 ? '0' : '') + d + "T"
|
||
+ (h < 10 ? '0' : '') + h + ':' + (i < 10 ? '0' : '') + i + ':' + (s < 10 ? '0' : '') + s
|
||
+ timeOffsetString
|
||
},
|
||
{
|
||
regExp: /P/g,
|
||
value: h > 12 ? 'PM' : 'AM'
|
||
},
|
||
{
|
||
regExp: /DD/g,
|
||
value: this.days[this.daysOrder[dateObject.getDay()]].name
|
||
},
|
||
{
|
||
regExp: /D/g,
|
||
value: this.days[this.daysOrder[dateObject.getDay()]].shortname
|
||
}
|
||
];
|
||
|
||
finalValue = format || this.dateFormat;
|
||
|
||
for (i = 0; i < formatArray.length; i += 1) {
|
||
finalValue = finalValue.replace(formatArray[i].regExp, formatArray[i].value);
|
||
}
|
||
|
||
return finalValue;
|
||
};
|
||
/**
|
||
* Updates the control's date text.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.updateValue = function () {
|
||
var finalValue;
|
||
|
||
if (this.dateObject) {
|
||
finalValue = this.formatDate(this.dateObject, this.dateFormat);
|
||
} else {
|
||
finalValue = "";
|
||
}
|
||
|
||
this.value = finalValue;
|
||
|
||
if (this.html) {
|
||
this.html.value = finalValue;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Gets the control's value directly from the element.
|
||
* @return {String}
|
||
*/
|
||
DateTimeControl.prototype.getValueFromRawElement = function () {
|
||
return this.getValue('UTC');
|
||
};
|
||
/**
|
||
* The handler to be executed everytime the control's value changes.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
DateTimeControl.prototype.onChangeHandler = function (hide) {
|
||
var prevValue = this.value,
|
||
newValue,
|
||
resCallback,
|
||
date,
|
||
month,
|
||
year,
|
||
auxDate,
|
||
valueChanged = false;
|
||
|
||
auxDate = new Date();
|
||
date = parseInt($(this.dom.tableBody).find("a.selected").text(), 10);
|
||
if (isNaN(date)) {
|
||
return this;
|
||
}
|
||
month = parseInt(this.dom.monthSelector.value, 10);
|
||
year = parseInt(this.dom.yearSelector.value, 10);
|
||
auxDate.setYear(year);
|
||
auxDate.setMonth(month);
|
||
auxDate.setDate(date);
|
||
if (this.datetime) {
|
||
auxDate.setMilliseconds(0);
|
||
auxDate.setSeconds(parseInt(this.dom.secondsInput.value, 10));
|
||
auxDate.setMinutes(parseInt(this.dom.minutesInput.value, 10));
|
||
auxDate.setHours(parseInt(this.dom.hoursInput.value, 10));
|
||
this.dom.doneButton.disabled = true;
|
||
} else {
|
||
if (!this.dateObject) {
|
||
this.dateObject = new Date();
|
||
}
|
||
auxDate.setMilliseconds(0);
|
||
auxDate.setSeconds(0);
|
||
auxDate.setMinutes(0);
|
||
auxDate.setHours(0);
|
||
}
|
||
if (!this.dateObject) {
|
||
this.dateObject = new Date();
|
||
}
|
||
if (auxDate.getTime() !== this.dateObject.getTime()) {
|
||
valueChanged = true;
|
||
}
|
||
if (typeof this.onBeforeChange === 'function' && valueChanged) {
|
||
resCallback = this.onBeforeChange(this.formatDate(auxDate), prevValue);
|
||
}
|
||
if (resCallback !== false) {
|
||
this.dateObject = auxDate;
|
||
} else {
|
||
if (this.dom.monthSelector.value == this.dateObject.getMonth()
|
||
&& this.dom.yearSelector.value == this.dateObject.getFullYear()) {
|
||
|
||
jQuery(this.dom.tableBody).find('a.selected').removeClass('selected')
|
||
.find('a[data-date="' + this.dateObject.getDate() + '"]').addClass('selected');
|
||
}
|
||
}
|
||
newValue = this.getValueFromRawElement();
|
||
this.updateValue();
|
||
if (hide) {
|
||
this.hideCalendar();
|
||
}
|
||
if (typeof this.onChange === 'function' && this.value !== prevValue) {
|
||
this.onChange(this.value, prevValue);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Defines the events for the control
|
||
* @chainable
|
||
*/
|
||
DateTimeControl.prototype.defineEvents = function () {
|
||
var that = this,
|
||
preselectedDate,
|
||
specialCloseHandler = function (e) {
|
||
if ((e.target !== that.html && !$(e.target).parents('#pmui-datepicker-calendar-' + that.id).length)
|
||
|| (e.type === 'keyup' && !jQuery(document.activeElement).parents('#pmui-datepicker-calendar-'
|
||
+ that.id).length)) {
|
||
that.hideCalendar();
|
||
}
|
||
},
|
||
timeInputFilter;
|
||
|
||
if (this.dom.todayButton) {
|
||
timeInputFilter = function () {
|
||
var num = parseInt(this.value, 10),
|
||
maxValue;
|
||
|
||
switch (this) {
|
||
case that.dom.hoursInput:
|
||
maxValue = 23;
|
||
break;
|
||
case that.dom.minutesInput:
|
||
case that.dom.secondsInput:
|
||
maxValue = 59;
|
||
break;
|
||
default:
|
||
throw new Error("defineEvents() at change event: No valid element.");
|
||
}
|
||
|
||
if (isNaN(num)) {
|
||
this.value = 0;
|
||
} else {
|
||
this.value = num < 0 ? 0 : Math.min(num, maxValue);
|
||
}
|
||
that.dom.doneButton.disabled = false;
|
||
};
|
||
|
||
this.addEvent('change').listen(this.dom.yearSelector, function () {
|
||
that.fillMonthSelector();
|
||
that.buildDaysTable();
|
||
});
|
||
this.addEvent('change').listen(this.dom.monthSelector, function () {
|
||
that.buildDaysTable();
|
||
});
|
||
this.addEvent('focusin click').listen(this.html, function () {
|
||
that.showCalendar();
|
||
});
|
||
this.addEvent('change').listen(this.dom.hoursInput, timeInputFilter);
|
||
this.addEvent('change').listen(this.dom.minutesInput, timeInputFilter);
|
||
this.addEvent('change').listen(this.dom.secondsInput, timeInputFilter);
|
||
this.addEvent('click').listen(this.dom.todayButton, function () {
|
||
preselectedDate = new Date();
|
||
that.dom.doneButton.disabled = false;
|
||
that.dom.yearSelector.value = preselectedDate.getFullYear();
|
||
that.fillMonthSelector();
|
||
that.dom.monthSelector.value = preselectedDate.getMonth();
|
||
that.buildDaysTable();
|
||
jQuery(that.dom.tableBody).find(".selected").removeClass('selected').end()
|
||
.find('a[data-date=' + preselectedDate.getDate() + ']').addClass("selected");
|
||
});
|
||
this.addEvent('click keyup mousedown').listen(document, specialCloseHandler)
|
||
.listen('.pmui-window', specialCloseHandler);
|
||
//In the future, if the new Event objects model is implemented the following line should be listening to an
|
||
//event close or windowClose. Currently a dirty implementation will fix he problem.
|
||
this.addEvent('click').listen('.pmui-button.pmui-window-close', function () {
|
||
that.hideCalendar();
|
||
});
|
||
this.addEvent('click').listen(this.dom.doneButton, function () {
|
||
that.onChangeHandler(true);
|
||
});
|
||
jQuery(this.dom.tableBody).on('click', 'a', function (e) {
|
||
e.preventDefault();
|
||
jQuery(that.dom.tableBody).find("a").filter(".selected").removeClass("selected");
|
||
jQuery(this).addClass("selected");
|
||
var date, month, year;
|
||
|
||
date = parseInt(this.textContent, 10);
|
||
month = parseInt(that.dom.monthSelector.value, 10);
|
||
year = parseInt(that.dom.yearSelector.value, 10);
|
||
if (that.datetime) {
|
||
that.dom.doneButton.disabled = false;
|
||
} else {
|
||
that.onChangeHandler(true);
|
||
}
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the HTML for the control.
|
||
* @return {HTMLElement}
|
||
*/
|
||
DateTimeControl.prototype.createHTML = function () {
|
||
var header,
|
||
table,
|
||
tableHeader,
|
||
monthSelector,
|
||
yearSelector,
|
||
row,
|
||
cell,
|
||
tableBody,
|
||
calendar,
|
||
footer,
|
||
button,
|
||
input;
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
DateTimeControl.superclass.prototype.createHTML.call(this);
|
||
|
||
this.html.type = 'text';
|
||
this.html.readOnly = true;
|
||
|
||
calendar = PMUI.createHTMLElement('div');
|
||
calendar.className = 'pmui-datepicker';
|
||
calendar.id = 'pmui-datepicker-calendar-' + this.id;
|
||
header = PMUI.createHTMLElement('div');
|
||
header.className = 'pmui-datepicker-header';
|
||
table = PMUI.createHTMLElement('table');
|
||
table.className = 'pmui-datepicker-head-table';
|
||
monthSelector = PMUI.createHTMLElement("select");
|
||
yearSelector = PMUI.createHTMLElement("select");
|
||
row = PMUI.createHTMLElement("tr");
|
||
cell = PMUI.createHTMLElement("td");
|
||
cell.className = 'pmui-datepicker-month-selector';
|
||
cell.appendChild(monthSelector);
|
||
row.appendChild(cell);
|
||
cell = PMUI.createHTMLElement("td");
|
||
cell.className = 'pmui-datepicker-year-selector';
|
||
cell.appendChild(yearSelector);
|
||
row.appendChild(cell);
|
||
table.appendChild(row);
|
||
header.appendChild(table);
|
||
|
||
this.dom.yearSelector = yearSelector;
|
||
this.dom.monthSelector = monthSelector;
|
||
|
||
table = PMUI.createHTMLElement('table');
|
||
table.className = 'pmui-datepicker-table';
|
||
tableHeader = PMUI.createHTMLElement('thead');
|
||
row = PMUI.createHTMLElement('tr');
|
||
this.dom.daysHeader = row;
|
||
tableHeader.appendChild(row);
|
||
table.appendChild(tableHeader);
|
||
|
||
tableBody = PMUI.createHTMLElement('tbody');
|
||
this.dom.tableBody = tableBody;
|
||
table.appendChild(tableBody);
|
||
|
||
footer = this.createFooterHTML();
|
||
calendar.appendChild(header);
|
||
calendar.appendChild(table);
|
||
calendar.appendChild(footer);
|
||
|
||
this.dom.calendar = calendar;
|
||
this.dom.footer = footer;
|
||
|
||
this.setMinDate(this.minDate)
|
||
.setMaxDate(this.maxDate)
|
||
.setDays(this.days)
|
||
.visibleDateTime(this.datetime);
|
||
|
||
if (this.eventsDefined) {
|
||
this.defineEvents();
|
||
}
|
||
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Creates the Fotter HTML for the control.
|
||
* @return {HTMLElement}
|
||
*/
|
||
DateTimeControl.prototype.createFooterHTML = function () {
|
||
var footertr,
|
||
tableFooter,
|
||
footer,
|
||
button,
|
||
cell1,
|
||
cell2,
|
||
cell3,
|
||
cell4,
|
||
cell5,
|
||
input;
|
||
|
||
footer = PMUI.createHTMLElement('div');
|
||
tableFooter = PMUI.createHTMLElement('table');
|
||
footertr = PMUI.createHTMLElement('tr');
|
||
footer.className = 'pmui-datepicker-footer';
|
||
|
||
cell1 = PMUI.createHTMLElement('td');
|
||
cell2 = cell1.cloneNode(false);
|
||
cell3 = cell1.cloneNode(false);
|
||
cell4 = cell1.cloneNode(false);
|
||
cell5 = cell1.cloneNode(false);
|
||
|
||
button = PMUI.createHTMLElement('button');
|
||
button.textContent = 'Today';
|
||
button.className = 'pmui-datepicker-button';
|
||
this.dom.todayButton = button;
|
||
cell1.appendChild(button);
|
||
footertr.appendChild(cell1);
|
||
|
||
input = PMUI.createHTMLElement('input');
|
||
input.setAttribute("type", "number");
|
||
input.size = 2;
|
||
input.min = 0;
|
||
input.max = 23;
|
||
input.value = 0;
|
||
input.placeholder = "hrs.";
|
||
this.dom.hoursInput = input;
|
||
cell2.appendChild(input);
|
||
footertr.appendChild(cell2);
|
||
|
||
input = input.cloneNode(false);
|
||
input.max = 59;
|
||
input.placeholder = "min.";
|
||
this.dom.minutesInput = input;
|
||
cell3.appendChild(input);
|
||
footertr.appendChild(cell3);
|
||
|
||
input = input.cloneNode(false);
|
||
input.max = 59;
|
||
input.placeholder = "sec.";
|
||
this.dom.secondsInput = input;
|
||
cell4.appendChild(input);
|
||
footertr.appendChild(cell4);
|
||
|
||
button = button.cloneNode(true);
|
||
button.textContent = "Done";
|
||
button.disabled = true;
|
||
this.dom.doneButton = button;
|
||
cell5.appendChild(button);
|
||
footertr.appendChild(cell5);
|
||
tableFooter.appendChild(footertr);
|
||
footer.appendChild(tableFooter);
|
||
return footer;
|
||
};
|
||
PMUI.extendNamespace('PMUI.control.DateTimeControl', DateTimeControl);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = DateTimeControl;
|
||
}
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.ui.Window
|
||
* @extend PMUI.core.Panel
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
*
|
||
* f = new PMUI.form.Form({
|
||
* items: [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Name",
|
||
* id: "123",
|
||
* value: "",
|
||
* placeholder: "insert your name",
|
||
* name: "name",
|
||
* helper: "Introduce your name",
|
||
* required : true,
|
||
* controlsWidth: 200,
|
||
* valueType: 'string'
|
||
* },
|
||
* {
|
||
* pmType: "text",
|
||
* label: "test Number",
|
||
* id: "1234",
|
||
* value: 10,
|
||
* placeholder: "insert your number",
|
||
* name: "numberTest",
|
||
* helper: "Introduce your number",
|
||
* required : true,
|
||
* controlsWidth: 200,
|
||
* valueType: 'number'
|
||
* },
|
||
* {
|
||
* pmType: "datetime",
|
||
* visible : true,
|
||
* label: "birth date",
|
||
* name: "birthdate",
|
||
* valueType: 'date',
|
||
* required: true
|
||
* }
|
||
* ]
|
||
* });
|
||
*
|
||
* w = new PMUI.ui.Window({
|
||
* title: "Window Example",
|
||
* width: 500,
|
||
* height: 230,
|
||
* modal: true,
|
||
* buttons: [
|
||
* {
|
||
* pmType: 'button',
|
||
* text: 'Save',
|
||
* handler: function() {
|
||
* alert("Saved!");
|
||
* }
|
||
* },
|
||
* {
|
||
* pmType: 'label',
|
||
* text: " or "
|
||
* },
|
||
* {
|
||
* pmType: 'button',
|
||
* text: "Close",
|
||
* handler : function () {
|
||
* w.close();
|
||
* },
|
||
* border: 'link'
|
||
* }
|
||
* ],
|
||
* closable: true,
|
||
* footerItems: [
|
||
* {
|
||
* text: "Close"
|
||
* }
|
||
* ],
|
||
* visibleFooter: true,
|
||
* buttonPanelPosition: 'top'
|
||
* });
|
||
* w.addItem(f);
|
||
* w.open();
|
||
* w.defineEvents();
|
||
*
|
||
* Create a new instace of the Window class
|
||
*
|
||
* @cfg {String} [title = [Untitled window]] Title The title for the Window
|
||
* @cfg {Boolean} [modal = true] Defines the window property is modal or not
|
||
* @cfg {String|Number} [height = "auto"] window height can be a number or a string. height
|
||
* is the div
|
||
* Element which contains a header, body and footer. When using a string that you can only use
|
||
* 'auto' or 'inherit' or # # # # px or% or # # # # em when is a number
|
||
* @cfg {String|Number} [width = 400] The width of the main window which contains a html element
|
||
* Element 'div' header, body and footer
|
||
* @cfg {String|Number} [footerHeight = "auto"] the height of the Element div footer (px, auto,
|
||
* number)which default 'auto'
|
||
* @cfg {PMUI.util.ArrayList} [buttons = []], defines an array of objects that are buttons
|
||
* settings may in the fotter Element div.
|
||
* @deprecated This config optio will be removed soon, please use the {@link #cfg-footerItems footerItems} config
|
||
* option instead.
|
||
* @cfg {boolean} [visibleCloseButton = true], the button close are can define or not in the window.
|
||
* @cfg {Array} [footerItems=[]] Sets the elements in the window footer, this elements can be instances of Button
|
||
* and/or instances of Label. The value for this config option must be an array in which each element can be:
|
||
*
|
||
* - An object literal, in this case the object literal must have the property "pmType" with its value set to
|
||
* "button" (if you want the element be a {@link PMUI.ui.Button Button}) or "label" (if you want the element be a
|
||
* {@link PMUI.ui.TextLabel Label}). Optionally you can add the respective config options for each case.
|
||
*
|
||
* - A PMUI object, in this case it must be an instance of {@link PMUI.ui.Button Button} or an instance of
|
||
* {@link PMUI.ui.TextLabel Label}.
|
||
*
|
||
* @cfg {String} [footerAlign="center"] Sets the horizontal alignment for the items in the wondow footer, the
|
||
* possible values are "center", "left", "right".
|
||
* @cfg {Boolean} [visibleFooter="false"] indicating whether the footer of the Window is visible or was hidden
|
||
* @cfg {String} [buttonPanelPosition="bottom"] indicates that position does the panel of buttons, you can be
|
||
* above or below body.
|
||
* @cfg {Function|null} [onOpen=null] The callback function to be executed everytime the
|
||
* {@link #event-onOpen onOpen} event.
|
||
* @cfg {Function|null} [onClose=null] The callback function to be executed everytime the
|
||
* {@link #event-onClose onClose} event.
|
||
*/
|
||
var Window = function (settings) {
|
||
Window.superclass.call(this, jQuery.extend(true, {
|
||
positionMode: 'absolute'
|
||
}, settings));
|
||
/**
|
||
* The window's header.
|
||
* @type {HTMLElement}
|
||
* @private
|
||
*/
|
||
this.header = null;
|
||
/**
|
||
* The window's body.
|
||
* @type {HTMLElement}
|
||
* @private
|
||
*/
|
||
this.body = null;
|
||
/**
|
||
* The window's footer.
|
||
* @type {PMUI.panel.ButtonPanel}
|
||
* @private
|
||
*/
|
||
this.footer = null;
|
||
/**
|
||
* @property {String} title
|
||
* The window's title. Set by the {@link #cfg-title title} config option and the
|
||
* {@link #method-setTitle setTitle()} method.
|
||
* @readonly
|
||
*/
|
||
this.title = null;
|
||
/**
|
||
* The windo's close button.
|
||
* @type {PMUI.ui.Button}
|
||
* @private
|
||
*/
|
||
this.closeButton = null;
|
||
/**
|
||
* If the window is opened or not.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.isOpen = false;
|
||
/**
|
||
* is defined if button panes Object is visible
|
||
* @type {[type]}
|
||
*/
|
||
this.visibleFooter = null;
|
||
/**
|
||
* If the window's close button is visible or not. Set by the
|
||
* {@link #cfg-visibleCloseButton visibleCloseButton} config option and the
|
||
* {@link #method-showCloseButton showCloseButton()} and {@link #method-hideCloseButton hideCloseButton()}
|
||
* methods.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.visibleCloseButton = null;
|
||
/**
|
||
* If the window will be a modal window. Set by the {@link #cfg-modal modal} config option and the
|
||
* {@link #method-setModal setModal()} method.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.modal = null;
|
||
/**
|
||
* The window's footer height.
|
||
* @type {Number|String}
|
||
*/
|
||
this.footerHeight = null;
|
||
/**
|
||
* The window's footer alignment.
|
||
* @type {String}
|
||
*/
|
||
this.footerAlign = null;
|
||
/**
|
||
* defines the position of the buttons panel on the window
|
||
* @type {String}
|
||
*/
|
||
this.buttonPanelPosition = null;
|
||
/**
|
||
* @event onOpen
|
||
* Fired everytime the window opens.
|
||
* @param {PMUI.ui.Window} window The window that was opened.
|
||
*/
|
||
this.onOpen = null;
|
||
/**
|
||
* @event onClose
|
||
* Fired everytime the window closes.
|
||
* @param {PMUI.ui.Window} window The window that was closed.
|
||
*/
|
||
this.onClose = null;
|
||
this.dom = {};
|
||
this.onBeforeClose = null;
|
||
Window.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Panel', Window);
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
Window.prototype.type = 'Window';
|
||
/**
|
||
* Defines the object's family
|
||
* @type {String}
|
||
*/
|
||
Window.prototype.family = 'ui';
|
||
|
||
Window.prototype.init = function (settings) {
|
||
var defaults = {
|
||
height: 'auto',
|
||
width: 'auto',
|
||
title: '[Untitled window]',
|
||
modal: true,
|
||
footerHeight: 'auto',
|
||
zOrder: 100,
|
||
footerItems: [],
|
||
footerAlign: 'center',
|
||
visibleCloseButton: true,
|
||
visibleFooter: false,
|
||
buttons: [],
|
||
buttonPanelPosition: 'bottom',
|
||
onOpen: null,
|
||
onClose: null,
|
||
onBeforeClose: null
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.footer = new PMUI.panel.ButtonPanel({
|
||
style: {
|
||
cssClasses: ['pmui-window-footer']
|
||
}
|
||
});
|
||
|
||
this.setTitle(defaults.title)
|
||
.setModal(defaults.modal)
|
||
.setWidth(defaults.width)
|
||
.setHeight(defaults.height)
|
||
.setFooterHeight(defaults.footerHeight)
|
||
.setFooterAlign(defaults.footerAlign)
|
||
.setZOrder(defaults.zOrder)
|
||
.setButtonPanelPosition(defaults.buttonPanelPosition)
|
||
.setFooterItems(defaults.footerItems)
|
||
.setOnOpenHandler(defaults.onOpen)
|
||
.setOnCloseHandler(defaults.onClose);
|
||
this.setOnBeforeCloseHandler(defaults.onBeforeClose);
|
||
|
||
if (defaults.visibleCloseButton) {
|
||
this.showCloseButton();
|
||
} else {
|
||
this.hideCloseButton();
|
||
}
|
||
if (defaults.visibleFooter) {
|
||
this.showFooter();
|
||
} else {
|
||
this.hideFooter();
|
||
}
|
||
//TODO tell the guys to replace its 'buttons' config option by FooterItems
|
||
if (defaults.footerItems && defaults.footerItems.length) {
|
||
this.setFooterItems(defaults.footerItems);
|
||
} else {
|
||
this.setFooterItems(defaults.buttons);
|
||
}
|
||
};
|
||
/**
|
||
* Sets the callback function to be executed everytime the {@link #event-onClose onClose} event fires.
|
||
* @param {Function|null} handler It can be a function or null.
|
||
*/
|
||
Window.prototype.setOnCloseHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnCloseHandler(): The parameter must be a function or null.");
|
||
}
|
||
this.onClose = handler;
|
||
return this;
|
||
};
|
||
|
||
Window.prototype.setOnBeforeCloseHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnCloseHandler(): The parameter must be a function or null.");
|
||
}
|
||
this.onBeforeClose = handler;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the callback function to be executed everytime the {@link #event-onOpen onOpen} event fires.
|
||
* @param {Function|null} handler It can be a function or null.
|
||
*/
|
||
Window.prototype.setOnOpenHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnOpenHandler(): The parameter must be a function or null.");
|
||
}
|
||
this.onOpen = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* updates the dimensions of the height of the HTMLElement window, body and foot when
|
||
it is modified by the user
|
||
* @chainable
|
||
*/
|
||
Window.prototype.updateDimensionsAndPosition = function () {
|
||
var bodyHeight,
|
||
footerHeight,
|
||
headerHeight,
|
||
windowHeight = this.height,
|
||
windowWidth;
|
||
|
||
if (!this.footer || !this.html || !this.isOpen) {
|
||
return this;
|
||
}
|
||
if (this.footerHeight === 'auto') {
|
||
this.footer.setHeight('auto');
|
||
} else {
|
||
this.footer.setHeight(this.footerHeight);
|
||
}
|
||
|
||
if (windowHeight === 'auto') {
|
||
this.body.style.height = 'auto';
|
||
this.body.style.minHeight = '150px';
|
||
} else {
|
||
if (/^\d+(\.\d+)?em$/.test(windowHeight)) {
|
||
windowHeight = PMUI.emToPx(parseInt(windowHeight, 10), this.modalObject);
|
||
} else if (/^\d+(\.\d+)?%$/.test(windowHeight)) {
|
||
windowHeight = jQuery(this.html).outerHeight();
|
||
}
|
||
footerHeight = this.visibleFooter ? jQuery(this.footer.getHTML()).outerHeight() : 0;
|
||
headerHeight = jQuery(this.header).outerHeight();
|
||
bodyHeight = windowHeight - footerHeight - headerHeight;
|
||
if (bodyHeight <= 0) {
|
||
bodyHeight = 0;
|
||
}
|
||
this.body.style.minHeight = '';
|
||
this.body.style.height = bodyHeight + "px";
|
||
}
|
||
|
||
windowWidth = jQuery(this.header).width();
|
||
windowWidth = windowWidth - (this.visibleCloseButton ? jQuery(this.closeButton.getHTML()).outerWidth() : 0);
|
||
this.dom.titleContainer.style.width = windowWidth < 0 ? 0 : windowWidth + 'px';
|
||
|
||
windowWidth = jQuery(this.html).outerWidth();
|
||
windowHeight = jQuery(this.html).outerHeight();
|
||
|
||
this.addCSSProperties({
|
||
left: '50%',
|
||
"margin-left": (windowWidth / -2) + "px",
|
||
top: '50%',
|
||
"margin-top": (windowHeight / -2) + "px"
|
||
});
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* shows the footer where the buttons are located
|
||
* @chainable
|
||
*/
|
||
Window.prototype.showFooter = function () {
|
||
this.footer.setVisible(this.visibleFooter = true);
|
||
return this.updateDimensionsAndPosition();
|
||
};
|
||
/**
|
||
* hides the footer where the buttons are located
|
||
* @chainable
|
||
*/
|
||
Window.prototype.hideFooter = function () {
|
||
this.footer.setVisible(this.visibleFooter = false);
|
||
return this.updateDimensionsAndPosition();
|
||
};
|
||
/**
|
||
* @method setTitle
|
||
* Sets the window title in the header part of the window.
|
||
* @param {String} title
|
||
* @chainable
|
||
*/
|
||
Window.prototype.setTitle = function (title) {
|
||
if (typeof title === 'string') {
|
||
this.title = title;
|
||
if (this.dom.titleContainer) {
|
||
this.dom.titleContainer.textContent = title;
|
||
this.dom.titleContainer.title = title;
|
||
}
|
||
} else {
|
||
throw new Error("The setTitle() method accepts only string values.");
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @method getTitle
|
||
* its title of teh window
|
||
* @return {String}
|
||
*/
|
||
Window.prototype.getTitle = function () {
|
||
return this.title;
|
||
};
|
||
/**
|
||
* @method setModal
|
||
* Set if the window is modal or not.
|
||
* @param {Boolean} modal
|
||
* @chainable
|
||
*/
|
||
Window.prototype.setModal = function (modal) {
|
||
if (typeof modal !== 'undefined') {
|
||
this.modal = !!modal;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
Window.prototype.setWidth = function (width) {
|
||
Window.superclass.prototype.setWidth.call(this, width);
|
||
return this.updateDimensionsAndPosition();
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
Window.prototype.setHeight = function (height) {
|
||
Window.superclass.prototype.setHeight.call(this, height);
|
||
return this.updateDimensionsAndPosition();
|
||
};
|
||
/**
|
||
* @method setFooterHeight
|
||
* high fixed size for the footer of the window
|
||
* @param {Number|String} height it can be a number or a string.
|
||
In case of using a String equals to 'auto','inherit','##px','##%','##em'
|
||
* @chainable
|
||
*/
|
||
Window.prototype.setFooterHeight = function (footerHeight) {
|
||
if (typeof footerHeight === 'number') {
|
||
this.footerHeight = footerHeight;
|
||
} else if (/^\d+(\.\d+)?px$/.test(footerHeight)) {
|
||
this.footerHeight = parseInt(footerHeight, 10);
|
||
} else if (footerHeight === 'auto') {
|
||
this.footerHeight = footerHeight;
|
||
} else {
|
||
throw new Error('setFooterHeight: footerHeight param is not valid.');
|
||
}
|
||
if (this.footer) {
|
||
this.footer.style.height = this.footerHeight + 'px';
|
||
}
|
||
if (this.isOpen) {
|
||
this.updateDimensionsAndPosition();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the alignment for the items on the footer.
|
||
* @param {String} align Possible values: "center", "left", "right".
|
||
* @chainable
|
||
*/
|
||
Window.prototype.setFooterAlign = function (align) {
|
||
this.footer.setAlignment(align);
|
||
this.footerAlign = align;
|
||
return this;
|
||
};
|
||
/**
|
||
* buttonPanelPosition parameter sets that have the panel of buttons, within the window
|
||
* @param {String} buttonPanelPosition Accepted values are 'top' or 'bottom'
|
||
*/
|
||
Window.prototype.setButtonPanelPosition = function (buttonPanelPosition) {
|
||
if (!(buttonPanelPosition === 'top' || buttonPanelPosition === 'bottom')) {
|
||
throw new Error('setButtonPanelPosition(): the value is not valid, should be a "top" or "bottom"');
|
||
}
|
||
this.buttonPanelPosition = buttonPanelPosition;
|
||
if (this.html) {
|
||
if (buttonPanelPosition === 'top') {
|
||
this.html.insertBefore(this.footer.html, this.body);
|
||
} else {
|
||
this.html.appendChild(this.footer.html);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Clear the items in the window footer.
|
||
* @chainable
|
||
*/
|
||
Window.prototype.clearFooterItems = function () {
|
||
this.footer.clearItems();
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds an item to the window footer.
|
||
* @param {Object|PMUI.ui.Button|PMUI.ui.TextLabel} item This parameter can be:
|
||
*
|
||
* - An object literal, in this case the object literal must have the property "pmType" with its value set to
|
||
* "button" (if you want the element be a {@link PMUI.ui.Button Button}) or "label" (if you want the element be a
|
||
* {@link PMUI.ui.TextLabel Label}). Optionally you can add the respective config options for each case.
|
||
*
|
||
* - A PMUI object, in this case it must be an instance of {@link PMUI.ui.Button Button} or an instance of
|
||
* {@link PMUI.ui.TextLabel Label}.
|
||
* @chainable
|
||
*/
|
||
Window.prototype.addFooterItem = function (item) {
|
||
this.footer.addItem(item);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the items for the window's footer.
|
||
* @param {Array} items This accepted value for this parameter is the same than the one for the
|
||
* {@link #cfg-footerItems footerItems} config option.
|
||
* @chainable
|
||
*/
|
||
Window.prototype.setFooterItems = function (items) {
|
||
var i;
|
||
|
||
if (!jQuery.isArray(items)) {
|
||
throw new Error("setFooterItems(): The parameter must be an array.");
|
||
}
|
||
this.clearFooterItems();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
this.addFooterItem(items[i]);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @method close
|
||
* if the window is open, sets the status to closed
|
||
* @chainable
|
||
*/
|
||
Window.prototype.close = function () {
|
||
jQuery(this.modalObject).detach();
|
||
jQuery(this.html).detach();
|
||
jQuery(this.closeButton).detach();
|
||
if (typeof this.onClose === 'function') {
|
||
this.onClose(this);
|
||
}
|
||
this.isOpen = false;
|
||
if (document.body && this.modal) {
|
||
document.body.style.overflow = "auto";
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows the window's close button.
|
||
* @chainable
|
||
*/
|
||
Window.prototype.showCloseButton = function () {
|
||
this.visibleCloseButton = true;
|
||
if (this.closeButton) {
|
||
this.closeButton.setVisible(true);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds an child item to the body HTMLElement
|
||
* @param {PMUI.core.Window|Object} item It can be one of the following data types:
|
||
* - {PMUI.core.Element} the object to add
|
||
* - {Object} a JSON object with the settings for the Container to be added
|
||
* @chainable
|
||
*/
|
||
Window.prototype.addItem = function (item) {
|
||
var itemToBeAdded;
|
||
|
||
if (this.factory) {
|
||
itemToBeAdded = this.factory.make(item);
|
||
}
|
||
if (itemToBeAdded && !this.isDirectParentOf(itemToBeAdded)) {
|
||
itemToBeAdded.parent = this;
|
||
this.items.insert(itemToBeAdded);
|
||
if (this.body) {
|
||
this.body.appendChild(itemToBeAdded.getHTML());
|
||
if (this.eventsDefined) {
|
||
itemToBeAdded.defineEvents();
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @method open
|
||
* If the window is closed, sets the status to open and displays the values set in the properties window, header, body and footer
|
||
* @chainable
|
||
*/
|
||
Window.prototype.open = function () {
|
||
var the_window;
|
||
|
||
if (this.isOpen) {
|
||
return this;
|
||
}
|
||
the_window = this.getHTML();
|
||
if (this.modal) {
|
||
this.modalObject.appendChild(the_window);
|
||
document.body.appendChild(this.modalObject);
|
||
jQuery(the_window).draggable({
|
||
handle: $(this.header),
|
||
containment: '#' + this.modalObject.id,
|
||
scroll: false
|
||
});
|
||
} else {
|
||
document.body.appendChild(the_window);
|
||
jQuery(this.getHTML()).draggable();
|
||
}
|
||
if (typeof this.onOpen === 'function') {
|
||
this.onOpen(this);
|
||
}
|
||
this.isOpen = true;
|
||
this.updateDimensionsAndPosition();
|
||
this.setVisible(true);
|
||
this.defineEvents();
|
||
if (document.body && this.modal) {
|
||
document.body.style.overflow = "hidden"
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Hides the window's close button.
|
||
* @chainable
|
||
*/
|
||
Window.prototype.hideCloseButton = function () {
|
||
this.visibleCloseButton = false;
|
||
if (this.closeButton) {
|
||
this.closeButton.setVisible(false);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows the window's close button.
|
||
* @chainable
|
||
*/
|
||
Window.prototype.showCloseButton = function () {
|
||
this.visibleCloseButton = true;
|
||
if (this.closeButton) {
|
||
this.closeButton.setVisible(true);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @method updateModalDimensions
|
||
* Updates the status of modal HTMLElement and
|
||
fixed all styles required to show
|
||
*/
|
||
Window.prototype.updateModalDimensions = function () {
|
||
if (document && this.modalObject) {
|
||
this.modalObject.style.height = this.modalObject.style.width = "0px";
|
||
this.modalObject.style.width = window.innerWidth + "px";
|
||
this.modalObject.style.height = window.innerHeight + "px";
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the padding for the windows body.
|
||
* @param {Number|String} bodyPadding A number or a string with a pixel-unit formatted text.d
|
||
*/
|
||
Window.prototype.setBodyPadding = function (bodyPadding) {
|
||
if (typeof bodyPadding === 'number') {
|
||
this.bodyPadding = bodyPadding
|
||
} else if (/^\d+(\.\d+)?px$/.test(height)) {
|
||
this.bodyPadding = parseInt(bodyPadding, 10);
|
||
} else {
|
||
throw new Error('setHeight: height param is not valid.');
|
||
}
|
||
|
||
this.bodyPadding = bodyPadding;
|
||
if (this.html) {
|
||
this.body.style.padding = bodyPadding + 'px';
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
Window.prototype.paintItems = function () {
|
||
if (this.body) {
|
||
Window.superclass.prototype.paintItems.call(this);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @method defineEvents
|
||
* Defines the events associated with the Window
|
||
*/
|
||
Window.prototype.defineEvents = function () {
|
||
var that = this,
|
||
html = this.html,
|
||
modal = this.modal,
|
||
stopPropagation,
|
||
updateDimensions,
|
||
cancelWheeling = function (e) {
|
||
var height = that.body.clientHeight,
|
||
scrollHeight = that.body.scrollHeight,
|
||
scrollTop = that.body.scrollTop;
|
||
|
||
e.stopPropagation();
|
||
};
|
||
|
||
Window.superclass.prototype.defineEvents.call(this);
|
||
stopPropagation = new PMUI.event.Action({
|
||
handler: function (e) {
|
||
e.stopPropagation();
|
||
}
|
||
}),
|
||
updateDimensions = new PMUI.event.Action({
|
||
handler: function () {
|
||
that.updateModalDimensions();
|
||
}
|
||
});
|
||
this.addEvent('mousedown').listen(this.body, stopPropagation);
|
||
that.addEvent('click').listen(this.html, stopPropagation);
|
||
that.addEvent('mouseover').listen(this.html, stopPropagation);
|
||
that.addEvent('mouseout').listen(this.html, stopPropagation);
|
||
that.addEvent('mousedown').listen(this.html, stopPropagation);
|
||
that.addEvent('resize').listen(window, updateDimensions);
|
||
this.addEvent('keydown').listen(this.html, stopPropagation);
|
||
this.addEvent('keypress').listen(this.html, stopPropagation);
|
||
this.addEvent('keyup').listen(this.html, stopPropagation);
|
||
|
||
this.modalObject.addEventListener('wheel', function (e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
}, false);
|
||
|
||
this.body.addEventListener('wheel', cancelWheeling, false);
|
||
this.footer.defineEvents();
|
||
that.closeButton.defineEvents();
|
||
this.updateModalDimensions();
|
||
return this;
|
||
};
|
||
/**
|
||
* @method createHTML
|
||
* Creates natural elements to the window html: head, body and foot
|
||
* @return {HTMLElement} returns a HTML element
|
||
*/
|
||
Window.prototype.createHTML = function () {
|
||
var header,
|
||
body,
|
||
titleContainer,
|
||
closeButton,
|
||
modal,
|
||
that = this;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
Window.superclass.prototype.createHTML.call(this);
|
||
|
||
header = PMUI.createHTMLElement('div');
|
||
header.className = 'pmui-window-header';
|
||
body = PMUI.createHTMLElement('div');
|
||
body.className = 'pmui-window-body';
|
||
modal = PMUI.createHTMLElement('div');
|
||
modal.className = 'pmui-window-modal';
|
||
modal.id = this.id + "-modal";
|
||
|
||
titleContainer = PMUI.createHTMLElement('span');
|
||
titleContainer.className = 'pmui-window-title';
|
||
titleContainer.style.display = "inline-block";
|
||
|
||
closeButton = new PMUI.ui.Button({
|
||
style: {
|
||
cssClasses: ['pmui-window-close']
|
||
},
|
||
text: "",
|
||
width: '16px',
|
||
handler: function (event) {
|
||
if (typeof that.onBeforeClose === "function") {
|
||
that.onBeforeClose(that);
|
||
} else {
|
||
that.close();
|
||
}
|
||
}
|
||
});
|
||
|
||
this.modalObject = modal;
|
||
header.appendChild(titleContainer);
|
||
header.appendChild(closeButton.getHTML());
|
||
$(closeButton.html).find(".button-icon").css('opacity', 'inherit');
|
||
|
||
this.html.appendChild(header);
|
||
this.html.appendChild(body);
|
||
this.html.appendChild(this.footer.getHTML());
|
||
|
||
this.dom.titleContainer = titleContainer;
|
||
this.header = header;
|
||
this.body = this.containmentArea = body;
|
||
this.closeButton = closeButton;
|
||
|
||
this.setTitle(this.title)
|
||
.setFooterHeight(this.footerHeight)
|
||
.setItems(this.items.asArray().slice(0))
|
||
.setButtonPanelPosition(this.buttonPanelPosition);
|
||
|
||
if (this.visibleCloseButton) {
|
||
this.showCloseButton();
|
||
} else {
|
||
this.hideCloseButton();
|
||
}
|
||
if (this.visibleFooter) {
|
||
this.showFooter();
|
||
} else {
|
||
this.hideFooter();
|
||
}
|
||
|
||
if (this.eventsDefined) {
|
||
this.defineEvents();
|
||
}
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.ui.Window', Window);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = Window;
|
||
}
|
||
}());
|
||
(function () {
|
||
var MessageWindow = function (settings) {
|
||
MessageWindow.superclass.call(this, settings);
|
||
/**
|
||
* The message for the message window.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.message = null;
|
||
/**
|
||
* An object for store the necessary dom elements to build the message window HTML.
|
||
* @type {Object}
|
||
* @private
|
||
*/
|
||
this.dom = {};
|
||
this.iconClass = null;
|
||
this.windowMessageType = null;
|
||
MessageWindow.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.ui.Window', MessageWindow);
|
||
|
||
|
||
MessageWindow.prototype.type = 'WindowMessage';
|
||
|
||
MessageWindow.prototype.family = 'ui';
|
||
|
||
MessageWindow.prototype.init = function (settings) {
|
||
var defaults = {
|
||
message: '[not-message]',
|
||
iconClass: '',
|
||
windowMessageType: 'default',
|
||
title: '',
|
||
footerAlign: "right"
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setFooterAlign(defaults.footerAlign);
|
||
this.setMessage(defaults.message);
|
||
this.setWindowMessageType(defaults.windowMessageType);
|
||
this.setTitle(defaults.title);
|
||
|
||
};
|
||
|
||
MessageWindow.prototype.setMessage = function (message) {
|
||
if (typeof message !== 'string') {
|
||
throw new Error('setMessage(): the parameter must be a string.');
|
||
}
|
||
|
||
this.message = jQuery.trim(message);
|
||
|
||
if (this.dom.messageContainer) {
|
||
this.dom.messageContainer.textContent = message;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
MessageWindow.prototype.getMessage = function () {
|
||
return this.message;
|
||
};
|
||
|
||
MessageWindow.prototype.setWindowMessageType = function (type) {
|
||
var classMessage = "";
|
||
|
||
if (typeof type !== "string") {
|
||
throw new Error("settype(): the type value is not valid");
|
||
}
|
||
this.windowMessageType = type;
|
||
this.style.removeClasses(["pmui-windowmessage-default", "pmui-windowmessage-error", "pmui-windowmessage-warning", "pmui-windowmessage-success"]);
|
||
classMessage = 'pmui-windowmessage-' + this.windowMessageType;
|
||
switch (this.windowMessageType) {
|
||
case 'error':
|
||
this.style.addClasses([classMessage]);
|
||
break;
|
||
case 'warning':
|
||
this.style.addClasses([classMessage]);
|
||
break;
|
||
case 'success':
|
||
this.style.addClasses([classMessage]);
|
||
break;
|
||
case 'default':
|
||
this.style.addClasses([classMessage]);
|
||
break;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
MessageWindow.prototype.getWindowMessageType = function () {
|
||
return this.windowMessageType;
|
||
};
|
||
|
||
MessageWindow.prototype.addItem = function () {
|
||
return this;
|
||
};
|
||
|
||
MessageWindow.prototype.createHTML = function () {
|
||
var table,
|
||
row,
|
||
cellIcon,
|
||
cellLabel,
|
||
icon,
|
||
p,
|
||
textContent;
|
||
|
||
MessageWindow.superclass.prototype.createHTML.call(this);
|
||
|
||
table = PMUI.createHTMLElement('table');
|
||
table.className = 'pmui-messagewindow-container';
|
||
row = PMUI.createHTMLElement('tr');
|
||
cellIcon = PMUI.createHTMLElement('td');
|
||
cellLabel = PMUI.createHTMLElement('td');
|
||
cellLabel.style.textAlign = "center";
|
||
cellLabel.className = "pmui-content-label"
|
||
icon = PMUI.createHTMLElement('span');
|
||
icon.className = 'pmui-messagewindow-icon';
|
||
textContent = PMUI.createHTMLElement('span');
|
||
textContent.className = 'pmui-messagewindow-message';
|
||
|
||
cellIcon.appendChild(icon);
|
||
row.appendChild(cellIcon);
|
||
|
||
|
||
cellLabel.appendChild(textContent);
|
||
row.appendChild(cellLabel);
|
||
table.appendChild(row);
|
||
|
||
this.dom.icon = icon;
|
||
this.dom.messageContainer = textContent;
|
||
|
||
this.body.appendChild(table);
|
||
|
||
this.setMessage(this.message);
|
||
this.body.style.padding = "15px";
|
||
cellLabel.style.width = (typeof this.width == 'number') ? this.width * (0.84) + "px" : "70%";
|
||
this.body.style.minHeight = "inherit";
|
||
return this.html;
|
||
};
|
||
|
||
MessageWindow.prototype.updateDimensionsAndPosition = function () {
|
||
var bodyHeight,
|
||
footerHeight,
|
||
headerHeight,
|
||
windowHeight = this.height,
|
||
windowWidth;
|
||
|
||
if (!this.footer || !this.html || !this.isOpen) {
|
||
return this;
|
||
}
|
||
if (this.footerHeight === 'auto') {
|
||
this.footer.setHeight('auto');
|
||
} else {
|
||
this.footer.setHeight(this.footerHeight);
|
||
}
|
||
|
||
if (windowHeight === 'auto') {
|
||
this.body.style.height = 'auto';
|
||
this.body.style.minHeight = 'inherit';
|
||
} else {
|
||
if (/^\d+(\.\d+)?em$/.test(windowHeight)) {
|
||
windowHeight = PMUI.emToPx(parseInt(windowHeight, 10), this.modalObject);
|
||
} else if (/^\d+(\.\d+)?%$/.test(windowHeight)) {
|
||
windowHeight = jQuery(this.html).outerHeight();
|
||
}
|
||
footerHeight = this.visibleFooter ? jQuery(this.footer.getHTML()).outerHeight() : 0;
|
||
headerHeight = jQuery(this.header).outerHeight();
|
||
bodyHeight = windowHeight - footerHeight - headerHeight;
|
||
if (bodyHeight <= 0) {
|
||
bodyHeight = 0;
|
||
}
|
||
this.body.style.minHeight = '';
|
||
this.body.style.height = bodyHeight + "px";
|
||
}
|
||
|
||
windowWidth = jQuery(this.header).width();
|
||
windowWidth = windowWidth - (this.visibleCloseButton ? jQuery(this.closeButton.getHTML()).outerWidth() : 0);
|
||
this.dom.titleContainer.style.width = windowWidth < 0 ? 0 : windowWidth + 'px';
|
||
|
||
windowWidth = jQuery(this.html).outerWidth();
|
||
windowHeight = jQuery(this.html).outerHeight();
|
||
|
||
this.addCSSProperties({
|
||
left: '50%',
|
||
"margin-left": (windowWidth / -2) + "px",
|
||
top: '50%',
|
||
"margin-top": (windowHeight / -2) + "px"
|
||
});
|
||
return this;
|
||
}
|
||
|
||
PMUI.extendNamespace('PMUI.ui.MessageWindow', MessageWindow);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = MessageWindow;
|
||
}
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.ui.ErrorMessageWindow
|
||
* A window to show a error message.
|
||
* @extends {PMUI.ui.MessageWindow}
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var message_window = new PMUI.ui.ErrorMessageWindow({
|
||
* message: 'This is an error message.'
|
||
* });
|
||
* message_window.open();
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class ErrorMessageWindow
|
||
* @param {Object} [settings={}] An object with the config options.
|
||
*
|
||
* @cfg {String} [title='Error'] The message to show in the message window.
|
||
*/
|
||
var ErrorMessageWindow = function (settings) {
|
||
ErrorMessageWindow.superclass.call(this, settings);
|
||
ErrorMessageWindow.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.ui.MessageWindow', ErrorMessageWindow);
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} settings The object with the config options.
|
||
* @private
|
||
*/
|
||
ErrorMessageWindow.prototype.init = function (settings) {
|
||
var defaults = {
|
||
title: 'Error'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setTitle(defaults.title);
|
||
};
|
||
/**
|
||
* Creates the message window HTML.
|
||
* @return {HTMLElement}
|
||
*/
|
||
ErrorMessageWindow.prototype.createHTML = function () {
|
||
ErrorMessageWindow.superclass.prototype.createHTML.call(this);
|
||
|
||
jQuery(this.dom.icon).addClass('pmui-messagewindow-icon-error');
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.ui.ErrorMessageWindow', ErrorMessageWindow);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ErrorMessageWindow;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.ui.WarningMessageWindow
|
||
* A window to show a warning message.
|
||
* @extends {PMUI.ui.MessageWindow}
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var message_window = new PMUI.ui.WarningMessageWindow({
|
||
* message: 'This is a warning message.'
|
||
* });
|
||
* message_window.open();
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class WarningMessageWindow
|
||
* @param {Object} [settings={}] An object with the config options.
|
||
*
|
||
* @cfg {String} [title='Warning'] The message to show in the message window.
|
||
*/
|
||
var WarningMessageWindow = function (settings) {
|
||
WarningMessageWindow.superclass.call(this, settings);
|
||
WarningMessageWindow.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.ui.MessageWindow', WarningMessageWindow);
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} settings The object with the config options.
|
||
* @private
|
||
*/
|
||
WarningMessageWindow.prototype.init = function (settings) {
|
||
var defaults = {
|
||
title: 'Warning'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setTitle(defaults.title);
|
||
};
|
||
/**
|
||
* Creates the message window ĤTML.
|
||
* @return {HTMLElement}
|
||
*/
|
||
WarningMessageWindow.prototype.createHTML = function () {
|
||
WarningMessageWindow.superclass.prototype.createHTML.call(this);
|
||
|
||
jQuery(this.dom.icon).addClass('pmui-messagewindow-icon-warning');
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.ui.WarningMessageWindow', WarningMessageWindow);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = WarningMessageWindow;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.ui.SuccessMessageWindow
|
||
* A window to show a success message.
|
||
* @extends {PMUI.ui.MessageWindow}
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var message_window = new PMUI.ui.SuccessMessageWindow({
|
||
* message: 'This is a success message.'
|
||
* });
|
||
* message_window.open();
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class SuccessMessageWindow
|
||
* @param {Object} [settings={}] An object with the config options.
|
||
*
|
||
* @cfg {String} [title='Success'] The message to show in the message window.
|
||
*/
|
||
var SuccessMessageWindow = function (settings) {
|
||
SuccessMessageWindow.superclass.call(this, settings);
|
||
SuccessMessageWindow.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.ui.MessageWindow', SuccessMessageWindow);
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} settings The object with the config options.
|
||
* @private
|
||
*/
|
||
SuccessMessageWindow.prototype.init = function (settings) {
|
||
var defaults = {
|
||
title: 'Success'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setTitle(defaults.title);
|
||
};
|
||
/**
|
||
* Creates the message window ĤTML.
|
||
* @return {HTMLElement}
|
||
*/
|
||
SuccessMessageWindow.prototype.createHTML = function () {
|
||
SuccessMessageWindow.superclass.prototype.createHTML.call(this);
|
||
|
||
jQuery(this.dom.icon).addClass('pmui-messagewindow-icon-success');
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.ui.SuccessMessageWindow', SuccessMessageWindow);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = SuccessMessageWindow;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.ui.InfoMessageWindow
|
||
* A window to show an info message.
|
||
* @extends {PMUI.ui.MessageWindow}
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var message_window = new PMUI.ui.InfoMessageWindow({
|
||
* message: 'This is an info message.'
|
||
* });
|
||
* message_window.open();
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class InfoMessageWindow
|
||
* @param {Object} [settings={}] An object with the config options.
|
||
*
|
||
* @cfg {String} [title='Information'] The message to show in the message window.
|
||
*/
|
||
var InfoMessageWindow = function (settings) {
|
||
InfoMessageWindow.superclass.call(this, settings);
|
||
InfoMessageWindow.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.ui.MessageWindow', InfoMessageWindow);
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} settings The object with the config options.
|
||
* @private
|
||
*/
|
||
InfoMessageWindow.prototype.init = function (settings) {
|
||
var defaults = {
|
||
title: 'Info'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setTitle(defaults.title);
|
||
};
|
||
/**
|
||
* Creates the message window HTML.
|
||
* @return {HTMLElement}
|
||
*/
|
||
InfoMessageWindow.prototype.createHTML = function () {
|
||
InfoMessageWindow.superclass.prototype.createHTML.call(this);
|
||
|
||
jQuery(this.dom.icon).addClass('pmui-messagewindow-icon-info');
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.ui.InfoMessageWindow', InfoMessageWindow);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = InfoMessageWindow;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.ui.ConfirmMessageWindow
|
||
* A window to show a question message. It haas built-in Yes and No buttons, but they can be overrode by some
|
||
* custom ones.
|
||
* @extends {PMUI.ui.MessageWindow}
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var message_window = new PMUI.ui.ConfirmMessageWindow({
|
||
* message: 'Do you want to display an alert?',
|
||
* onYes: function() {
|
||
* alert("this is an alert");
|
||
* message_window.close();
|
||
* },
|
||
* onNo: function() {
|
||
* message_window.close();
|
||
* }
|
||
* });
|
||
* message_window.open();
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class ConfirmMessageWindow
|
||
* @param {Object} [settings={}] An object with the config options.
|
||
*
|
||
* @cfg {String} [title='Error'] The message to show in the message window.
|
||
* @cfg {String} [yesText='Yes'] The text for the window's built-in Yes button.
|
||
* @cfg {String} [noText='No'] The text for the window's built-in No button.
|
||
* @cfg {Function|null} [onYes=null] The handler to be executed when the built-in Yes button is clicked.
|
||
* @cfg {Function|null} [onNo=null] The handler to be executed when the built-in No button is clicked.
|
||
* @cfg footerItems
|
||
* The items to be shown in the message window's footer, the accepted values for this are the same that the ones
|
||
* for the Window's footerItems config option.
|
||
*
|
||
* By default this is an empty array, if you modify this then the built-in Yes and No buttons won't be used,
|
||
* therefore the yesText, noText config options and onYes, onNo handlers won't be used either.
|
||
*/
|
||
var ConfirmMessageWindow = function (settings) {
|
||
ConfirmMessageWindow.superclass.call(this, settings);
|
||
ConfirmMessageWindow.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.ui.MessageWindow', ConfirmMessageWindow);
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} settings The object with the config options.
|
||
* @private
|
||
*/
|
||
ConfirmMessageWindow.prototype.init = function (settings) {
|
||
var yesButton = new PMUI.ui.Button(),
|
||
noButton = new PMUI.ui.Button(),
|
||
defaults = {
|
||
title: 'Confirm',
|
||
yesText: 'Yes',
|
||
noText: 'No',
|
||
onYes: null,
|
||
onNo: null,
|
||
footerItems: []
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setTitle(defaults.title);
|
||
|
||
if (!defaults.footerItems || !defaults.footerItems.length) {
|
||
defaults.footerItems = [
|
||
yesButton.setHandler(defaults.onYes).setText(defaults.yesText),
|
||
noButton.setHandler(defaults.onNo).setText(defaults.noText)
|
||
];
|
||
}
|
||
this.setFooterItems(defaults.footerItems);
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ConfirmMessageWindow.prototype.createHTML = function () {
|
||
ConfirmMessageWindow.superclass.prototype.createHTML.call(this);
|
||
|
||
jQuery(this.dom.icon).addClass('pmui-messagewindow-icon-confirm');
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.ui.ConfirmMessageWindow', ConfirmMessageWindow);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ConfirmMessageWindow;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.ui.Button
|
||
* @extend PMUI.core.Element
|
||
* * Usage example (only for subclasses since this is an abstract class):
|
||
*
|
||
* @example
|
||
* //Remember, this is an abstract class so it shouldn't be instantiate,
|
||
* //anyway we are instantiating it just for this example
|
||
*
|
||
* var a;
|
||
*
|
||
* a = new PMUI.ui.Button({
|
||
* handler : function () {
|
||
* alert("hi!");
|
||
* },
|
||
* text : 'closed',
|
||
* iconClass:"pmui-gridpanel-pager_previous",
|
||
* iconPosition : "left",
|
||
* messageTooltip : 'this button to close the window'
|
||
* });
|
||
*
|
||
* document.body.appendChild(a.getHTML());
|
||
* a.defineEvents();
|
||
*
|
||
* @constructor
|
||
* Create a new instace of the Window class
|
||
* @param {Object} settigs Constructor object
|
||
*/
|
||
var Button = function (settings, parent) {
|
||
Button.superclass.call(this, jQuery.extend(settings, {elementTag: "a"}));
|
||
/**
|
||
* @property icon for the Button, it can a string
|
||
* @type {String}
|
||
*/
|
||
this.icon = null;
|
||
/**
|
||
* @property {PMUI.event.Action} Defines the Action Object to handle he action windows
|
||
* @type {Action}
|
||
*/
|
||
this.action = null;
|
||
/**
|
||
* @property parent
|
||
* @type {String}
|
||
*/
|
||
this.parent = null;
|
||
/**
|
||
* @property text of the Button
|
||
* @type {String}
|
||
*/
|
||
this.text = null;
|
||
/**
|
||
* @property alias Button for idetified to alias
|
||
* @type {String}
|
||
*/
|
||
this.aliasButton = null;
|
||
/**
|
||
* [iconPosition description]
|
||
* @type {[type]}
|
||
*/
|
||
this.iconPosition = null;
|
||
/**
|
||
* [messageTooltip description]
|
||
* @type {[type]}
|
||
*/
|
||
this.messageTooltip = null;
|
||
|
||
//this.buttonClass = null;
|
||
|
||
//this.foreignClassName = null;
|
||
|
||
this.linkStyle = null;
|
||
|
||
this.labelVisible = null;
|
||
this.iconVisible = null;
|
||
this.disabled = null;
|
||
this.dom = null;
|
||
this.buttonType = null;
|
||
|
||
Button.prototype.init.call(this, settings, parent);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', Button);
|
||
|
||
Button.prototype.type = 'Button';
|
||
Button.prototype.family = 'Button';
|
||
|
||
Button.prototype.init = function (settings, parent) {
|
||
var defaults;
|
||
|
||
defaults = {
|
||
iconClass: '',
|
||
aliasButton: null,
|
||
parent: parent || null,
|
||
height: "auto",
|
||
width: "auto",
|
||
handler: function () {
|
||
},
|
||
text: '[button]',
|
||
iconPosition: "right",
|
||
tooltip: false,
|
||
messageTooltip: "",
|
||
//buttonClass : '',
|
||
iconVisible: true,
|
||
labelVisible: true,
|
||
disabled: false,
|
||
//cls: 'pmui-button',
|
||
//linkStyle: false,
|
||
//foreignClassName : "",
|
||
//useForeignClass : false
|
||
buttonType: 'default'
|
||
};
|
||
this.dom = {};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setAliasButton(defaults.aliasButton)
|
||
.setParent(defaults.parent)
|
||
.setText(defaults.text)
|
||
.setIcon(defaults.iconClass)
|
||
.setWidth(defaults.width)
|
||
.setHeight(defaults.height)
|
||
.setIconPosition(defaults.iconPosition)
|
||
.setHandler(defaults.handler)
|
||
.setTooltipMessage(defaults.messageTooltip)
|
||
.setDisabled(defaults.disabled)
|
||
.setButtonType(defaults.buttonType);
|
||
|
||
};
|
||
|
||
Button.prototype.setButtonType = function (buttonType) {
|
||
var classButton = "";
|
||
|
||
if (typeof buttonType !== "string") {
|
||
throw new Error("setButtonType(): the type value is not valid");
|
||
}
|
||
this.buttonType = buttonType;
|
||
this.style.removeClasses(["pmui-error", "pmui-warning", "pmui-success", "pmui-info", "pmui-link"]);
|
||
classButton = 'pmui-' + this.buttonType;
|
||
switch (this.buttonType) {
|
||
case 'error':
|
||
this.style.addClasses([classButton]);
|
||
break;
|
||
case 'warning':
|
||
this.style.addClasses([classButton]);
|
||
break;
|
||
case 'success':
|
||
this.style.addClasses([classButton]);
|
||
break;
|
||
case 'info':
|
||
this.style.addClasses([classButton]);
|
||
break;
|
||
case 'link':
|
||
this.style.addClasses([classButton]);
|
||
break;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Button.prototype.showLabel = function () {
|
||
this.labelVisible = true;
|
||
if (this.html) {
|
||
this.label.style.display = '';
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Button.prototype.setDisabled = function (value) {
|
||
if (typeof value !== 'boolean') {
|
||
throw new Error('setDisabled(): the parameter is not valid, should be type boolean');
|
||
}
|
||
this.disabled = value;
|
||
if (this.html) {
|
||
if (this.disabled) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
}
|
||
return this;
|
||
}
|
||
|
||
Button.prototype.disable = function () {
|
||
this.disabled = true;
|
||
this.style.addClasses(['pmui-disabled']);
|
||
if (this.eventsDefined) {
|
||
this.defineEvents();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @method enable
|
||
* button can be enabled if it was disabled before
|
||
* @chainable
|
||
*/
|
||
Button.prototype.enable = function () {
|
||
this.disabled = false;
|
||
this.style.removeClasses(['pmui-disabled']);
|
||
if (this.eventsDefined) {
|
||
this.defineEvents();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Performs the click action on the button.
|
||
* @chainable
|
||
*/
|
||
Button.prototype.click = function () {
|
||
jQuery(this.html).trigger('click');
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* @method setHandler
|
||
* Sets the handler for the button
|
||
* @param {Function} handler is a Function.
|
||
* @chainable
|
||
*/
|
||
Button.prototype.setHandler = function (handler) {
|
||
if (typeof handler !== "function" && handler !== null) {
|
||
throw new Error("setHandler(): the parameter should be a function or null;");
|
||
}
|
||
this.handler = handler;
|
||
this.action = new PMUI.event.Action({
|
||
actionText: this.aliasButton,
|
||
handler: this.handler
|
||
});
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* @method removeEvent
|
||
* Remove Event for the button
|
||
* @param {Function} handler is a Function.
|
||
* @chainable
|
||
*/
|
||
Button.prototype.removeEvent = function (type) {
|
||
jQuery(this.html).unbind(type);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* @method removeEvents
|
||
* Remove Events for the button
|
||
* @param {Function} handler is a Function.
|
||
* @chainable
|
||
*/
|
||
Button.prototype.removeEvents = function () {
|
||
var x;
|
||
for (x in this.events) {
|
||
this.removeEvent(this.events[x].eventName);
|
||
}
|
||
this.events = {};
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the text for the label Button.
|
||
* @param {String} is a String.
|
||
* @chainable
|
||
*/
|
||
Button.prototype.setText = function (text) {
|
||
this.text = text;
|
||
if (this.html && this.dom.spanText) {
|
||
if (jQuery.trim(text) !== "") {
|
||
this.dom.spanText.textContent = this.text;
|
||
} else {
|
||
this.dom.spanText.inerHTML = ' ';
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the icon for the Button.
|
||
* @param {String} is a String.
|
||
* @chainable
|
||
*/
|
||
Button.prototype.setIcon = function (iconClass) {
|
||
var icon;
|
||
|
||
if (!(typeof iconClass == "string")) {
|
||
throw new Error("setIcon(): the property should bo string");
|
||
}
|
||
this.icon = iconClass;
|
||
if (this.html && this.dom.icon) {
|
||
this.dom.icon.className = this.dom.icon.className + " " + this.icon;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* @method setAliasButton
|
||
* Sets the alias for the label Button
|
||
* @param {String} is a String. lue
|
||
* @chainable
|
||
*/
|
||
Button.prototype.setAliasButton = function (alias) {
|
||
this.aliasButton = alias;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* @method setParent
|
||
* Sets the parent for the Button.
|
||
* @param {Object} is a HTML Element.
|
||
* @chainable
|
||
*/
|
||
Button.prototype.setParent = function (parent) {
|
||
this.parent = parent;
|
||
return this;
|
||
};
|
||
/**
|
||
* @method createHTML
|
||
* Create HTML for the element
|
||
* @return {HTMLElement} HTML Generated
|
||
*/
|
||
|
||
Button.prototype.createHTML = function () {
|
||
var spanText,
|
||
icon;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
Button.superclass.prototype.createHTML.call(this);
|
||
this.html.href = '#';
|
||
//***conatainer for text
|
||
spanText = PMUI.createHTMLElement('span');
|
||
spanText.className = "button-label";
|
||
this.dom.spanText = spanText;
|
||
this.html.appendChild(spanText);
|
||
|
||
// container for icon
|
||
icon = PMUI.createHTMLElement('span');
|
||
icon.className = 'button-icon';
|
||
this.dom.icon = icon;
|
||
this.html.appendChild(icon);
|
||
|
||
this.setIconPosition(this.iconPosition);
|
||
this.setTooltipMessage(this.messageTooltip);
|
||
|
||
this.setDisabled(this.disabled);
|
||
this.setText(this.text);
|
||
this.setIcon(this.icon);
|
||
this.applyStyle();
|
||
|
||
return this.html;
|
||
};
|
||
/**
|
||
* @method defineEvents
|
||
* Define events click for the Button, listening the function action
|
||
*/
|
||
|
||
Button.prototype.defineEvents = function () {
|
||
var that = this;
|
||
|
||
Button.superclass.prototype.defineEvents.call(this);
|
||
if (this.html) {
|
||
if (this.disabled) {
|
||
this.addEvent('click').listen(this.html, function (e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
});
|
||
} else {
|
||
this.addEvent('click').listen(this.html, function (e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
if (typeof that.handler === 'function') {
|
||
that.handler(that);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* @method setHeight
|
||
* Sets the height for the button.
|
||
* @param {String, number} height
|
||
* This parameter can take the following types
|
||
* - number
|
||
* - string
|
||
*/
|
||
Button.prototype.setHeight = function (height) {
|
||
if (typeof height === 'number') {
|
||
this.height = height + "px";
|
||
} else if (/^\d+(\.\d+)?px$/.test(height)) {
|
||
this.height = height;
|
||
} else if (/^\d+(\.\d+)?%$/.test(height)) {
|
||
this.height = height;
|
||
} else if (/^\d+(\.\d+)?em$/.test(height)) {
|
||
this.height = height;
|
||
} else if (height === 'auto' || height === 'inherit') {
|
||
this.height = height;
|
||
} else {
|
||
throw new Error('setHeight: height param is not a number');
|
||
}
|
||
if (this.height !== 'auto') {
|
||
this.style.addProperties({"line-height": parseInt(this.height, 10) + "px"});
|
||
} else {
|
||
this.style.addProperties({"line-height": 'normal'});
|
||
}
|
||
this.applyStyle();
|
||
return this;
|
||
};
|
||
/**
|
||
* @method setIconPosition
|
||
* Creates the HTML element for the control.
|
||
* @param {String} position
|
||
* This parameter can take the following values: left, right
|
||
*/
|
||
Button.prototype.setIconPosition = function (position) {
|
||
if (position == 'right' || position == "left" || position == "top" || position == "bottom") {
|
||
this.iconPosition = position;
|
||
if (this.html) {
|
||
if (this.iconPosition == 'left' || this.iconPosition == 'top') {
|
||
$(this.html).prepend(this.dom.icon);
|
||
if (this.iconPosition == 'left') {
|
||
this.dom.icon.style.display = 'inline-block';
|
||
this.dom.icon.style.marginLeft = '';
|
||
|
||
} else {
|
||
this.dom.icon.style.display = 'block';
|
||
this.dom.icon.style.marginLeft = '50%';
|
||
}
|
||
} else {
|
||
$(this.html).append(this.dom.icon);
|
||
if (this.iconPosition == 'right') {
|
||
this.dom.icon.style.display = 'inline-block';
|
||
this.dom.icon.style.marginLeft = '';
|
||
} else {
|
||
this.dom.icon.style.display = 'block';
|
||
this.dom.icon.style.marginLeft = '50%';
|
||
}
|
||
}
|
||
}
|
||
|
||
} else {
|
||
throw new Error("setIconPosition(): the parameter is not valid, should be 'right','left', 'top' or 'bottom'");
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @method setTooltipMessage
|
||
* Sets the tooltip message
|
||
* @param {String} messageTooltip
|
||
*/
|
||
Button.prototype.setTooltipMessage = function (messageTooltip) {
|
||
if (typeof messageTooltip == "string") {
|
||
this.messageTooltip = messageTooltip;
|
||
if (this.html) {
|
||
this.html.setAttribute('title', messageTooltip);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace("PMUI.ui.Button", Button);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = Button;
|
||
}
|
||
}());
|
||
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.ui.TooltipMessage
|
||
* @extends PMUI.core.Element
|
||
* Class to handle tooltip elements and alert messages
|
||
*
|
||
* Usage example (creates 4 TooltipMessage instances):
|
||
*
|
||
* @example
|
||
* //usage example
|
||
* //creates 4 TooltipMessage instances:
|
||
* var a, b, c, d;
|
||
* $(function() {
|
||
* // Instantiates a simple info message
|
||
* a = new PMUI.ui.TooltipMessage({
|
||
* message: "Hi folks! this is a info",
|
||
* category: "info",
|
||
* displayMode: "block",
|
||
* mode: "normal"
|
||
* });
|
||
* //Instantiates an error tooltip with mouse tracking option enabled
|
||
* b = new PMUI.ui.TooltipMessage({
|
||
* message: "Hi folks! this is an error",
|
||
* category: "error",
|
||
* track: true,
|
||
* displayMode: "block"
|
||
* });
|
||
* //Instantiates a warning tooltip with a slide down effect when the tooltip is opened
|
||
* c = new PMUI.ui.TooltipMessage({
|
||
* message: "Hi folks! this is a warning",
|
||
* category: "warning",
|
||
* displayMode: "block",
|
||
* showEffect: {
|
||
* effect: "slideDown",
|
||
* delay: 250
|
||
* }
|
||
* });
|
||
* //Instantiates a help tooltip with a explode effect when the tooltip is hidden
|
||
* d = new PMUI.ui.TooltipMessage({
|
||
* message: "Hi folks! this is a help",
|
||
* category: "help",
|
||
* displayMode: "block",
|
||
* hideEffect: {
|
||
* effect: "explode",
|
||
* delay: 250
|
||
* }
|
||
* });
|
||
* document.body.appendChild(a.getHTML());
|
||
* document.body.appendChild(b.getHTML());
|
||
* document.body.appendChild(c.getHTML());
|
||
* document.body.appendChild(d.getHTML());
|
||
* });
|
||
* @constructor
|
||
* Create a new instace of the class 'TooltipMessage'
|
||
* @param {Object} settings
|
||
* A JSON object which can contain the following fields:
|
||
*
|
||
* @cfg {String} [message = ""] The message to show
|
||
* @cfg {String} [category = 'help'] The object's category, it can be "info", "help", "warning" or "error"
|
||
* @cfg {String} [displayMode = 'inline'] Determines if the object will have an "inline" or "block" displaying
|
||
* @cfg {String} [mode="tooltip"] When is set to "tooltip" the object has a tooltip behavior, but when is set to "normal" it
|
||
* has a regular message behavior
|
||
* @cfg {String} [tooltipClass='pmui-tooltip-message'] the css class for the HTML element which will contain the message
|
||
* @cfg {Object} [tooltipPosition = {
|
||
my: "left top+15",
|
||
at: "left bottom",
|
||
collision: "flipfit"
|
||
}] specifies the position for the tooltip, read the
|
||
{@link PMUI.ui.TooltipMessage#setTooltipPosition .setTooltipPosition()} for more info
|
||
* @cfg {Object} [showEffect=null] specifies the animation to apply when the tooltip is shown, read the
|
||
{@link PMUI.ui.TooltipMessage#setShowEffect .setShowEffect()} for more info
|
||
* @cfg {Object} [hideEffect=null] specifies the animation to apply when the tooltip is hidden, read the
|
||
{@link PMUI.ui.TooltipMessage#setHideEffect .setHideEffect()} for more info
|
||
* @cfg {Function} [onOpen] a callback function to be invoked when the tooltip is shown
|
||
* @cfg {Function} [onClose] a callback functio to be invoked when the tooltip is hidden
|
||
* @cfg {Boolean} [track = false] a turns on/off the tooltip to follow the mouse movement
|
||
* Note: tooltipClass, tooltipPosition, showEffect, hideEffect, onOpen, onClose and track options
|
||
only are applied when the mode is set to "tooltip"
|
||
*/
|
||
var TooltipMessage = function (settings) {
|
||
TooltipMessage.superclass.call(this, settings);
|
||
/**
|
||
* @property {PMUI.core.Element} icon
|
||
* An {@link PMUI.core.Element} which is used to put the icon in
|
||
* @private
|
||
*/
|
||
this.icon = null;
|
||
/**
|
||
* An Element
|
||
* @type {PMUI.core.Element} which is used to display the message when the mode is set to "normal"
|
||
* @private
|
||
*/
|
||
this.messageArea = null;
|
||
/**
|
||
* @property {String} [message=""]
|
||
* The message to be displayed
|
||
* @readonly
|
||
*/
|
||
this.message = null;
|
||
/**
|
||
* @property {String} [category="help"]
|
||
* The category for the message
|
||
* @readonly
|
||
*/
|
||
this.category = null;
|
||
/**
|
||
* @property {String} [displayMode="inline"]
|
||
* The displaying mode for the object's HTML element
|
||
* @readonly
|
||
*/
|
||
this.displayMode = null;
|
||
/**
|
||
* @property {String} [mode="tooltip"]
|
||
* The object's behavior mode
|
||
* @readonly
|
||
*/
|
||
this.mode = null;
|
||
/**
|
||
* @property {Object} [tooltipPosition={
|
||
my: "left top+15",
|
||
at: "left bottom",
|
||
collision: "flipfit"
|
||
}]
|
||
* The tooltip position
|
||
* @readonly
|
||
*/
|
||
this.tooltipPosition = null;
|
||
/**
|
||
* @property {String} [tooltipClass="pmui-tooltip-message"]
|
||
* The CSS class name for the tooltip HTML element
|
||
* @readonly
|
||
*/
|
||
this.tooltipClass = null;
|
||
/**
|
||
* @property {Object|Boolean|String|Number} [showEffect=null]
|
||
* The effect to apply when the tooltip is shown
|
||
*/
|
||
this.showEffect = null;
|
||
/**
|
||
* @property {Object|Boolean|String|Number} [hideEffect=null]
|
||
* The effect to apply when the tooltip is hidden
|
||
*/
|
||
this.hideEffect = null;
|
||
/**
|
||
* @property {Function} [onOpen=null]
|
||
* The function callback to be invoked when the tooltip is shown
|
||
*/
|
||
this.onOpen = null;
|
||
/**
|
||
* @property {Function} [onClose=null]
|
||
* The function callback to be invoked when the tooltip is hidden
|
||
* @type {Function}
|
||
*/
|
||
this.onClose = null;
|
||
/**
|
||
* @property {Boolean} [track=false]
|
||
* A boolean that specifies if the the tooltip element must follow the mouse position
|
||
*/
|
||
this.track = null;
|
||
TooltipMessage.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', TooltipMessage);
|
||
|
||
TooltipMessage.prototype.type = 'PMUITooltipMessage';
|
||
|
||
TooltipMessage.prototype.family = 'PMUITooltipMessage';
|
||
|
||
TooltipMessage.prototype.init = function (settings) {
|
||
var defaults = {
|
||
message: "",
|
||
category: "help",
|
||
displayMode: "inline",
|
||
mode: "tooltip",
|
||
tooltipClass: 'pmui-tooltip-message',
|
||
tooltipPosition: {
|
||
my: "left top+15",
|
||
at: "left bottom",
|
||
collision: "flipfit"
|
||
},
|
||
showEffect: null,
|
||
hideEffect: null,
|
||
onOpen: null,
|
||
onClose: null,
|
||
track: false
|
||
};
|
||
|
||
$.extend(true, defaults, settings);
|
||
|
||
this.onClose = defaults.onClose;
|
||
this.onOpen = defaults.onOpen;
|
||
|
||
this.setTooltipClass(defaults.tooltipClass)
|
||
.setTooltipPosition(defaults.tooltipPosition)
|
||
.setShowEffect(defaults.showEffect)
|
||
.setHideEffect(defaults.hideEffect)
|
||
.setTrack(defaults.track)
|
||
.setMessage(defaults.message)
|
||
.setCategory(defaults.category)
|
||
.setDisplayMode(defaults.displayMode)
|
||
.setMode(defaults.mode);
|
||
};
|
||
/**
|
||
* Set the CSS class for the HTML element which will contain the tooltip message.
|
||
* This only takes effect when the mode property is set to "tooltip"
|
||
* @param {String} tooltipClass
|
||
*/
|
||
TooltipMessage.prototype.setTooltipClass = function (tooltipClass) {
|
||
this.tooltipClass = tooltipClass;
|
||
return this;
|
||
};
|
||
/**
|
||
* Establish if the HTML element which will be contain the tooltip message should track
|
||
(follow) the mouse position when it appears
|
||
* * This only takes effect when the mode property is set to "tooltip"
|
||
* @param {Boolean} [track=true]
|
||
*/
|
||
TooltipMessage.prototype.setTrack = function (track) {
|
||
this.track = !!track;
|
||
if (this.html) {
|
||
this.setMode(this.mode);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* [setHideEffect description]
|
||
* If and how to animate the hiding of the tooltip.
|
||
* This only takes effect when the mode property is set to "tooltip"
|
||
* @param {Object|Boolean|String|Number} effect
|
||
* - Boolean: When set to false, no animation will be used and the tooltip will be hidden
|
||
immediately. When set to true, the tooltip will fade out with the default duration and the
|
||
default easing.
|
||
* - Number: The tooltip will fade out with the specified duration and the default easing.
|
||
* - String: The tooltip will be hidden using the specified effect. The value can either be the
|
||
name of a built-in jQuery animation method, such as "slideUp", or the name of a jQuery UI effect,
|
||
such as "fold". In either case the effect will be used with the default duration and the default easing.
|
||
* - Object: If the value is an object, then effect, delay, duration, and easing properties may be
|
||
provided. If the effect property contains the name of a jQuery method, then that method will be used;
|
||
otherwise it is assumed to be the name of a jQuery UI effect. When using a jQuery UI effect that supports
|
||
additional settings, you may include those settings in the object and they will be passed to the effect.
|
||
If duration or easing is omitted, then the default values will be used. If effect is omitted,
|
||
then "fadeOut" will be used. If delay is omitted, then no delay is used.
|
||
*/
|
||
TooltipMessage.prototype.setHideEffect = function (effect) {
|
||
this.hideEffect = effect;
|
||
if (this.html) {
|
||
this.setMode(this.mode);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* If and how to animate the showing of the tooltip.
|
||
* This only takes effect when the mode property is set to "tooltip"
|
||
* @param {Object|Boolean|String|Number} effect
|
||
* - Boolean: When set to false, no animation will be used and the tooltip will be shown immediately.
|
||
When set to true, the tooltip will fade in with the default duration and the default easing.
|
||
* - Number: The tooltip will fade in with the specified duration and the default easing.
|
||
* - String: The tooltip will be shown using the specified effect. The value can either be the name of
|
||
a built-in jQuery animation method, such as "slideDown", or the name of a jQuery UI effect, such as
|
||
"fold". In either case the effect will be used with the default duration and the default easing.
|
||
* - Object: If the value is an object, then effect, delay, duration, and easing properties may be
|
||
provided. If the effect property contains the name of a jQuery method, then that method will be used;
|
||
otherwise it is assumed to be the name of a jQuery UI effect. When using a jQuery UI effect that
|
||
supports additional settings, you may include those settings in the object and they will be passed
|
||
to the effect. If duration or easing is omitted, then the default values will be used. If effect is
|
||
omitted, then "fadeIn" will be used. If delay is omitted, then no delay is used.
|
||
*/
|
||
TooltipMessage.prototype.setShowEffect = function (effect) {
|
||
this.showEffect = effect;
|
||
if (this.html) {
|
||
this.setMode(this.mode);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Identifies the position of the tooltip in relation to the associated target element.
|
||
* The of option defaults to the target element, but you can specify another element to position
|
||
against. You can refer to the [jQuery UI Position][1] utility for more details about the various options.
|
||
* [1]: http://api.jqueryui.com/position
|
||
* @param {Object} position
|
||
*/
|
||
TooltipMessage.prototype.setTooltipPosition = function (position) {
|
||
this.tooltipPosition = position;
|
||
if (this.html) {
|
||
this.setMode(this.mode);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the message to be shown in both normal and tooltip modes
|
||
* @param {String} message
|
||
*/
|
||
TooltipMessage.prototype.setMessage = function (message) {
|
||
if (typeof message === 'string') {
|
||
this.message = message;
|
||
if (this.html) {
|
||
if (this.messageArea) {
|
||
this.messageArea.getHTML().textContent = message;
|
||
}
|
||
|
||
if (this.mode === 'tooltip') {
|
||
this.icon.html.title = message;
|
||
} else {
|
||
this.icon.html.title = "";
|
||
}
|
||
}
|
||
} else {
|
||
throw new Error("setMessage() method only accepts string values.");
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Set the category for the tooltip/message object
|
||
* @param {String} category the value can be one of the following:
|
||
*
|
||
* - help
|
||
* - info
|
||
* - error
|
||
* - warning
|
||
*/
|
||
TooltipMessage.prototype.setCategory = function (category) {
|
||
var validCategories = [
|
||
"help", "info", "error", "warning"
|
||
];
|
||
|
||
if (typeof category === 'string' && validCategories.indexOf(category) > -1) {
|
||
this.category = category;
|
||
if (this.icon && this.messageArea) {
|
||
this.icon.style.removeAllClasses();
|
||
this.icon.style.addClasses(['pmui-icon', 'pmui-icon-' + category]);
|
||
this.messageArea.className = 'pmui-tooltip-message pmui-tooltip-' + category + '-message';
|
||
}
|
||
if (this.html) {
|
||
if (this.category === "error") {
|
||
this.style.addClasses(["pmui-tooltip-category-error"]);
|
||
} else {
|
||
this.style.removeClasses(["pmui-tooltip-category-error"]);
|
||
}
|
||
}
|
||
} else {
|
||
throw new Error('setCategory() method only accepts' +
|
||
' one of the following values: "help", "info", "warning", "info".');
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the CSS displaying mode
|
||
* @param {String} displayMode It can take the "block" or "inline" values
|
||
*/
|
||
TooltipMessage.prototype.setDisplayMode = function (displayMode) {
|
||
if (displayMode === 'block' || displayMode === 'inline') {
|
||
this.displayMode = displayMode;
|
||
if (this.html) {
|
||
this.style.addProperties({"display": displayMode});
|
||
}
|
||
} else {
|
||
throw new Error('setDisplayMode() method only accepts "inline" or "block" values');
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the mode for the object, it determines if the current object has a tooltip or notification message behavior
|
||
* @param {String} mode It only can take one of the following values:
|
||
* - "tooltip"
|
||
* - "normal"
|
||
*/
|
||
TooltipMessage.prototype.setMode = function (mode) {
|
||
if (mode === 'tooltip' || mode === 'normal') {
|
||
this.mode = mode;
|
||
if (this.html) {
|
||
$(this.html).addClass('pmui-tooltip-mode-' + mode);
|
||
if (mode === 'tooltip') {
|
||
this.messageArea.setVisible(false);
|
||
this.icon.html.title = this.message;
|
||
$(this.icon.html).tooltip({
|
||
tooltipClass: this.tooltipClass,
|
||
position: this.tooltipPosition,
|
||
show: this.showEffect,
|
||
hide: this.hideEffect,
|
||
open: this.onOpen,
|
||
track: this.track,
|
||
close: this.onClose
|
||
});
|
||
} else {
|
||
try {
|
||
$(this.icon.html).tooltip('destroy');
|
||
} catch (ex) {
|
||
}
|
||
this.icon.html.title = "";
|
||
this.messageArea.setVisible(true);
|
||
}
|
||
}
|
||
} else {
|
||
throw new Error('setMode() method only accepts "tooltip" or "normal" values');
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* It creates the HTML Element for the current object
|
||
* @return {HTMLElement}
|
||
*/
|
||
TooltipMessage.prototype.createHTML = function () {
|
||
var html,
|
||
messageArea,
|
||
icon;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
html = PMUI.createHTMLElement("span");
|
||
html.className = 'pmui-tooltip';
|
||
icon = new PMUI.core.Element({
|
||
elementTag: 'span',
|
||
width: 18,
|
||
height: 18,
|
||
style: {
|
||
cssClasses: ['pmui-icon'],
|
||
cssProperties: {
|
||
display: "inline-block",
|
||
"vertical-align": "middle"
|
||
}
|
||
}
|
||
});
|
||
messageArea = new PMUI.core.Element({
|
||
elementTag: 'span',
|
||
style: {
|
||
cssClasses: ['pmui-tooltip-message']
|
||
}
|
||
});
|
||
|
||
html.appendChild(icon.getHTML());
|
||
html.appendChild(messageArea.getHTML());
|
||
this.icon = icon;
|
||
this.messageArea = messageArea;
|
||
this.html = html;
|
||
|
||
this.applyStyle();
|
||
|
||
this.setCategory(this.category);
|
||
this.setMessage(this.message);
|
||
this.setMode(this.mode);
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.ui.TooltipMessage', TooltipMessage);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = TooltipMessage;
|
||
}
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.ui.TextLabel
|
||
* A text label that can contain a plain text or an HTML formatted text.
|
||
* @extends {PMUI.core.Element}
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var plainText, htmlText;
|
||
* plainText = new PMUI.ui.TextLabel({
|
||
* textMode: 'plain',
|
||
* text: 'Hello! this is a label with a plain text in it',
|
||
* style: {
|
||
* cssProperties: {
|
||
* background: "red"
|
||
* }
|
||
* }
|
||
* });
|
||
* htmlText = new PMUI.ui.TextLabel({
|
||
* textMode: 'html',
|
||
* text: '<h1>Hello!</h1> this ia a label with a <b> HTML</b> formatted text'
|
||
* });
|
||
* document.body.appendChild(plainText.getHTML());
|
||
* document.body.appendChild(htmlText.getHTML());
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class.
|
||
* @param {Object} [settings={}] An object literal with the config options to config the object.
|
||
*
|
||
* @cfg {String} [textMode='plain'] The rendering mode for the text in the label. Possible values:
|
||
*
|
||
* - "plain": for plain text rendering.
|
||
* - "html": for html text rendering. Only the <b>, <i>, <h1> to <h6> tags are allowed, any other tags will be
|
||
* removed.
|
||
* @cfg {String} [elementTag='span'] The HTML tag to be used as the text label.
|
||
* @cfg {String} [text=""] The label's text.
|
||
*/
|
||
var TextLabel = function (settings) {
|
||
TextLabel.superclass.call(this, settings);
|
||
/**
|
||
* The text rendering mode. Set by the {@link #cfg-textMode textMode config option} and the
|
||
* {@link #method-setTextMode setTextMode() method}.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.textMode = null;
|
||
/**
|
||
* The current displayed label's text. Set by the {@link #cfg-text text config option} and the
|
||
* {@link #method-setText setText() method}.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.text = null;
|
||
/**
|
||
* The original set text.
|
||
* @type {String}
|
||
* @private
|
||
*/
|
||
this.rawText = null;
|
||
TextLabel.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', TextLabel);
|
||
/**
|
||
* The object's type.
|
||
* @type {String}
|
||
*/
|
||
TextLabel.prototype.type = 'TextLabel';
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} [settings={}] An object literal with the config options the new object will be initialized
|
||
* with.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
TextLabel.prototype.init = function (settings) {
|
||
var defaults = {
|
||
textMode: 'plain',
|
||
elementTag: 'span',
|
||
text: ''
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setElementTag(defaults.elementTag)
|
||
.setTextMode(defaults.textMode)
|
||
.setText(defaults.text);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the label's text.
|
||
* @param {String} text
|
||
*/
|
||
TextLabel.prototype.setText = function (text) {
|
||
var tags;
|
||
|
||
if (typeof text !== 'string') {
|
||
throw new Error('setText(): the parameter must be a string.');
|
||
}
|
||
this.text = this.rawText = text;
|
||
if (this.textMode === 'html') {
|
||
allowed = ("<b><i><h1><h2><h3><h4><h5><h6>".match(/<[a-z][a-z0-9]*>/g) || []).join('');
|
||
tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
|
||
commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
|
||
this.text = text.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
|
||
return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
|
||
});
|
||
}
|
||
|
||
if (this.html) {
|
||
if (this.textMode === 'html') {
|
||
this.html.innerHTML = this.text;
|
||
} else {
|
||
this.html.textContent = this.text;
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the text rendering mode.
|
||
* @param {String} textMode Possible values:
|
||
*
|
||
* - "plain": for plain text rendering.
|
||
* - "html": for html text rendering. Only the <b>, <i>, <h1> to <h6> tags are allowed, any other tags will be
|
||
* removed.
|
||
*/
|
||
TextLabel.prototype.setTextMode = function (textMode) {
|
||
if (textMode !== 'plain' && textMode !== 'html') {
|
||
throw Error("setTextMode(): The parameter must be \"plain\" or \"html\".");
|
||
}
|
||
this.textMode = textMode;
|
||
if (typeof this.rawText === 'string') {
|
||
this.setText(this.rawText);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the label's HTML.
|
||
* @return {HTMLElement}
|
||
*/
|
||
TextLabel.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
TextLabel.superclass.prototype.createHTML.call(this);
|
||
this.setText(this.rawText);
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.ui.TextLabel', TextLabel);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = TextLabel;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.ui.FlashMessage
|
||
* A message to display for a while.
|
||
* @extends {PMUI.core.Element}
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var message = new PMUI.ui.FlashMessage({
|
||
* message: "Hi!, this is a flash message!",
|
||
* duration: 5000,
|
||
* severity: 'info'
|
||
* });
|
||
*
|
||
* message.show();
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class.
|
||
* @param {Object} [settings] The config options.
|
||
*
|
||
* @cfg {String|Array} [message=""] The object's message. It can be a single string or an array of strings. In the
|
||
* llatter case the mesage will be showed in a list format.
|
||
* @cfg {Number} [duration=3000] The time in milliseconds the message will be displayed.
|
||
* @cfg {HTMLElement|PMUI.ui.Element} [appendTo=document.body] The html element/PMUI's object the flash message
|
||
* will be displayed.
|
||
* @cfg {String} [display="absolute"] The display mode for the object's html.
|
||
* @cfg {String} [position="absolute"] The position mode for the object's html.
|
||
* @cfg {String} [severity="info"] The severity for the message. Valid values: 'info', 'success', 'error'.
|
||
*/
|
||
var FlashMessage = function (settings) {
|
||
FlashMessage.superclass.call(this, settings);
|
||
/**
|
||
* The object's message. Set by the {@link #cfg-message message} config option and the
|
||
* {@link #method-setMessage setMessage()} method.
|
||
* @type {String|Array}
|
||
* @readonly
|
||
*/
|
||
this.message = null;
|
||
/**
|
||
* The duration in milliseconds to show the message. Set by the {@link #cfg-duration duration} config option
|
||
* and the {@link #method-setDuration setDuration()} method.
|
||
* @type {Number}
|
||
* @readonly
|
||
*/
|
||
this.duration = null;
|
||
/**
|
||
* The html element/PMUI's object the message will be displayed in. Set by the {@link #cfg-appendTo appendTo}
|
||
* config option and the {@link #method-setAppendTo setAppendTo()} method.
|
||
* @type {HTMLElement|PMUI.core.Element}
|
||
*/
|
||
this.appendTo = null;
|
||
/**
|
||
* The message's severity. Set by the {@link #cfg-severity severity} config option and the
|
||
* {@link #method-setSeverity setSeverity()} method.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.severity = null;
|
||
FlashMessage.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', FlashMessage);
|
||
/**
|
||
* The object's type.
|
||
* @type {String}
|
||
*/
|
||
FlashMessage.prototype.type = 'FlashMessage';
|
||
/**
|
||
* The initializer method.
|
||
* @param {Object} [settings] The config options
|
||
* @private
|
||
*/
|
||
FlashMessage.prototype.init = function (settings) {
|
||
var defaults = {
|
||
message: "",
|
||
duration: 3000,
|
||
appendTo: document.body,
|
||
display: 'inline-block',
|
||
positionMode: 'fixed',
|
||
severity: 'info'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
this.setMessage(defaults.message)
|
||
.setDuration(defaults.duration)
|
||
.setAppendTo(defaults.appendTo)
|
||
.setPositionMode(defaults.positionMode)
|
||
.setDisplay(defaults.display)
|
||
.setSeverity(defaults.severity);
|
||
};
|
||
/**
|
||
* Sets the severity for the message.
|
||
* @param {String} severity Valid values: "info", "success" or "error".
|
||
* @chainable
|
||
*/
|
||
FlashMessage.prototype.setSeverity = function (severity) {
|
||
if (!(severity === 'success' || severity === 'error' || severity === 'info')) {
|
||
throw new Error('setSeverity(): the parameter must be "success" or "error" or "info"');
|
||
}
|
||
this.severity = severity;
|
||
this.style.removeClasses(['pmui-info', 'pmui-error', 'pmui-success']).addClasses(['pmui-' + severity]);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the html element/PMUI's object in which the message will be displayed.
|
||
* @param {HTMLElement|PMUI.core.Element} appendTo
|
||
* @chainable
|
||
*/
|
||
FlashMessage.prototype.setAppendTo = function (appendTo) {
|
||
if (!(PMUI.isHTMLElement(appendTo) || appendTo instanceof PMUI.core.Element)) {
|
||
throw new Error("setAppendTo(): The parameter must be a HTML element or an instance of PMUI.ui.Element.");
|
||
}
|
||
this.appendTo = appendTo;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the duration for display the message.
|
||
* @param {Number} duration The duration in milliseconds.
|
||
* @chainable
|
||
*/
|
||
FlashMessage.prototype.setDuration = function (duration) {
|
||
if (typeof duration !== 'number') {
|
||
throw new Error('setDuration(): The parameter must be a number.');
|
||
}
|
||
this.duration = duration;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the message for the object.
|
||
* @param {String|Array} message It can be a string or an array of strings, in the latter case the message will be
|
||
* showed in a list format.
|
||
* @chainable
|
||
*/
|
||
FlashMessage.prototype.setMessage = function (message) {
|
||
var ul,
|
||
li,
|
||
i;
|
||
|
||
if (typeof message !== 'string' && !jQuery.isArray(message)) {
|
||
throw new Error('setMessage(): The parameter must be a message.');
|
||
}
|
||
this.message = (typeof message === 'string') ? jQuery.trim(message) : message;
|
||
if (this.html) {
|
||
jQuery(this.html).empty();
|
||
if (typeof message === 'string') {
|
||
this.html.textContent = message;
|
||
} else {
|
||
ul = PMUI.createHTMLElement('ul');
|
||
ul.className = 'pmui-flashmessage-list';
|
||
ul.style.listStyleType = 'none';
|
||
for (i = 0; i < message.length; i += 1) {
|
||
li = PMUI.createHTMLElement('li');
|
||
li.textContent = message[i];
|
||
ul.appendChild(li);
|
||
}
|
||
this.html.appendChild(ul);
|
||
}
|
||
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows the message in the html element/PMUI's object specified by the {@link #cfg-appendTo appendTo} config
|
||
* option or the {@link #method-setAppendTo setAppendTo()} method.
|
||
* @chainable
|
||
*/
|
||
FlashMessage.prototype.show = function () {
|
||
var targetHTML = this.appendTo,
|
||
html = this.html,
|
||
top = 50,
|
||
w,
|
||
pw;
|
||
|
||
if (!PMUI.isHTMLElement(targetHTML)) {
|
||
targetHTML = targetHTML.html;
|
||
}
|
||
if (targetHTML) {
|
||
if (!html) {
|
||
html = this.getHTML();
|
||
}
|
||
jQuery(html).fadeTo(1, 0).get(0).style.top = top + "px";
|
||
document.body.appendChild(html);
|
||
w = jQuery(html).outerWidth();
|
||
targetHTML.appendChild(html);
|
||
this.style.addProperties({
|
||
left: '50%',
|
||
'margin-left': w / -2
|
||
});
|
||
jQuery(html).finish().css({
|
||
'top': '50px'
|
||
}).fadeTo(1, 0).animate({
|
||
top: "-=" + top,
|
||
opacity: 1
|
||
}, 400, 'swing').delay(this.duration).animate({
|
||
top: "+=" + top,
|
||
opacity: 0,
|
||
zIndex: '0'
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritDoc
|
||
*/
|
||
FlashMessage.prototype.createHTML = function () {
|
||
FlashMessage.superclass.prototype.createHTML.call(this);
|
||
this.setMessage(this.message);
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.ui.FlashMessage', FlashMessage);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = FlashMessage;
|
||
}
|
||
}());
|
||
(function () {
|
||
var Menu = function (settings) {
|
||
settings = jQuery.extend(true, settings, {
|
||
elementTag: 'ul',
|
||
positionMode: 'absolute'
|
||
});
|
||
Menu.superclass.call(this, settings);
|
||
this.targetElement = null;
|
||
this.parent = null;
|
||
this.onShow = null;
|
||
this.onHide = null;
|
||
this.displayed = null;
|
||
this.factory = new PMUI.menu.MenuItemFactory();
|
||
this.items = new PMUI.util.ArrayList();
|
||
this.onOutsideClickHandler = null;
|
||
Menu.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', Menu);
|
||
|
||
Menu.prototype.type = 'Menu';
|
||
|
||
Menu.prototype.init = function (settings) {
|
||
var defaults = {
|
||
targetElement: null,
|
||
parent: null,
|
||
onShow: null,
|
||
onHide: null,
|
||
items: []
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.onShow = defaults.onShow;
|
||
this.onHide = defaults.onHide;
|
||
this.setParent(defaults.parent)
|
||
.setItems(defaults.items)
|
||
.setTargetElement(defaults.targetElement)
|
||
.setOutsideClickHandler();
|
||
};
|
||
|
||
Menu.prototype.setOutsideClickHandler = function () {
|
||
var that = this;
|
||
|
||
this.onOutsideClickHandler = function (e) {
|
||
if (!jQuery(e.currentTarget).parents('#' + that.id).length) {
|
||
that.hide();
|
||
}
|
||
};
|
||
return this;
|
||
};
|
||
|
||
Menu.prototype.setTargetElement = function (target) {
|
||
var rootMenu,
|
||
targetElement = (this.targetElement && this.targetElement.html) || document.body;
|
||
|
||
$(targetElement).removeClass('pmui-contextmenu-target');
|
||
if (target instanceof PMUI.core.Element || null) {
|
||
rootMenu = this.getRootMenu();
|
||
if (rootMenu.targetElement) {
|
||
if (rootMenu.targetElement.menu === rootMenu) {
|
||
rootMenu.targetElement.menu = null;
|
||
}
|
||
}
|
||
rootMenu.targetElement = target;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Menu.prototype.getTargetElement = function () {
|
||
var rootMenu = this.getRootMenu();
|
||
return rootMenu.targetElement;
|
||
};
|
||
|
||
Menu.prototype.addItem = function (item) {
|
||
var newItem = this.factory.make(item);
|
||
|
||
if (newItem) {
|
||
newItem.setParent(this);
|
||
this.items.insert(newItem);
|
||
if (this.html) {
|
||
this.html.appendChild(newItem.getHTML());
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Menu.prototype.removeItem = function (item) {
|
||
var itemToRemove;
|
||
|
||
if (typeof item === 'string') {
|
||
itemToRemove = this.items.find('id', item);
|
||
} else if (typeof item === 'number') {
|
||
itemToRemove = this.items.get(item);
|
||
} else if (item instanceof PMUI.item.MenuItem && this.items.contains(item)) {
|
||
itemToRemove = item;
|
||
}
|
||
if (itemToRemove) {
|
||
this.items.remove(itemToRemove);
|
||
jQuery(itemToRemove.html).detach();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Menu.prototype.clearItems = function () {
|
||
var index = 0;
|
||
while (this.items.getSize()) {
|
||
this.removeItem(index);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Menu.prototype.setItems = function (items) {
|
||
var i;
|
||
|
||
if (!jQuery.isArray(items)) {
|
||
throw new Error('setItems(): The parameter must be an array.');
|
||
}
|
||
this.clearItems();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
this.addItem(items[i]);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Menu.prototype.getItems = function () {
|
||
var index = 0;
|
||
return this.items.asArray().slice(index);
|
||
};
|
||
|
||
Menu.prototype.setParent = function (parent) {
|
||
if (!(parent === null || parent instanceof PMUI.menu.MenuItem)) {
|
||
throw new Error('setParent(): The parameter must be an instance of PMUI.item.MenuItem or null.');
|
||
}
|
||
this.parent = parent;
|
||
return this;
|
||
};
|
||
|
||
Menu.prototype.defineEventListeners = function () {
|
||
this.removeEvents();
|
||
this.addEvent('contextmenu').listen(this.html, function (e) {
|
||
e.stopPropagation();
|
||
e.preventDefault();
|
||
});
|
||
this.addEvent('click').listen(this.html, function (e) {
|
||
e.stopPropagation();
|
||
});
|
||
this.addEvent('mousedown').listen(this.html, function (e) {
|
||
e.stopPropagation();
|
||
});
|
||
|
||
return this;
|
||
};
|
||
|
||
Menu.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
Menu.superclass.prototype.createHTML.call(this);
|
||
|
||
this.setItems(this.items.asArray().slice(0));
|
||
|
||
this.defineEventListeners();
|
||
|
||
return this.html;
|
||
};
|
||
|
||
Menu.prototype.isRoot = function () {
|
||
return !this.parent;
|
||
};
|
||
|
||
Menu.prototype.getRootMenu = function () {
|
||
if (this.isRoot()) {
|
||
return this;
|
||
} else {
|
||
return this.parent.parent.getRootMenu();
|
||
}
|
||
};
|
||
|
||
Menu.prototype.show = function (x, y) {
|
||
var rootMenu = this.getRootMenu(),
|
||
targetElement = (this.targetElement && this.targetElement.html) || document.body,
|
||
zIndex = parseInt(targetElement.style.zIndex);
|
||
x = x || 0;
|
||
y = y || 0;
|
||
rootMenu.setPosition({
|
||
x: x,
|
||
y: y
|
||
});
|
||
PMUI.removeCurrentMenu();
|
||
rootMenu.setZOrder(zIndex + 1);
|
||
$(targetElement).addClass('pmui-contextmenu-target');
|
||
document.body.appendChild(rootMenu.getHTML());
|
||
this.addEvent('mousedown', 'clickOutside').listen(document, this.onOutsideClickHandler);
|
||
this.displayed = true;
|
||
PMUI.currentContextMenu = this;
|
||
if (typeof this.onShow === 'function') {
|
||
this.onShow(this);
|
||
}
|
||
if (document.documentElement.clientHeight - y < jQuery(this.html).outerHeight()) {
|
||
this.html.style.top = y - jQuery(this.html).outerHeight() + 'px'
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Menu.prototype.hide = function () {
|
||
var rootMenu = this.getRootMenu(),
|
||
targetElement = (this.targetElement && this.targetElement.html) || document.body;
|
||
|
||
this.removeEvent('clickOutside');
|
||
$(targetElement).removeClass('pmui-contextmenu-target');
|
||
jQuery(rootMenu.html).detach();
|
||
rootMenu.displayed = false;
|
||
PMUI.currentContextMenu = null;
|
||
if (typeof rootMenu.onHide === 'function') {
|
||
rootMenu.onHide(rootMenu);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Menu.prototype.setContextMenu = function () {
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.menu.Menu', Menu);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = Menu;
|
||
}
|
||
}());
|
||
(function () {
|
||
var MenuItem = function (settings) {
|
||
MenuItem.superclass.call(this, settings);
|
||
this.dom = {};
|
||
this.parent = null;
|
||
MenuItem.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', MenuItem);
|
||
|
||
MenuItem.prototype.type = 'MenuItem';
|
||
|
||
MenuItem.prototype.init = function (settings) {
|
||
var defaults = {
|
||
parent: null
|
||
}
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setParent(defaults.parent);
|
||
};
|
||
|
||
MenuItem.prototype.setParent = function (parent) {
|
||
if (!(parent === null || parent instanceof PMUI.menu.Menu)) {
|
||
throw new Error('setParent(): The parameter must be an instance of PMUI.ui.Menu or null.');
|
||
}
|
||
this.parent = parent;
|
||
return this;
|
||
};
|
||
|
||
MenuItem.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
|
||
MenuItem.prototype.getRootMenu = function () {
|
||
var parent = this.parent;
|
||
|
||
if (this.parent) {
|
||
return this.parent.getRootMenu();
|
||
}
|
||
return parent;
|
||
};
|
||
|
||
MenuItem.prototype.isLeaf = function () {
|
||
throw new Error("isLeaf() is being called from an abstract class.");
|
||
};
|
||
|
||
MenuItem.prototype.getMenu = function () {
|
||
return this.parent;
|
||
};
|
||
|
||
MenuItem.prototype.setContextMenu = function () {
|
||
return this;
|
||
};
|
||
|
||
MenuItem.prototype.getMenuTargetElement = function () {
|
||
var rootMenu = this.getRootMenu();
|
||
|
||
if (rootMenu) {
|
||
return rootMenu.getTargetElement();
|
||
}
|
||
return rootMenu
|
||
};
|
||
|
||
MenuItem.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
MenuItem.superclass.prototype.createHTML.call(this);
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.menu.MenuItem', MenuItem);
|
||
|
||
}());
|
||
(function () {
|
||
var MenuOption = function (settings) {
|
||
MenuOption.superclass.call(this, settings);
|
||
this.onClick = null;
|
||
this.text = null;
|
||
this.hideOnClick = null;
|
||
this.disabled = null;
|
||
MenuOption.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.menu.MenuItem', MenuOption);
|
||
|
||
MenuOption.prototype.type = 'MenuOption';
|
||
|
||
MenuOption.prototype.init = function (settings) {
|
||
var defaults = {
|
||
onClick: null,
|
||
elementTag: 'li',
|
||
text: '[option]',
|
||
hideOnClick: true,
|
||
disabled: false
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
this.setElementTag(defaults.elementTag)
|
||
.setText(defaults.text)
|
||
.setOnClickHandler(defaults.onClick)
|
||
.hideOnClick = !!defaults.hideOnClick;
|
||
|
||
if (defaults.disabled) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
};
|
||
|
||
MenuOption.prototype.enable = function () {
|
||
this.disabled = false;
|
||
this.style.removeClasses(['pmui-disabled']);
|
||
return this;
|
||
};
|
||
|
||
MenuOption.prototype.disable = function () {
|
||
this.disabled = true;
|
||
this.style.addClasses(['pmui-disabled']);
|
||
return this;
|
||
};
|
||
|
||
MenuOption.prototype.setText = function (text) {
|
||
if (typeof text !== 'string') {
|
||
throw new Error('setText(): the parameter must be a srting.');
|
||
}
|
||
this.text = text;
|
||
if (this.dom.textContainer) {
|
||
this.dom.textContainer.textContent = text;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
MenuOption.prototype.setOnClickHandler = function (onClick) {
|
||
if (!(onClick === null || typeof onClick === 'function')) {
|
||
throw new Error('setOnClickHandler(): The parameter must be a function or null.');
|
||
}
|
||
this.onClick = onClick;
|
||
return this;
|
||
};
|
||
|
||
MenuOption.prototype.onClickHandler = function () {
|
||
var that = this;
|
||
|
||
return function (e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
if (!that.disabled) {
|
||
if (typeof that.onClick === 'function') {
|
||
that.onClick(that);
|
||
}
|
||
if (that.hideOnClick) {
|
||
that.parent.hide();
|
||
}
|
||
}
|
||
};
|
||
};
|
||
|
||
MenuOption.prototype.remove = function () {
|
||
this.parent.removeItem(this);
|
||
return this;
|
||
};
|
||
|
||
MenuOption.prototype.defineEventListeners = function () {
|
||
this.removeEvents();
|
||
this.addEvent('click').listen(this.dom.title, this.onClickHandler());
|
||
return this;
|
||
};
|
||
|
||
MenuOption.prototype.createHTML = function () {
|
||
var link,
|
||
textContainer,
|
||
iconContainer;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
MenuOption.superclass.prototype.createHTML.call(this);
|
||
|
||
link = PMUI.createHTMLElement('a');
|
||
link.href = '#';
|
||
link.className = 'pmui-menuoption-title';
|
||
|
||
textContainer = PMUI.createHTMLElement('span');
|
||
textContainer.className = 'pmui-menuoption-text';
|
||
|
||
iconContainer = PMUI.createHTMLElement('i');
|
||
iconContainer.className = 'pmui-menuoption-text-icon';
|
||
|
||
this.dom.title = link;
|
||
this.dom.textContainer = textContainer;
|
||
this.dom.iconContainer = iconContainer;
|
||
|
||
link.appendChild(iconContainer);
|
||
link.appendChild(textContainer);
|
||
this.html.appendChild(link);
|
||
|
||
this.setText(this.text);
|
||
|
||
this.defineEventListeners();
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.menu.MenuOption', MenuOption);
|
||
}());
|
||
(function () {
|
||
var MenuRegularOption = function (settings) {
|
||
MenuRegularOption.superclass.call(this, settings);
|
||
this.childMenu = null;
|
||
MenuRegularOption.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.menu.MenuOption', MenuRegularOption);
|
||
|
||
MenuRegularOption.prototype.init = function (settings) {
|
||
var defaults = {
|
||
items: []
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.childMenu = new PMUI.menu.Menu({
|
||
positionMode: 'absolute',
|
||
parent: this
|
||
});
|
||
|
||
this.setItems(defaults.items);
|
||
};
|
||
|
||
MenuRegularOption.prototype.setItems = function (items) {
|
||
this.childMenu.setItems(items);
|
||
if (this.childMenu.getItems().length) {
|
||
this.style.addClasses(['pmui-father']);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
MenuRegularOption.prototype.getItems = function () {
|
||
return this.childMenu.getItems();
|
||
};
|
||
|
||
MenuRegularOption.prototype.onClickHandler = function () {
|
||
var that = this;
|
||
return function (e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
if (!that.disabled) {
|
||
if (typeof that.onClick === 'function') {
|
||
that.onClick(that);
|
||
}
|
||
if (that.hideOnClick && that.childMenu.getItems().length === 0) {
|
||
that.parent.hide();
|
||
}
|
||
}
|
||
};
|
||
};
|
||
|
||
MenuRegularOption.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
MenuRegularOption.superclass.prototype.createHTML.call(this);
|
||
this.html.appendChild(this.childMenu.getHTML());
|
||
this.setItems(this.getItems());
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.menu.MenuRegularOption', MenuRegularOption);
|
||
}());
|
||
(function () {
|
||
var MenuSeparatorItem = function (settings) {
|
||
MenuSeparatorItem.superclass.call(this, jQuery.extend(true, settings, {
|
||
elementTag: 'div'
|
||
}));
|
||
MenuSeparatorItem.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.menu.MenuItem', MenuSeparatorItem);
|
||
|
||
MenuSeparatorItem.prototype.type = 'MenuSeparatorItem';
|
||
|
||
MenuSeparatorItem.prototype.isLeaf = function () {
|
||
return true;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.menu.MenuSeparatorItem', MenuSeparatorItem);
|
||
}());
|
||
(function () {
|
||
var MenuItemFactory = function (settings) {
|
||
MenuItemFactory.superclass.call(this, settings);
|
||
MenuItemFactory.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.util.Factory', MenuItemFactory);
|
||
|
||
MenuItemFactory.prototype.type = "MenuItemFactory";
|
||
|
||
MenuItemFactory.prototype.init = function (settings) {
|
||
var defaults = {
|
||
products: {
|
||
"menuRegularOption": PMUI.menu.MenuRegularOption,
|
||
"menuSeparatorItem": PMUI.menu.MenuSeparatorItem
|
||
},
|
||
defaultProduct: "menuRegularOption"
|
||
};
|
||
|
||
this.setDefaultProduct(defaults.defaultProduct)
|
||
.setProducts(defaults.products);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.menu.MenuItemFactory', MenuItemFactory);
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.form.Field
|
||
* Abstract class that encapsulates the field behavior
|
||
* @extends PMUI.core.Element
|
||
* @abstract
|
||
*
|
||
* @constructor
|
||
* While it is true that this class must not be instantiated,
|
||
* it is useful to mention the settings parameter for the constructor function
|
||
* (which will be used for the non abstract subclasses).
|
||
* @param {Object} [settings] A JSON object, it can be contain the following fields:
|
||
*
|
||
* - {@link PMUI.form.Field#cfg-name name}.
|
||
* - {@link PMUI.form.Field#cfg-label label}.
|
||
* - {@link PMUI.form.Field#cfg-value value}.
|
||
* - {@link PMUI.form.Field#cfg-helper helper}.
|
||
* - {@link PMUI.form.Field#cfg-showHelper showHelper}.
|
||
* - {@link PMUI.form.Field#cfg-validators validators}.
|
||
* - {@link PMUI.form.Field#cfg-valueType valueType}.
|
||
* - {@link PMUI.form.Field#cfg-controlPositioning controlPositioning}.
|
||
* - {@link PMUI.form.Field#cfg-labelWidth labelWidth}.
|
||
* - {@link PMUI.form.Field#cfg-showColon showColon}
|
||
*
|
||
* @cfg {String} name The name for the field.
|
||
* @cfg {String} label The text to be shown as the field's label
|
||
* @cfg {String} value The initial value to be set to the control.
|
||
* @cfg {String} helper The helper text to be shown in the helper tooltip
|
||
* @cfg {Boolean} showHelper A boolean value which determines if the helper tootltip will be shown or not.
|
||
* @cfg {Object} validators An array where each array's item is a JSON object (with the validator setting data)
|
||
* or a {@link PMUI.form.Validator Validator} object.
|
||
* {
|
||
* validators: [
|
||
* {
|
||
* type: "maxlength",
|
||
* criteria: 5
|
||
* },
|
||
* new LengthValidator({
|
||
* min: 0,
|
||
* max: 5
|
||
* })
|
||
* ]
|
||
* }
|
||
* In example above, "validators" is an array in which their first element is an JSON object
|
||
* and the second one is a {@link PMUI.form.Validator Validator} object.
|
||
* @cfg {String} valueType A string which specifies the data type for the Field value.
|
||
* @cfg {String} controlPositioning A formatted string that specifies the order output for the control(s).
|
||
* A string which specifies the output order for the field's controls.
|
||
* Basically this string uses a wildcard with the format "[cx]", each one is replaced by the control:
|
||
* "[c0]-[c1]-[c2]"
|
||
* If you apply the string above to the controlPositioning property, it will render
|
||
* the first three field's controls, each one separated from the other by a "-".
|
||
*
|
||
* Another wildcard is [c*], this represents all the controls or the ones that haven't been included yet:
|
||
* "[c*]-"
|
||
* The example above will render all the controls and at the end it will add a "-".
|
||
*
|
||
* "[c2]-[c*]"
|
||
* The example above will render first the second control and then the other ones (starting from the first one).
|
||
* @cfg {String} labelWidth The width for the label.
|
||
* The width label should be a String with the following format "X%"
|
||
*
|
||
* Note that this% should not exceed 80%, because 20% is the tooltip
|
||
* @cfg {Boolean} showColon If a colon is shown after the label text.
|
||
* @cfg {Boolean} [labelVisible=true] If the label is visible or not.
|
||
* @cfg {String} [labelPosition="left"] Sets the position for the label, the value can take one of the following
|
||
* options:
|
||
*
|
||
* - "left" (default).
|
||
* - "right".
|
||
* - "top".
|
||
* - "bottom"
|
||
*
|
||
* @cfg {String|Number|Array} [controlsWidth] Determines the width for the field's controls, but the width of the
|
||
* field must be a number or a string with the format "#px", otherwise the width for the controls will be set to
|
||
* "auto".It can be:
|
||
*
|
||
* - A String, in this case the string must have the following format "##px", otherwise must be "auto".
|
||
* - A Number, in this case the value received is parsed into a px units value.
|
||
* - An Array in which each element can be a String or a Number (following the rules above).
|
||
*
|
||
* This will be applied respectively to each control in the field.
|
||
* @cfg {Function} [onClick=null] Description here.
|
||
* @cfg {Function|null} [onBeforeChange] The callback function to be executed before the field's value changes. To
|
||
* avoid the change the callback function must return false. For info about the parameters sent to the calback
|
||
* function please read the {@link #event-onBeforeChange onBeforeChange event} documentation.
|
||
*/
|
||
var Field = function (settings) {
|
||
Field.superclass.call(this, settings);
|
||
/**
|
||
* @property {String} [name=[The object's id]] The field's name.
|
||
* @readonly
|
||
*/
|
||
this.name = null;
|
||
/**
|
||
* @property {String} [label = "[field]"] The field's label text.
|
||
* @readonly
|
||
*/
|
||
this.label = null;
|
||
/**
|
||
* @property {String} [value=""] The field's value.
|
||
* @readonly
|
||
*/
|
||
this.value = null;
|
||
/**
|
||
* @property {PMUI.ui.TooltipMessage} [helper] The field's help tooltip
|
||
* @readonly
|
||
*/
|
||
this.helper = null;
|
||
/**
|
||
* @property {PMUI.ui.TooltipMessage} [message] A {@link PMUI.ui.TooltipMessage TooltipMessage}
|
||
* object to show a message related to the field (i.e. validation error messages)
|
||
* @private
|
||
*/
|
||
this.message = null;
|
||
/**
|
||
* @property {Array} controls An array, it will contain all the necessary Control objects
|
||
* @private
|
||
*/
|
||
this.controls = [];
|
||
/**
|
||
* @property {Object} validators An JSON object which will contain all the
|
||
* {@link PMUI.form.Validator Validators} object.
|
||
* @private
|
||
*/
|
||
this.validators = {};
|
||
/**
|
||
* @property {String} [controlPositioning="[c*]"] A formatted string that specifies
|
||
* the order output for the field's controls.
|
||
* @readonly
|
||
*/
|
||
this.controlPositioning = null;
|
||
/**
|
||
* @property {Object} [dom] A JSON object which will contain important DOM object
|
||
* for the Field object.
|
||
* @private
|
||
*/
|
||
this.dom = null;
|
||
/**
|
||
* @property {Boolean} [helperIsVisible=false] A Boolean that let us
|
||
* know if the help tooltip will be shown or not.
|
||
* @readonly
|
||
*/
|
||
this.helperIsVisible = null;
|
||
/**
|
||
* @property {String} [labelWidth="30%"]
|
||
* The width for the label. This property should be a String with the following format "X%"
|
||
* @readonly
|
||
*/
|
||
this.labelWidth = null;
|
||
/**
|
||
* @property {Boolean} [visibleColon=true]
|
||
* If a colon is shown after the label text.
|
||
* @readonly
|
||
*/
|
||
this.visibleColon = null;
|
||
/**
|
||
* @property {Boolean} labelVisible
|
||
* If the label is visible or not.
|
||
* @readonly
|
||
*/
|
||
this.labelVisible = null;
|
||
/**
|
||
* @property {String} [labelPosition="String"] The position for the field's label.
|
||
* @readonly
|
||
*/
|
||
this.labelPosition = null;
|
||
/**
|
||
* @event onBeforeChange
|
||
* Fired before the field's value changes.
|
||
* @param {String} newValue The new value to be set.
|
||
* @param {String} oldValue The old field's value.
|
||
*/
|
||
this.onBeforeChange = null;
|
||
/**
|
||
* @event onChange
|
||
* Fired when the field's value changes.
|
||
* @param {String} newValue The field's new value.
|
||
* @param {String} oldValue The previous field's value.
|
||
*/
|
||
this.onChange = null;
|
||
/**
|
||
* @property {String} valueType The value data type for the field.
|
||
*/
|
||
this.valueType = null;
|
||
/**
|
||
* @property {PMUI.form.ValidatorFactory} validatorFactory The factory object for validator production.
|
||
*/
|
||
this.validatorFactory = null;
|
||
/**
|
||
* @property {Boolean} [required] If the field is required or not
|
||
*/
|
||
this.required = null;
|
||
/**
|
||
* @property {String} [requiredMessage="This field is required."]
|
||
* The message to display when the validation for required property fails.
|
||
*/
|
||
this.requiredMessage = null;
|
||
/**
|
||
* @property {Boolean} [validAtChange=true]
|
||
* If the validation must be executed every time the field's value changes.
|
||
*/
|
||
this.validAtChange = null;
|
||
/**
|
||
* The width for the control(s)
|
||
* @type {Number|String|Array}
|
||
* @readonly
|
||
*/
|
||
this.controlsWidth = [];
|
||
/**
|
||
* @property {Number|String} controlsContainerWidth
|
||
* @type {Number|String}
|
||
*/
|
||
this.controlsContainerWidth = null;
|
||
/**
|
||
* @property {PMUI.form.Form} form
|
||
* The form the field belongs to.
|
||
*/
|
||
this.form = null;
|
||
/**
|
||
* @property {Boolean} eventsDefined
|
||
* If the events for the object have been defined.
|
||
*/
|
||
this.eventsDefined = null;
|
||
/**
|
||
* @property {PMUI.data.DataSet} data
|
||
* The field's data object.
|
||
* @private
|
||
*/
|
||
this.data = null;
|
||
/**
|
||
* The initial value the field will be set when its reset() method is called.
|
||
* @type {String}
|
||
* @private
|
||
*/
|
||
this.initialValue = null;
|
||
/**
|
||
* [onClick description]
|
||
* @type {[type]}
|
||
*/
|
||
this.onClick = null;
|
||
/**
|
||
* If the field is disabled or not. Notice that if it is disabled the validation won't be executed.
|
||
* @type {Boolean}
|
||
*/
|
||
this.disabled = null;
|
||
|
||
/**
|
||
* @protected
|
||
* Valid Types
|
||
* @type {Array}
|
||
*/
|
||
this.dependentFields = [];
|
||
this.dependencyHandler = null;
|
||
|
||
this.validTypes = {
|
||
'string': true,
|
||
'number': true,
|
||
'boolean': true,
|
||
'date': true,
|
||
'object': true,
|
||
'integer': true,
|
||
'float': true
|
||
};
|
||
Field.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', Field);
|
||
|
||
Field.prototype.type = "Field";
|
||
|
||
Field.prototype.init = function (settings) {
|
||
var defaults = {
|
||
name: this.id,
|
||
label: '[field]',
|
||
value: '',
|
||
helper: '',
|
||
showHelper: !!(settings && settings.helper),
|
||
validators: [],
|
||
valueType: 'string',
|
||
controlPositioning: '[c*]',
|
||
labelWidth: '23.5%',
|
||
width: '100%',
|
||
showColon: true,
|
||
validatorFactory: new PMUI.form.ValidatorFactory(),
|
||
onBeforeChange: null,
|
||
onChange: null,
|
||
required: false,
|
||
validAtChange: true,
|
||
requiredMessage: 'This field is required.'.translate(),
|
||
labelVisible: true,
|
||
labelPosition: 'left',
|
||
form: null,
|
||
controlsWidth: "auto",
|
||
controlsContainerWidth: "70%",
|
||
disabled: false,
|
||
dependentFields: [],
|
||
dependencyHandler: function () {
|
||
},
|
||
onClick: null
|
||
};
|
||
|
||
this.dependentFields = [];
|
||
this.dependencyFields = new PMUI.util.ArrayList();
|
||
$.extend(true, defaults, settings);
|
||
|
||
this.initialValue = defaults.value;
|
||
|
||
this.helper = new PMUI.ui.TooltipMessage({
|
||
category: 'help'
|
||
});
|
||
|
||
this.dom = {};
|
||
this.data = new PMUI.data.DataField();
|
||
|
||
this.message = new PMUI.ui.TextLabel({
|
||
text: 'This field is required.'.translate(),
|
||
displayMode: 'block',
|
||
mode: 'normal',
|
||
visible: false
|
||
});
|
||
|
||
this.setForm(defaults.form)
|
||
.setValidAtChange(defaults.validAtChange)
|
||
.setRequired(defaults.required)
|
||
.setRequiredMessage(defaults.requiredMessage)
|
||
.setValidatorFactory(defaults.validatorFactory)
|
||
.setValidators(defaults.validators)
|
||
.setName(defaults.name)
|
||
.setLabel(defaults.label)
|
||
.setValue(defaults.value)
|
||
.setHelper(defaults.helper)
|
||
.setValueType(defaults.valueType)
|
||
.setControlPositioning(defaults.controlPositioning)
|
||
.setOnBeforeChangeHandler(defaults.onBeforeChange)
|
||
.setOnChangeHandler(defaults.onChange)
|
||
.setWidth(defaults.width)
|
||
.setLabelWidth(defaults.labelWidth)
|
||
.setLabelPosition(defaults.labelPosition)
|
||
.setControlsWidth(defaults.controlsWidth)
|
||
.setControlsContainerWidth(defaults.controlsContainerWidth)
|
||
.setOnClickHandler(defaults.onClick)
|
||
.setControls();
|
||
this.setDependencyHandler(defaults.dependencyHandler);
|
||
this.setDependentFields(defaults.dependentFields);
|
||
|
||
if (defaults.showHelper) {
|
||
this.showHelper();
|
||
} else {
|
||
this.hideHelper();
|
||
}
|
||
if (defaults.showColon) {
|
||
this.showColon();
|
||
} else {
|
||
this.hideColon();
|
||
}
|
||
if (defaults.labelVisible) {
|
||
this.showLabel();
|
||
} else {
|
||
this.hideLabel();
|
||
}
|
||
if (defaults.disabled) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
};
|
||
Field.prototype.onBeforeChangeHandler = function (handler) {
|
||
var that = this;
|
||
return function (newValue, oldValue) {
|
||
var callbackResponse,
|
||
futureValue = "",
|
||
i;
|
||
|
||
if (typeof that.onBeforeChange === 'function') {
|
||
for (i = 0; i < that.controls.length; i += 1) {
|
||
if (that.controls[i] === this) {
|
||
futureValue += ' ' + newValue;
|
||
} else {
|
||
futureValue += ' ' + that.controls[i].getValue();
|
||
}
|
||
}
|
||
futureValue = futureValue.substr(1);
|
||
callbackResponse = that.onBeforeChange(futureValue, that.getValue());
|
||
}
|
||
return callbackResponse;
|
||
};
|
||
};
|
||
Field.prototype.setOnBeforeChangeHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnBeforeChangeHandler(): The parameter must be a function or null.");
|
||
}
|
||
this.onBeforeChange = handler;
|
||
return this;
|
||
};
|
||
Field.prototype.setOnClickHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnClickHandler(): The parameter must be a function or null.");
|
||
}
|
||
this.onClick = handler;
|
||
return this;
|
||
};
|
||
Field.prototype.setDependentFields = function (dependentFields) {
|
||
if (!jQuery.isArray(dependentFields)) {
|
||
throw new Error("setDependentFields(): The parameter must be an array.");
|
||
}
|
||
this.dependentFields = dependentFields;
|
||
if (this.form) {
|
||
this.form.updateDependencies();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Field.prototype.removeDependentField = function (FieldName) {
|
||
var i;
|
||
|
||
for (i = 0; this.dependentFields.length; i += 1) {
|
||
if (this.dependentFields[i] === FieldName) {
|
||
this.dependentFields.splice(i, 1);
|
||
i--;
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Field.prototype.setDependencyHandler = function (handler) {
|
||
if (typeof handler == 'function' || handler == null) {
|
||
this.dependencyHandler = handler;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Disables the field. Notice that when a field is disabled it is not validated and it is not returned when its
|
||
* form's getData() method is invoked.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.disable = function () {
|
||
var i;
|
||
|
||
this.disabled = true;
|
||
this.style.addClasses(["pmui-disabled"]);
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
this.controls[i].disable(true);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Enables the field.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.enable = function () {
|
||
var i;
|
||
|
||
this.disabled = false;
|
||
this.style.removeClasses(["pmui-disabled"]);
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
this.controls[i].disable(false);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Resets the field to its original value.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.reset = function () {
|
||
this.setValue(this.initialValue);
|
||
this.hideMessage();
|
||
if (this.eventsDefined) {
|
||
this.onChangeHandler();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Determines the width for the field's controls, but the width of the field must be a number or a string with
|
||
* the format "#px", otherwise the width for the controls will be set to "auto".
|
||
* @param {Number|String|Array} width It can be:
|
||
*
|
||
* - A String, in this case the string must have the following format "##px", otherwise must be "auto".
|
||
* - A Number, in this case the value received is parsed into a px units value.
|
||
* - An Array in which each element can be a String or a Number (following the rules above).
|
||
*
|
||
* This will be applied respectively to each control in the field.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setControlsWidth = function (width) {
|
||
var i,
|
||
labelWidthPx,
|
||
auxWidth,
|
||
autoGerateWidthForControls = false,
|
||
fieldWidthIsAbsolute = false;
|
||
|
||
if (!(width === 'auto' || typeof width === 'number' || jQuery.isArray(width) || /^\d+(\.\d+)?px/.test(width))) {
|
||
throw new Error("setControlsWidth(): The parameter must be a string \"auto\", or a number or an array.");
|
||
}
|
||
|
||
this.controlsWidth = width;
|
||
|
||
if (width === 'auto') {
|
||
autoGerateWidthForControls = true;
|
||
}
|
||
|
||
if (typeof this.width === 'number' || /^\d+(\.\d+)?px/.test(this.width)) {
|
||
fieldWidthIsAbsolute = true;
|
||
}
|
||
|
||
if (!autoGerateWidthForControls) {
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (jQuery.isArray(width)) {
|
||
this.controls[i].setWidth(width[i] || "auto");
|
||
} else {
|
||
this.controls[i].setWidth(width);
|
||
}
|
||
}
|
||
} else if (fieldWidthIsAbsolute) {
|
||
auxWidth = parseInt(this.width, 10);
|
||
labelWidthPx = auxWidth * (parseInt(this.labelWidth, 10) / 100) + 4;
|
||
labelWidthPx = auxWidth - 83 - labelWidthPx;
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
this.controls[i].setWidth(labelWidthPx);
|
||
}
|
||
} else {
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
this.controls[i].setWidth("auto");
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the width for the controls container.
|
||
* @param width
|
||
*/
|
||
Field.prototype.setControlsContainerWidth = function (width) {
|
||
if (!(typeof width === 'number' || jQuery.isArray(width) || /^\d+(\.\d+)?(px|\%)/.test(width))) {
|
||
throw new Error("setControlsContainerWidth(): The parameter must be a string (with a numeric or percentage value), or a number or an array.");
|
||
}
|
||
this.controlsContainerWidth = width;
|
||
if (this.dom && this.dom.controlContainer) {
|
||
$(this.dom.controlContainer).css('width', width);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the form the field belongs to.
|
||
* @param {PMUI.form.Form} form
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setForm = function (form) {
|
||
if (form instanceof PMUI.form.Form) {
|
||
this.form = form;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Turns on/off the validation when the field's value changes.
|
||
* @param {Boolean} validAtChange
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setValidAtChange = function (validAtChange) {
|
||
this.validAtChange = !!validAtChange;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the position for the label.
|
||
* @param {String} position It can take one of the following values: "top", "right", "bottom", "left".
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setLabelPosition = function (position) {
|
||
if (position === 'top' || position === 'right' || position === 'bottom' || position === 'left') {
|
||
this.labelPosition = position;
|
||
if (this.html) {
|
||
if (position === 'top' || position === 'left') {
|
||
this.html.insertBefore(this.dom.labelTextContainer, this.dom.controlContainer);
|
||
this.dom.labelTextContainer.style.display = position === 'top' ? 'block' : 'inline-block';
|
||
$(this.dom.controlContainer).css("float", '');
|
||
} else {
|
||
this.html.insertBefore(this.dom.controlContainer, this.dom.labelTextContainer);
|
||
this.dom.labelTextContainer.style.display = position === 'bottom' ? 'block' : 'inline-block';
|
||
$(this.dom.labelTextContainer).css("float", '');
|
||
}
|
||
}
|
||
} else {
|
||
throw new Error('setLabelPosition(): it only accepts "top", "rigth", "left" or "bottom" as value for ' +
|
||
'the parameter');
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the factory which must be produce {@link PMUI.form.Validator Validator} objects.
|
||
* @param {PMUI.util.Factory|Object} factory
|
||
* It can be a:
|
||
*
|
||
* - a {@link PMUI.util.Factory} object
|
||
* - a JSON object: in this case a new {@link PMUI.form.ValidatorFactory ValidatorFactory} will be created
|
||
* using the JSON object as the constructor parameter.
|
||
* @private
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setValidatorFactory = function (factory) {
|
||
if (factory instanceof PMUI.util.Factory) {
|
||
this.validatorFactory = factory;
|
||
} else {
|
||
this.validatorFactory = new PMUI.form.ValidatorFactory(factory);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the message to show when the required field validation fails.
|
||
* @param {String} requiredMessage
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setRequiredMessage = function (requiredMessage) {
|
||
if (typeof requiredMessage === 'string') {
|
||
this.requiredMessage = requiredMessage;
|
||
} else {
|
||
throw new Error("the setRequiredMessage() method only accepts string values.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets if the fields is required or not.
|
||
* @param {Boolean} required
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setRequired = function (required) {
|
||
this.required = !!required;
|
||
if (this.dom.fieldRequired) {
|
||
if (this.required) {
|
||
this.showRequired();
|
||
} else {
|
||
this.hideRequired();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Field.prototype.hideRequired = function () {
|
||
this.dom.fieldRequired.style.display = 'none';
|
||
return this;
|
||
};
|
||
|
||
Field.prototype.showRequired = function () {
|
||
this.dom.fieldRequired.style.display = 'inline-block';
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes all the validators from the field.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.clearValidators = function () {
|
||
var key;
|
||
|
||
for (key in this.validators) {
|
||
if (this.validators.hasOwnProperty(key)) {
|
||
this.validators[key] = null;
|
||
delete this.validators[key];
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a validator to the field.
|
||
* @param {String|PMUI.form.Validator|Object} validator
|
||
* It can be:
|
||
*
|
||
* - a String: it must be on of the supported pmTypes by the
|
||
* {@link PMUI.form.ValidatorFactory ValidatorFactory} class.
|
||
* - a {@link PMUI.form.Validator Validator} object.
|
||
* - a JSON object: in this case the JSON structure must be the same as the needed one to create
|
||
* the desired validator, additionally must have the respective pmType.
|
||
*
|
||
* Note. All the supported pmTypes are specified in the
|
||
* {@link PMUI.form.ValidatorFactory ValidatorFactory documentation}.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.addValidator = function (validator) {
|
||
var newValidator;
|
||
|
||
if (this.validatorFactory) {
|
||
if (this.validatorFactory.isValidClass(validator) || this.validatorFactory.isValidName(validator.pmType)) {
|
||
newValidator = this.validatorFactory.make(validator);
|
||
} else {
|
||
throw new Error('Invalid validator to add.');
|
||
}
|
||
}
|
||
|
||
if (newValidator && newValidator instanceof PMUI.form.Validator) {
|
||
newValidator.setParent(this);
|
||
this.validators[newValidator.type] = newValidator;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the validators for the field.
|
||
* @param {Array} validators An array in which each element can be one of the accepted types in the
|
||
* {@link PMUI.form.Field#addValidator addValidator() method}.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setValidators = function (validators) {
|
||
var i = 0;
|
||
|
||
if (jQuery.isArray(validators)) {
|
||
this.clearValidators();
|
||
for (i = 0; i < validators.length; i += 1) {
|
||
this.addValidator(validators[i]);
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows a colon after the label text.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.showColon = function () {
|
||
this.visibleColon = true;
|
||
if (this.dom.fieldColon) {
|
||
this.dom.fieldColon.style.display = '';
|
||
}
|
||
};
|
||
/**
|
||
* Hides the colon after the label text.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.hideColon = function () {
|
||
this.visibleColon = false;
|
||
if (this.dom.fieldColon) {
|
||
this.dom.fieldColon.style.display = "none";
|
||
}
|
||
return this;
|
||
}
|
||
/**
|
||
* Sets the width for the label.
|
||
* @param {String} width It can be a Number or a String.
|
||
* This parameter should be a String with the following format "X%";
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setLabelWidth = function (width) {
|
||
if (/^\d+(\.\d+)?(px|em|%)$/.test(width)) {
|
||
this.labelWidth = width;
|
||
this.setControlsWidth(this.controlsWidth);
|
||
} else {
|
||
throw new Error('setLabelWidth(): invalid "width" parameter');
|
||
}
|
||
if (this.dom.labelTextContainer) {
|
||
this.dom.labelTextContainer.style.width = this.labelWidth;
|
||
if (this.labelVisible && this.labelPosition != "top")
|
||
$(this.dom.messageContainer).css({"margin-left": parseInt(this.labelWidth) + 1 + "%"});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback function to be called when the field's value changes.
|
||
* @param {Function} handler
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setOnChangeHandler = function (handler) {
|
||
if (typeof handler === 'function') {
|
||
this.onChange = handler;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the helper tooltip visible.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.showHelper = function () {
|
||
this.helperIsVisible = true;
|
||
this.helper.setVisible(true);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the helper tooltip non visible.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.hideHelper = function () {
|
||
this.helperIsVisible = false;
|
||
this.helper.setVisible(false);
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns an array with all the field's controls.
|
||
* @return {Array}
|
||
*/
|
||
Field.prototype.getControls = function () {
|
||
return this.controls;
|
||
};
|
||
/**
|
||
* Returns an index based field's control.
|
||
* @param {Number} index An integer value.
|
||
* @return {PMUI.control.Control}
|
||
*/
|
||
Field.prototype.getControl = function (index) {
|
||
index = index || 0;
|
||
return this.controls[index];
|
||
};
|
||
/**
|
||
* Sets the controlPositioning property.
|
||
* @param {String} positioning The string must have the same format that the
|
||
* {@link PMUI.form.Field#cfg-controlPositioning controlPositioning} config option.
|
||
*/
|
||
Field.prototype.setControlPositioning = function (positioning) {
|
||
var pos,
|
||
controlPos,
|
||
i,
|
||
j,
|
||
k,
|
||
controls,
|
||
span,
|
||
addControl,
|
||
that = this;
|
||
|
||
if (typeof positioning === 'string') {
|
||
this.controlPositioning = positioning;
|
||
if (this.html && this.controls.length) {
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
jQuery(this.controls[i].getHTML()).detach();
|
||
}
|
||
$(this.dom.controlContainer).empty();
|
||
if (positioning !== "") {
|
||
controls = this.controls.slice();
|
||
pos = positioning.split(/\[c[\d|\*]\]/);
|
||
controlPos = positioning.match(/\[c[\d|\*]\]/g);
|
||
addControl = function (c) {
|
||
var k;
|
||
if (c === '[c*]') {
|
||
for (k = 0; k < controls.length; k += 1) {
|
||
if (controls[k] !== null) {
|
||
that.dom.controlContainer.appendChild(controls[k].getHTML());
|
||
controls[k] = null;
|
||
}
|
||
}
|
||
} else {
|
||
k = c.match(/\d+/);
|
||
k = parseInt(k[0], 10);
|
||
if (controls[k] !== null) {
|
||
that.dom.controlContainer.appendChild(controls[k].getHTML());
|
||
controls[k] = null;
|
||
}
|
||
}
|
||
};
|
||
|
||
j = 0;
|
||
for (i = 0; i < pos.length; i += 1) {
|
||
if (pos[i] === "" && j < controlPos.length) {
|
||
addControl(controlPos[j]);
|
||
j++;
|
||
} else {
|
||
span = PMUI.createHTMLElement('span');
|
||
span.textContent = pos[i];
|
||
this.dom.controlContainer.appendChild(span);
|
||
}
|
||
if (j < controlPos.length) {
|
||
addControl(controlPos[j]);
|
||
j++;
|
||
}
|
||
}
|
||
this.dom.labelTextContainer.setAttribute('for', this.controls[0].id);
|
||
this.dom.controlContainer.appendChild(this.helper.getHTML());
|
||
}
|
||
}
|
||
} else {
|
||
throw new Error("The setControlPositioning() method only accepts string values.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the controls for the field.
|
||
*
|
||
* Since this is an abstract method, it must be implemented in its non-abstract subclasses
|
||
* @abstract
|
||
* @private
|
||
*/
|
||
Field.prototype.setControls = function () {
|
||
};
|
||
/**
|
||
* Sets the name for the Field
|
||
* @param {String} name
|
||
*/
|
||
Field.prototype.setName = function (name) {
|
||
if (typeof name === 'string') {
|
||
this.name = name;
|
||
this.data.setKey(name);
|
||
} else {
|
||
throw new Error('The setName() method only accepts string values!');
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the field's name
|
||
* @return {String}
|
||
*/
|
||
Field.prototype.getName = function () {
|
||
return this.name;
|
||
};
|
||
/**
|
||
* Sets the text for the field's label.
|
||
* @param {String} label
|
||
*/
|
||
Field.prototype.setLabel = function (label) {
|
||
if (typeof label === 'string') {
|
||
this.label = label;
|
||
} else {
|
||
throw new Error("The setLabel() method only accepts string values!");
|
||
}
|
||
if (this.dom.fieldTextLabel) {
|
||
this.dom.fieldTextLabel.textContent = this.label;
|
||
}
|
||
if (this.dom.fieldRequired) {
|
||
this.dom.fieldRequired.textContent = '*';
|
||
this.setRequired(this.required);
|
||
}
|
||
if (this.dom.fieldColon) {
|
||
this.dom.fieldColon.textContent = ":";
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the text from the field's label.
|
||
* @return {String}
|
||
*/
|
||
Field.prototype.getLabel = function () {
|
||
return this.label;
|
||
};
|
||
/**
|
||
* Sets the value to the field's controls.
|
||
* @protected
|
||
* @param {String} value
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setValueToControls = function (value) {
|
||
var i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
this.controls[i].setValue(value);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the current value from the field's controls without affect the field's value.
|
||
* @return {String}
|
||
* @private
|
||
*/
|
||
Field.prototype.getValueFromControls = function () {
|
||
var value = '',
|
||
i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
value += ' ' + this.controls[i].getValue();
|
||
}
|
||
|
||
return value.substr(1);
|
||
};
|
||
/**
|
||
* Update the field's value property from the controls
|
||
* @protected
|
||
* @chainable
|
||
*/
|
||
Field.prototype.updateValueFromControls = function () {
|
||
var value = this.getValueFromControls();
|
||
|
||
this.value = value;
|
||
this.data.setValue(value);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the field's value.
|
||
* @param {String} value
|
||
*/
|
||
Field.prototype.setValue = function (value) {
|
||
if (typeof value === 'number') {
|
||
value = value.toString();
|
||
}
|
||
if (typeof value === 'string') {
|
||
this.value = value;
|
||
} else {
|
||
throw new Error("The setValue() method only accepts string values!");
|
||
}
|
||
this.data.setValue(this.value);
|
||
this.setValueToControls(this.value);
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the field's value.
|
||
* @param [format] Defines the return format
|
||
* @returns {*}
|
||
*/
|
||
Field.prototype.getValue = function (format) {
|
||
var castFormat = format || this.valueType;
|
||
return PMUI.castValue(this.value, castFormat);
|
||
};
|
||
/**
|
||
* Sets the helper text.
|
||
* @param {String} helper
|
||
*/
|
||
Field.prototype.setHelper = function (helper) {
|
||
this.helper.setMessage(helper);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows a message below the control.
|
||
* @param {String} message The message
|
||
* @param {String} [category="info"] The message category,
|
||
* It can be one of the accepted values for the
|
||
* {@link PMUI.ui.TooltipMessage#setCategory TooltipMessage's setCategory() method}, it defaults to "info".
|
||
* @chainable
|
||
*/
|
||
Field.prototype.showMessage = function () {
|
||
this.message.setVisible(true)
|
||
return this;
|
||
};
|
||
/**
|
||
* Hides the message below the control.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.hideMessage = function () {
|
||
this.message.setVisible(false);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the value type for the field.
|
||
* @param {String} type
|
||
*/
|
||
Field.prototype.setValueType = function (type) {
|
||
var newType;
|
||
if (typeof type === 'string') {
|
||
newType = this.validTypes[type] ? type : 'object';
|
||
this.valueType = newType;
|
||
this.data.setType(newType);
|
||
} else {
|
||
throw new Error("The setValueType() method only accepts string values!");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the field's value type.
|
||
* @return {String}
|
||
*/
|
||
Field.prototype.getValueType = function () {
|
||
return this.valueType;
|
||
};
|
||
/**
|
||
* The onChange event handler constructor.
|
||
* @private
|
||
* @return {Function} The handler.
|
||
*/
|
||
Field.prototype.onChangeHandler = function () {
|
||
var that = this,
|
||
i,
|
||
dependentFields = this.dependentFields,
|
||
form = this.form;
|
||
|
||
return function () {
|
||
var previousValue = that.value,
|
||
newValue = that.getValueFromControls();
|
||
|
||
if (newValue === previousValue) {
|
||
return this;
|
||
}
|
||
|
||
that.value = newValue;
|
||
that.data.setValue(newValue);
|
||
|
||
if (that.validAtChange) {
|
||
that.isValid();
|
||
}
|
||
|
||
if (typeof that.onChange === 'function') {
|
||
that.onChange(that.getValue(), previousValue);
|
||
}
|
||
if (that.form) {
|
||
(that.form.onChangeHandler())(that, that.value, previousValue);
|
||
//PMUI call a event for dependency [dependencyHandler]
|
||
for (i = 0; i < dependentFields.length; i += 1) {
|
||
dependentField = form.getField(dependentFields[i]);
|
||
if (!dependentField) {
|
||
that.removeDependentField(dependentFields[i]);
|
||
continue;
|
||
}
|
||
dependentField.fireDependencyHandler();
|
||
}
|
||
}
|
||
};
|
||
};
|
||
|
||
Field.prototype.fireDependencyHandler = function () {
|
||
var form = this.form,
|
||
dependsOf,
|
||
obj = {},
|
||
i,
|
||
that = this;
|
||
|
||
if (form) {
|
||
dependsOf = form.dependencies[that.name];
|
||
for (i = 0; i < dependsOf.length; i += 1) {
|
||
obj[dependsOf[i].name] = dependsOf[i];
|
||
}
|
||
if (typeof this.dependencyHandler === 'function') {
|
||
this.dependencyHandler(that, obj);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Attach the event listeners to the HTML element
|
||
* @private
|
||
* @chainable
|
||
*/
|
||
Field.prototype.defineEvents = function () {
|
||
var i,
|
||
that = this;
|
||
|
||
Field.superclass.prototype.defineEvents.call(this);
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
this.controls[i].setOnChangeHandler(this.onChangeHandler())
|
||
.setOnBeforeChangeHandler(this.onBeforeChangeHandler())
|
||
.defineEvents();
|
||
}
|
||
if (this.onClick) {
|
||
this.addEvent('click').listen(this.html, function (e) {
|
||
if (typeof that.onClick === 'function') {
|
||
that.onClick(that);
|
||
}
|
||
});
|
||
this.addEvent('click').listen(this.dom.labelTextContainer, function (e) {
|
||
e.stopPropagation();
|
||
});
|
||
}
|
||
this.eventsDefined = true;
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns true if the label is visible, otherwise returns false.
|
||
* @return {Boolean}
|
||
*/
|
||
Field.prototype.isLabelVisible = function () {
|
||
return this.labelVisible;
|
||
};
|
||
/**
|
||
* Hides the field's label.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.hideLabel = function () {
|
||
jQuery(this.dom.labelTextContainer).css('visibility', 'hidden');
|
||
this.labelVisible = false;
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows the field's label.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.showLabel = function () {
|
||
jQuery(this.dom.labelTextContainer).css('visibility', '');
|
||
this.labelVisible = true;
|
||
return this;
|
||
};
|
||
/**
|
||
* Evaluates the required validation.
|
||
* @return {Boolean} Returns true if the validation passes otherwise returns false.
|
||
*/
|
||
Field.prototype.evalRequired = function () {
|
||
var valid = true;
|
||
if (this.required) {
|
||
if (this.valueType !== 'number') {
|
||
if (this.getValue() === "" || this.getValue() === "[]") {
|
||
valid = false;
|
||
}
|
||
} else {
|
||
if (this.getValue().toString() === 'NaN') {
|
||
valid = false;
|
||
}
|
||
}
|
||
if (valid) {
|
||
this.hideMessage();
|
||
} else {
|
||
this.showMessage();
|
||
}
|
||
}
|
||
return valid;
|
||
};
|
||
/**
|
||
* Executes the validations and returns true if all of them passes, otherwise returns false.
|
||
* @return {Boolean}
|
||
*/
|
||
Field.prototype.isValid = function () {
|
||
var valid = true, validator;
|
||
valid = valid && this.evalRequired();
|
||
if (!valid) {
|
||
this.controls[0].style.addClasses(['error']);
|
||
return valid;
|
||
}
|
||
this.controls[0].style.removeClasses(['error']);
|
||
for (validator in this.validators) {
|
||
if (this.validators.hasOwnProperty(validator)) {
|
||
valid = valid && this.validators[validator].isValid();
|
||
if (!valid) {
|
||
this.message.setText(this.validators[validator].errorMessage);
|
||
return valid;
|
||
}
|
||
}
|
||
}
|
||
return valid;
|
||
};
|
||
/**
|
||
* Create the HTML Element for the Field.
|
||
* @protected
|
||
* @return {HTMLElement}
|
||
*/
|
||
Field.prototype.createHTML = function () {
|
||
var html, label,
|
||
labelTextContainer,
|
||
controlContainer,
|
||
messageContainer,
|
||
fieldColon,
|
||
fieldRequired,
|
||
fieldTextLabel;
|
||
|
||
if (!this.html) {
|
||
this.style.addClasses(['pmui-field']);
|
||
Field.superclass.prototype.createHTML.call(this);
|
||
|
||
|
||
labelTextContainer = PMUI.createHTMLElement("label");
|
||
|
||
// contenedor de todos los labels
|
||
labelTextContainer.className = 'pmui-field-label';
|
||
|
||
//labelText
|
||
fieldTextLabel = PMUI.createHTMLElement('span');
|
||
fieldTextLabel.className = "pmui-field-textLabel";
|
||
//asterisk for required
|
||
fieldRequired = PMUI.createHTMLElement ('span');
|
||
fieldRequired.className = "pmui-field-required";
|
||
//colon
|
||
fieldColon = PMUI.createHTMLElement('span');
|
||
fieldColon.className = "pmui-field-colon";
|
||
|
||
|
||
controlContainer = PMUI.createHTMLElement("span");
|
||
controlContainer.className = 'pmui-field-control';
|
||
messageContainer = PMUI.createHTMLElement("span");
|
||
messageContainer.className = 'pmui-field-message';
|
||
messageContainer.style.display = "block"
|
||
|
||
|
||
//labelTextContainer append tree childs label, * and :
|
||
labelTextContainer.appendChild(fieldTextLabel);
|
||
labelTextContainer.appendChild(fieldRequired);
|
||
labelTextContainer.appendChild(fieldColon);
|
||
|
||
//messageContainer append the helper
|
||
messageContainer.appendChild(this.message.getHTML());
|
||
|
||
//this html append label, control and helper tag
|
||
this.html.appendChild(labelTextContainer);
|
||
this.html.appendChild(controlContainer);
|
||
this.html.appendChild(messageContainer);
|
||
|
||
this.dom.labelTextContainer = labelTextContainer;
|
||
this.dom.fieldTextLabel = fieldTextLabel;
|
||
this.dom.fieldColon = fieldColon;
|
||
this.dom.fieldRequired = fieldRequired;
|
||
this.dom.controlContainer = controlContainer;
|
||
this.dom.messageContainer = messageContainer;
|
||
|
||
this.setControlPositioning(this.controlPositioning);
|
||
this.setLabelWidth(this.labelWidth);
|
||
this.setLabel(this.label);
|
||
this.setValue(this.value);
|
||
this.setLabelPosition(this.labelPosition);
|
||
if (this.labelVisible) {
|
||
this.showLabel();
|
||
} else {
|
||
this.hideLabel();
|
||
}
|
||
if (this.visibleColon) {
|
||
this.showColon();
|
||
} else {
|
||
this.hideColon();
|
||
}
|
||
}
|
||
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Set the width for the field.
|
||
* @param {Number|String} width height it can be a number or a string.
|
||
* In case of using a String you only can use 'auto' or ##px or ##% or ##em when ## is a number.
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setWidth = function (width) {
|
||
Field.superclass.prototype.setWidth.call(this, width);
|
||
if (this.labelWidth) {
|
||
this.setLabelWidth(this.labelWidth);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @method setFocus
|
||
* set the focus on field for to control
|
||
* @param {Number} [index] if the field has more than one control and needs to focus on a specific Control
|
||
* @chainable
|
||
*/
|
||
Field.prototype.setFocus = function (index) {
|
||
var i = index || 0,
|
||
j,
|
||
controls = this.getControls();
|
||
|
||
if (this.controls[i] && this.controls[i].setFocus) {
|
||
this.controls[i].setFocus();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.form.Field', Field);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = Field;
|
||
}
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.field.TextField
|
||
* @extends PMUI.form.Field
|
||
* Class to handle a {@link PMUI.control.TextControl} field.
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var a;
|
||
* $(function() {
|
||
* a = new PMUI.field.TextField({
|
||
* label: "Some Text",
|
||
* placeholder: 'a text here',
|
||
* required: true,
|
||
* helper: "Introduce a text (6 chars. max.)",
|
||
* validators: [
|
||
* {
|
||
* pmType: 'textLength',
|
||
* criteria: {
|
||
* maxLength: 6
|
||
* }
|
||
* }
|
||
* ]
|
||
* });
|
||
* document.body.appendChild(a.getHTML());
|
||
* a.defineEvents();
|
||
* });
|
||
*
|
||
*
|
||
* The code above will generate a required TextField with "Some Text" as label,
|
||
* the control will have a placeholder with the text "a text here".
|
||
* Also the field will contain a helper with the text "Introduce a text (6 chars. max.)"
|
||
* and a validator that will control the maximum length for the text to be entered.
|
||
*
|
||
* @cfg {String} [placeholder=""] The text to show as placeholder for the field's control
|
||
* @cfg {Number} [maxLength=0] An integer that specifies the maximum character length for the text to be entered.
|
||
* 0 means no max length.
|
||
*
|
||
* #Note: This setting doesn't act as a validator, it simply set the max character length
|
||
* for the field's control.
|
||
* @cfg {Boolean} [trimOnBlur=true] A boolean that specifies if the value entered will be trimmed
|
||
* when the field loses focus.
|
||
*/
|
||
var TextField = function (settings) {
|
||
TextField.superclass.call(this, settings);
|
||
/**
|
||
* @property {Boolean} [trimOnBlur=true] If the field's value must be trimmed every time it loses focus.
|
||
*/
|
||
this.trimOnBlur = null;
|
||
TextField.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.form.Field', TextField);
|
||
|
||
TextField.prototype.type = "TextField";
|
||
|
||
TextField.prototype.init = function (settings) {
|
||
var defaults = {
|
||
placeholder: "",
|
||
maxLength: 0,
|
||
trimOnBlur: true,
|
||
readOnly: false
|
||
};
|
||
|
||
$.extend(true, defaults, settings);
|
||
|
||
this.setPlaceholder(defaults.placeholder)
|
||
.setMaxLength(defaults.maxLength)
|
||
.setTrimOnBlur(defaults.trimOnBlur)
|
||
.setReadOnly(defaults.readOnly)
|
||
.setDependentFields(this.dependentFields);
|
||
};
|
||
/**
|
||
* Sets the value for the field.
|
||
* @param {String} value
|
||
* @chainable
|
||
*/
|
||
TextField.prototype.setValue = function (value) {
|
||
if (this.trimOnBlur) {
|
||
value = jQuery.trim(value);
|
||
}
|
||
TextField.superclass.prototype.setValue.call(this, value);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the placeholder for the control. Note that this feature is only supported
|
||
* by browsers which support the "placeholder" for input elements.
|
||
* @param {String} placeholder
|
||
* @chainable
|
||
*/
|
||
TextField.prototype.setReadOnly = function (readonly) {
|
||
this.controls[0].setReadOnly(readonly);
|
||
return this;
|
||
};
|
||
/**
|
||
* [setPlaceholder description]
|
||
* @param {[type]} placeholder [description]
|
||
*/
|
||
TextField.prototype.setPlaceholder = function (placeholder) {
|
||
this.controls[0].setPlaceholder(placeholder);
|
||
return this;
|
||
};
|
||
/**
|
||
* [getPlaceholder description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
TextField.prototype.getPlaceholder = function () {
|
||
return this.controls[0].getPlaceholder();
|
||
};
|
||
/**
|
||
* [setMaxLength description]
|
||
* @param {[type]} maxLength [description]
|
||
*/
|
||
TextField.prototype.setMaxLength = function (maxLength) {
|
||
this.controls[0].setMaxLength(maxLength);
|
||
return this;
|
||
};
|
||
/**
|
||
* Set the parameter disabled for the control.
|
||
* @param {[disabled]} value
|
||
* @chainable
|
||
*/
|
||
TextField.prototype.setDisabled = function (value) {
|
||
if (typeof value === 'boolean') {
|
||
this.controls[0].setDisabled(value);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* [getMaxLength description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
TextField.prototype.getMaxLength = function () {
|
||
return this.controls[0].getMaxLength();
|
||
};
|
||
/**
|
||
* [isReadOnly description]
|
||
* @return {Boolean} [description]
|
||
*/
|
||
TextField.prototype.isReadOnly = function () {
|
||
return this.controls[0].isReadOnly();
|
||
};
|
||
/**
|
||
* Switches on/off the value trimming for the field's value when it loses focus.
|
||
* @param {Boolean} trimOnBlur Send true for switch on or false to switch off.
|
||
* @chainable
|
||
*/
|
||
TextField.prototype.setTrimOnBlur = function (trimOnBlur) {
|
||
this.trimOnBlur = !!trimOnBlur;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns a boolean value that indicates if the trimming function is enabled/disabled
|
||
* @return {Boolean}
|
||
*/
|
||
TextField.prototype.getTrimOnBlur = function () {
|
||
return this.trimOnBlur;
|
||
};
|
||
/**
|
||
* Sets the control for the TextField
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
TextField.prototype.setControls = function () {
|
||
if (this.controls.length) {
|
||
return this;
|
||
}
|
||
|
||
this.controls.push(new PMUI.control.TextControl());
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Establish the handler function for the internal onChange event
|
||
* @return {Function}
|
||
* @private
|
||
*/
|
||
TextField.prototype.onChangeHandler = function () {
|
||
var that = this,
|
||
i,
|
||
dependentFields = this.dependentFields,
|
||
form = this.form;
|
||
|
||
return function () {
|
||
var previousValue = that.value,
|
||
value;
|
||
|
||
if (that.trimOnBlur) {
|
||
value = that.controls[0].getValue();
|
||
value = jQuery.trim(value);
|
||
that.controls[0].setValue(value);
|
||
}
|
||
that.updateValueFromControls();
|
||
if (that.validAtChange) {
|
||
that.isValid();
|
||
}
|
||
if (typeof that.onChange === 'function') {
|
||
that.onChange(that.getValue(), previousValue);
|
||
}
|
||
if (that.form) {
|
||
(that.form.onChangeHandler())(that, that.getValue(), previousValue);
|
||
} else if (that.parent && that.parent.form) {
|
||
(that.parent.form.onChangeHandler())(that, that.getValue(), previousValue);
|
||
} else if (that.parent.parent && that.parent.parent.form) {
|
||
(that.parent.parent.form.onChangeHandler())(that, that.getValue(), previousValue);
|
||
} else if (that.parent.parent.parent && that.parent.parent.parent.form) {
|
||
(that.parent.parent.parent.form.onChangeHandler())(that, that.getValue(), previousValue);
|
||
} else {
|
||
return;
|
||
}
|
||
if (that.form) {
|
||
for (i = 0; i < dependentFields.length; i += 1) {
|
||
dependentField = form.getField(dependentFields[i]);
|
||
if (!dependentField) {
|
||
that.removeDependentField(dependentFields[i]);
|
||
continue;
|
||
}
|
||
dependentField.fireDependencyHandler();
|
||
}
|
||
}
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.field.TextField', TextField);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = TextField;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.field.PasswordField
|
||
* @extends PMUI.form.Field
|
||
* Class to handle a {@link PMUI.control.PasswordControl} field.
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var a;
|
||
* $(function() {
|
||
* a = new PMUI.field.PasswordField({
|
||
* label: "Some Text",
|
||
* required: true,
|
||
* helper: "Introduce a text (6 chars. max.)",
|
||
* validators: [
|
||
* {
|
||
* pmType: 'textLength',
|
||
* criteria: {
|
||
* maxLength: 6
|
||
* }
|
||
* }
|
||
* ]
|
||
* });
|
||
* document.body.appendChild(a.getHTML());
|
||
* a.defineEvents();
|
||
* });
|
||
*
|
||
*
|
||
* The code above will generate a required PasswordField with "Some Text" as label,
|
||
* the control will have a placeholder with the text "a text here".
|
||
* Also the field will contain a helper with the text "Introduce a text (6 chars. max.)"
|
||
* and a validator that will control the maximum length for the text to be entered.
|
||
*
|
||
* @cfg {Number} [maxLength=0] An integer that specifies the maximum character length for the text to be entered.
|
||
* 0 means no max length.
|
||
*
|
||
* #Note: This setting doesn't act as a validator, it simply set the max character length
|
||
* for the field's control.
|
||
* @cfg {Boolean} [trimOnBlur=true] A boolean that specifies if the value entered will be trimmed
|
||
* when the field loses focus.
|
||
*/
|
||
var PasswordField = function (settings) {
|
||
PasswordField.superclass.call(this, settings);
|
||
/**
|
||
* @property {Boolean} [trimOnBlur=true] If the field's value must be trimmed every time it loses focus.
|
||
*/
|
||
this.trimOnBlur = null;
|
||
PasswordField.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.form.Field', PasswordField);
|
||
|
||
PasswordField.prototype.type = "PasswordField";
|
||
|
||
PasswordField.prototype.init = function (settings) {
|
||
var defaults = {
|
||
maxLength: 0,
|
||
trimOnBlur: true
|
||
};
|
||
|
||
$.extend(true, defaults, settings);
|
||
|
||
this.setMaxLength(defaults.maxLength)
|
||
.setTrimOnBlur(defaults.trimOnBlur);
|
||
};
|
||
/**
|
||
* Sets the value for the field.
|
||
* @param {String} value
|
||
* @chainable
|
||
*/
|
||
PasswordField.prototype.setValue = function (value) {
|
||
if (this.trimOnBlur) {
|
||
value = jQuery.trim(value);
|
||
}
|
||
PasswordField.superclass.prototype.setValue.call(this, value);
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Set MaxLength
|
||
* @param maxLength
|
||
* @returns {PMUI.field.PasswordField}
|
||
*/
|
||
PasswordField.prototype.setMaxLength = function (maxLength) {
|
||
this.controls[0].setMaxLength(maxLength);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Get Max Length
|
||
* @returns {*}
|
||
*/
|
||
PasswordField.prototype.getMaxLength = function () {
|
||
return this.controls[0].getMaxLength();
|
||
};
|
||
|
||
/**
|
||
* Switches on/off the value trimming for the field's value when it loses focus.
|
||
* @param {Boolean} trimOnBlur Send true for switch on or false to switch off.
|
||
* @chainable
|
||
*/
|
||
PasswordField.prototype.setTrimOnBlur = function (trimOnBlur) {
|
||
this.trimOnBlur = !!trimOnBlur;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns a boolean value that indicates if the trimming function is enabled/disabled
|
||
* @return {Boolean}
|
||
*/
|
||
PasswordField.prototype.getTrimOnBlur = function () {
|
||
return this.trimOnBlur;
|
||
};
|
||
/**
|
||
* Sets the control for the PasswordField
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
PasswordField.prototype.setControls = function () {
|
||
if (this.controls.length) {
|
||
return this;
|
||
}
|
||
|
||
this.controls.push(new PMUI.control.PasswordControl());
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Establish the handler function for the internal onChange event
|
||
* @return {Function}
|
||
* @private
|
||
*/
|
||
PasswordField.prototype.onChangeHandler = function () {
|
||
var that = this;
|
||
|
||
return function () {
|
||
var previousValue = that.value,
|
||
value;
|
||
|
||
if (that.trimOnBlur) {
|
||
value = that.controls[0].getValue();
|
||
value = jQuery.trim(value);
|
||
that.controls[0].setValue(value);
|
||
}
|
||
that.updateValueFromControls();
|
||
if (that.validAtChange) {
|
||
that.isValid();
|
||
}
|
||
if (typeof that.onChange === 'function') {
|
||
that.onChange(that.getValue(), previousValue);
|
||
}
|
||
if (that.form) {
|
||
(that.form.onChangeHandler())(that, that.getValue(), previousValue);
|
||
}
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.field.PasswordField', PasswordField);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = PasswordField;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.field.TextAreaField
|
||
* @extends PMUI.field.TextField
|
||
* Class to handle a {@link PMUI.control.TextAreaControl}.
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var a;
|
||
* $(function() {
|
||
* a = new PMUI.field.TextAreaField({
|
||
* id:'12345',
|
||
* label: "coment",
|
||
* cols: 300,
|
||
* rows: 200,
|
||
* name: 'coments',
|
||
* placeholder: 'make your comment here...........',
|
||
* required: true,
|
||
* labelposition:'left',
|
||
* labelVerticalPosition:'top',
|
||
* tooltipPosition:'bottom',
|
||
* helper: "Introduce a text (200 chars. max.)",
|
||
* validators: [
|
||
* {
|
||
* pmType: 'textLength',
|
||
* criteria: {
|
||
* maxLength: 200
|
||
* }
|
||
* }
|
||
* ]
|
||
* });
|
||
* document.body.appendChild(a.getHTML());
|
||
* });
|
||
*
|
||
*
|
||
* TextAreaField, is a field for very long text strings
|
||
* to generate the above code on TextAreaField requires, one id, label, name, placeholder, required,
|
||
labelposition,
|
||
* labelVerticalPosition, tooltipPosition, helper.
|
||
*
|
||
* In case to modified label position or tooltip position it can contain the next properties:
|
||
* @cfg {'string'} [labelVerticalPosition='top'] in case that the position of the label left or right we
|
||
fixed this
|
||
* property in three cases ('top', 'center', 'bottom')
|
||
* @cfg {'string'} [tooltipPosition='top'] this property can set the tooltip in two cases ('top' or 'bottom')
|
||
for TextAreaField
|
||
*/
|
||
|
||
var TextAreaField = function (settings) {
|
||
|
||
TextAreaField.superclass.call(this, settings);
|
||
/**
|
||
* @property {string} [labelVerticalPosition='top'], in case that the position of the label left
|
||
or right we fixed this
|
||
* property in three cases ('top', 'center', 'bottom')
|
||
* @readonly
|
||
*/
|
||
this.labelVerticalPosition = null;
|
||
/**
|
||
* @property {string} [tooltipPosition='top'] this property can set the tooltip in two cases ('top' or
|
||
'bottom').
|
||
* @readonly
|
||
*/
|
||
this.tooltipPosition = null;
|
||
this.cols = null;
|
||
this.rows = null;
|
||
|
||
TextAreaField.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.field.TextField', TextAreaField);
|
||
|
||
TextAreaField.prototype.type = "TextAreaField";
|
||
|
||
TextAreaField.prototype.init = function (settings) {
|
||
var defaults = {
|
||
labelVerticalPosition: 'top',
|
||
tooltipPosition: 'top',
|
||
cols: 'auto',
|
||
rows: 'auto'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setLabelVerticalPosition(defaults.labelVerticalPosition);
|
||
this.setTooltipPosition(defaults.tooltipPosition);
|
||
this.setRows(defaults.rows);
|
||
this.setCols(defaults.cols);
|
||
|
||
};
|
||
|
||
/**
|
||
* Sets the labelVerticalPosition for the Label of the TextAreaField.
|
||
* input values (top, center and bottom) only affect the field if the label of TextAreaField is in
|
||
* left or right position.
|
||
* @param {String} labelVerticalPosition
|
||
* @chainable
|
||
*/
|
||
|
||
TextAreaField.prototype.setLabelVerticalPosition = function (value) {
|
||
var x,
|
||
result;
|
||
|
||
if (value === 'top' || value === 'bottom' || value === 'center') {
|
||
this.labelVerticalPosition = value;
|
||
|
||
if (this.controls[0] && this.html) {
|
||
this.dom.labelTextContainer.style.position = 'relative';
|
||
if (this.labelPosition === 'left' || this.labelPosition === 'right') {
|
||
if (this.labelVerticalPosition === 'top') {
|
||
this.dom.labelTextContainer.style.top = '0px';
|
||
this.dom.labelTextContainer.style.verticalAlign = 'top';
|
||
}
|
||
if (this.labelVerticalPosition === 'bottom') {
|
||
this.dom.labelTextContainer.style.top = '0px';
|
||
|
||
this.dom.labelTextContainer.style.verticalAlign = 'bottom';
|
||
}
|
||
if (this.labelVerticalPosition === 'center') {
|
||
|
||
this.dom.labelTextContainer.style.verticalAlign = 'top';
|
||
result = ($(this.controls[0].getHTML()).outerHeight() / 2) -
|
||
($(this.dom.labelTextContainer).outerHeight() / 2);
|
||
|
||
this.dom.labelTextContainer.style.top = (result) + 'px';
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
throw new Error("The value is not 'top' or 'bottom' please enter these values");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the label position
|
||
* input values(top, bottom, left, right)
|
||
* @param {String} labelPosition
|
||
* @chainable
|
||
*/
|
||
TextAreaField.prototype.setLabelPosition = function (position) {
|
||
if (this.html && (position === 'top' || position === 'bottom')) {
|
||
this.dom.labelTextContainer.style.top = '0px';
|
||
}
|
||
TextAreaField.superclass.prototype.setLabelPosition.call(this, position);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the tooltipPosition for the Label of the TextAreaField.
|
||
* input values (top and bottom) only affect the field if the label of TextAreaField
|
||
* @param {String} tooltipPosition
|
||
* @chainable
|
||
*/
|
||
TextAreaField.prototype.setTooltipPosition = function (value) {
|
||
|
||
if (value === 'top' || value === 'bottom') {
|
||
this.tooltipPosition = value;
|
||
|
||
if (this.controls[0] && this.html) {
|
||
|
||
|
||
if (this.tooltipPosition === 'top') {
|
||
this.helper.icon.style.addProperties({'vertical-align': 'top'});
|
||
}
|
||
if (this.tooltipPosition === 'bottom') {
|
||
|
||
this.helper.icon.style.addProperties({'vertical-align': 'bottom'});
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
throw new Error("The value is not 'top' or 'bottom' please enter these values");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the setHeight for the {PMUI.controls.TextAreaControl}.
|
||
* @param {String|number} [PMUI.controls.TextAreaControl]
|
||
* @chainable
|
||
*/
|
||
TextAreaField.prototype.setControlHeight = function (height) {
|
||
this.controls[0].setHeight(height);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the setWidth for the {PMUI.controls.TextAreaControl}.
|
||
* @param {String|number} [PMUI.controls.TextAreaControl]
|
||
* @chainable
|
||
*/
|
||
TextAreaField.prototype.setControlWidth = function (width) {
|
||
this.controls[0].setWidth(width);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the text for the TextAreaField label.
|
||
* @param {String} label
|
||
*/
|
||
|
||
TextAreaField.prototype.setLabel = function (label) {
|
||
if (typeof label === 'string') {
|
||
this.label = label;
|
||
} else {
|
||
throw new Error("The setLabel() method only accepts string values!");
|
||
}
|
||
if (this.dom.fieldTextLabel) {
|
||
this.dom.fieldTextLabel.textContent = this.label;
|
||
}
|
||
if (this.dom.fieldRequired) {
|
||
this.dom.fieldRequired.textContent = '*';
|
||
this.setRequired(this.required);
|
||
}
|
||
if (this.dom.fieldColon) {
|
||
this.dom.fieldColon.textContent = ":";
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the control for the TextField
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
TextAreaField.prototype.setControls = function () {
|
||
if (this.controls.length) {
|
||
return this;
|
||
}
|
||
|
||
this.controls.push(new PMUI.control.TextAreaControl());
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Disables the field
|
||
* @param {Boolean} Disable, if the field, then control is activated, if the control is enabled
|
||
* @chainable
|
||
*/
|
||
TextAreaField.prototype.disableField = function () {
|
||
this.controls[0].disable(true);
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables/enables the control
|
||
* @param {Boolean} Enable, if the field, then control is activated, if the control is diabled
|
||
* @chainable
|
||
*/
|
||
TextAreaField.prototype.enableField = function () {
|
||
this.controls[0].disable(false);
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the HTML element for the textAreaField
|
||
* @return {HTMLElement}
|
||
*/
|
||
TextAreaField.prototype.createHTML = function () {
|
||
TextAreaField.superclass.prototype.createHTML.call(this);
|
||
this.setLabelVerticalPosition(this.labelVerticalPosition);
|
||
this.setTooltipPosition(this.tooltipPosition);
|
||
return this.html;
|
||
};
|
||
/**
|
||
* assign hight as rows to textArea,
|
||
* @param {number|String} rows will be assigned as high in PX, the entered values can
|
||
* be numbers, 'number + px', 'auto' or percentage
|
||
* @chainable
|
||
*/
|
||
TextAreaField.prototype.setRows = function (rows) {
|
||
this.controls[0].setHeight(rows);
|
||
return this;
|
||
};
|
||
/**
|
||
* assign width as Cols to textArea,
|
||
* @param {number|String} Cols will be assigned as high in PX, the entered values can
|
||
* be numbers, 'number + px', 'auto' or percentage
|
||
* @chainable
|
||
*/
|
||
TextAreaField.prototype.setCols = function (cols) {
|
||
this.controls[0].setWidth(cols);
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.field.TextAreaField', TextAreaField);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = TextAreaField;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.field.DropDownListField
|
||
* @extends PMUI.form.Field
|
||
* Class to handle a {@link PMUI.control.DropDownListControl} field.
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var settings, list;
|
||
* $(function(){
|
||
* settings = {
|
||
* id : '123',
|
||
* label : "Pais",
|
||
* name : 'List Select',
|
||
* required: true,
|
||
* helper: "selected one opcion of the list",
|
||
* options: [
|
||
* {
|
||
* label: "BOLIVIA",
|
||
* options: [
|
||
* {
|
||
* label: "La Paz",
|
||
* value: 1,
|
||
* disabled : true
|
||
* },
|
||
* {
|
||
* label: "Cochabamba",
|
||
* value: 2
|
||
* },
|
||
* {
|
||
* label: "SantaCruz",
|
||
* value: 3
|
||
* },
|
||
* ]
|
||
* },
|
||
* {
|
||
* label: "ARGENTINA",
|
||
* options: [
|
||
* {
|
||
* label: "Buenos Aires",
|
||
* value: 4
|
||
* },
|
||
* {
|
||
* label: "Santa Fe",
|
||
* value: 5
|
||
* },
|
||
* {
|
||
* value: "Cordoba"
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* label: "CHILE",
|
||
* options: [
|
||
* {
|
||
* label: "Arica",
|
||
* value: 6
|
||
* },
|
||
* {
|
||
* label: "Santiago",
|
||
* value: 7
|
||
* },
|
||
* {
|
||
* value: "Concepcion"
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* label: "New York",
|
||
* value: 8
|
||
* },
|
||
* {
|
||
* label: "Mexico D.F.",
|
||
* value: 9
|
||
* }
|
||
* ]
|
||
* }
|
||
* list = new PMUI.field.DropDownListField(settings);
|
||
* document.body.appendChild(list.getHTML());
|
||
* });
|
||
*
|
||
*
|
||
* DropDownListField typo is a selection field, enclose the values ​​that we can choose from a list
|
||
* of options. The attributes that accompany the opening tag are:
|
||
* The code above will generate a DropDownListField, required one id, name, requiere,
|
||
* helper, text for list the options, one opcion array with the list options
|
||
*
|
||
* @constructor Creates an instance of the class DropDownListField.
|
||
* @param {Object} options Initialization options.
|
||
* @cfg {Array} [options=[]] An array with all the options to be contained by the
|
||
{PMUI.control.DropDownListControl}.
|
||
*
|
||
* Each element in the array is a JSON object, this JSON object can represent an option group
|
||
* or an option item.
|
||
*
|
||
* In case to represent an option item it can contain the next properties:
|
||
*
|
||
* - value {String} (required): the value for the option.
|
||
* - label {String} (optional): the label for the option, if isn't specified the value is used instead.
|
||
* - selected {Boolean} (optional): if the option is selected. #Note. If the configuration object has the
|
||
* "value" propery set then this "selected" property will be
|
||
* - disabled {Boolean} (optional): if the option is disabled or not.
|
||
*
|
||
* On the other hand, in case to represent an option group, it can contain the next properties:
|
||
*
|
||
* - label {String} (required): The name for the option group.
|
||
* - disabled {Boolean} (optional): If the group is disabled or not.
|
||
* - options {Array} (required): An array in which each element is a JSON object representing an option item,
|
||
* so every item must have the structure explained above (for represent option items). #Note. This propery makes
|
||
* the difference between an option and a option group. If the "options" property is not specified or if it isn't
|
||
* an array then it will treated like a option item.
|
||
* @cfg {String|Number} [listWidth='auto'] This value sets the width of the list
|
||
*/
|
||
|
||
|
||
var DropDownListField = function (settings) {
|
||
|
||
DropDownListField.superclass.call(this, settings);
|
||
|
||
/**
|
||
* @property {Boolean} [disabled=false] If the field is disabled or not.
|
||
* @readonly
|
||
*/
|
||
|
||
this.listWidth = null;
|
||
//this.defaultValue = null;
|
||
|
||
DropDownListField.prototype.init.call(this, settings);
|
||
|
||
};
|
||
|
||
PMUI.inheritFrom("PMUI.form.Field", DropDownListField);
|
||
|
||
DropDownListField.prototype.type = "DropDownListField";
|
||
|
||
DropDownListField.prototype.init = function (settings) {
|
||
var defaults = {
|
||
options: [],
|
||
listWidth: 'auto',
|
||
value: null
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setOptions(defaults.options);
|
||
this.setListWidth(defaults.listWidth);
|
||
this.updateValueFromControls();
|
||
|
||
if (defaults.value !== null) {
|
||
this.setValue(defaults.value);
|
||
}
|
||
};
|
||
/**
|
||
* Sets the options/option groups for the control.
|
||
* @param {Array} options An array with the same structure that the
|
||
* {@link PMUI.field.DropDownListField#cfg-options "options"} property in the
|
||
* Config settings section.
|
||
*/
|
||
DropDownListField.prototype.setOptions = function (options) {
|
||
var i;
|
||
if (jQuery.isArray(options)) {
|
||
this.controls[0].setOptions(options);
|
||
}
|
||
if (!this.value && options) {
|
||
for (i = 0; i < options.length; i += 1) {
|
||
if (options[i].selected) {
|
||
this.initialValue = options[i].value || options[i].label || "";
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
this.value = this.controls[0].getValue();
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the options/option groups from the field
|
||
* @param {Boolean} [includeGroups=false] If it's evaluated as true then it will include
|
||
* the option groups with its child elements, otherwise it will return only the option items.
|
||
* @return {Array}
|
||
*
|
||
* example
|
||
*
|
||
* list.getOptions(false)
|
||
* [La Paz][Cochabamba][Santa Cruz][Buenos Aires][Santa Fe][Cordoba][Santiago][.][.][Mexico D.F]
|
||
*
|
||
* list.getOptions(true)
|
||
* [BOLIVIA
|
||
* [La Paz][Cochabamba][SantaCruz]
|
||
* ]
|
||
* [ARGENTINA
|
||
* [Buenos Aires][Santa Fe][Cordoba]
|
||
* ]
|
||
* [CHILE
|
||
* [x][y][z]
|
||
* ]
|
||
* [New York]
|
||
* [Mexico D.F.]
|
||
*
|
||
* @return {Array}
|
||
*/
|
||
DropDownListField.prototype.getOptions = function (includeGroups) {
|
||
return this.controls[0].getOptions(includeGroups);
|
||
};
|
||
/**
|
||
* Clear all the options from the control.
|
||
* @chainable
|
||
*/
|
||
DropDownListField.prototype.clearOptions = function () {
|
||
this.controls[0].clearOptions();
|
||
this.value = this.controls[0].value;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Disables one or more options/option groups.
|
||
* @param {String|Number|Object} option It can be a string, a number or a JSON object.
|
||
*
|
||
* - In case to be a String, it will be disabled the options that match the string in its value and the option
|
||
* groups which match the string in its label. In this case more than one single item can be disabled.
|
||
* - In case to be a Number, it will be disabled the option/option group which index position matches the number.
|
||
* Obviously, in this case only one item will be disabled.
|
||
* - In case to be an object you can specify if the change will be applied only to options or option groups,
|
||
* it should have two properties:
|
||
* - criteria {String}: The value (in case of options) or the label (in case of option groups) the items
|
||
needs
|
||
* to match for apply the changes.
|
||
* - applyTo {String} (optional), it can take the following values:
|
||
* - "groups", the change will be applied only to the option groups.
|
||
* - "options", the change will be applied only to the options (direct child of the object).
|
||
* - [any other string value], the default value, it indicates that the change will be applied to both
|
||
* options/option groups that matches the criteria in its value/label respectly.
|
||
*
|
||
* @param {String} [group] It it is specified must be an String making reference to an existing option group
|
||
label.
|
||
* Using this parameter, the elements to be match by the first parameter will be search only in the option groups
|
||
* that match this parameter in its label.
|
||
*
|
||
* example
|
||
* list = [a
|
||
* [a0]
|
||
* [a1]
|
||
* ]
|
||
* [b
|
||
* [b0]
|
||
* [b1]
|
||
* ]
|
||
* [c]
|
||
* //disabling sending a number
|
||
* list.disableOption(0); -->disabled group a
|
||
* list.disableOption(4); -->disabled option b[b0]
|
||
*
|
||
* //disabling sending a string
|
||
* list.disableOption('a') --> disabled group a
|
||
* list.disableOption('b0') --> disabled option b[b0]
|
||
|
||
* //disabling sending a objects
|
||
list.disableOption({criteria:'a', applyTo:'groups'}) --> disabled group a
|
||
*
|
||
* @chainable
|
||
*/
|
||
|
||
DropDownListField.prototype.disableOption = function (option, group) {
|
||
this.controls[0].disableOption(option, group);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Enables one or more options/option groups.
|
||
* @param {String|Number|Object} option It can be a string, a number or a JSON object.
|
||
*
|
||
* - In case to be a String, it will be enabled the options that match the string in its value and the option
|
||
* groups which match the string in its label. In this case more than one single item can be enabled.
|
||
* - In case to be a Number, it will be enabled the option/option group which index position matches the number.
|
||
* Obviously, in this case only one item will be enabled.
|
||
* - In case to be an object you can specify if the change will be applied only to options or option groups,
|
||
* it should have two properties:
|
||
* - criteria {String}: The value (in case of options) or the label (in case of option groups) the items needs
|
||
* to match for apply the changes.
|
||
* - applyTo {String} (optional), it can take the following values:
|
||
* - "groups", the change will be applied only to the option groups.
|
||
* - "options", the change will be applied only to the options (direct child of the object).
|
||
* - [any other string value], the default value, it indicates that the change will be applied to both
|
||
* options/option groups that matches the criteria in its value/label respectly.
|
||
*
|
||
* @param {String} [group] It it is specified must be an String making reference to an existing option group
|
||
label.
|
||
* Using this parameter, the elements to be match by the first parameter will be search only in the option groups
|
||
* that match this parameter in its label.
|
||
* @chainable
|
||
*/
|
||
|
||
DropDownListField.prototype.enableOption = function (option, group) {
|
||
this.controls[0].enableOption(option, group);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Removes one or more option/option groups.
|
||
* @param {String|Number|Object} option It can be a string, a number or a JSON object.
|
||
*
|
||
* - In case to be a String, it will be removed the options that match the string in its value and the option
|
||
* groups which match the string in its label. In this case more than one single item can be removed.
|
||
* - In case to be a Number, it will be removed the option/option group which index position matches the number.
|
||
* Obviously, in this case only one item will be removed.
|
||
* - In case to be an object you can specify if the change will be applied only to options or option groups,
|
||
* it should have two properties:
|
||
* - criteria {String}: The value (in case of options) or the label (in case of option groups) the items
|
||
needs
|
||
* to match for apply the changes.
|
||
* - applyTo {String} (optional), it can take the following values:
|
||
* - "groups", the change will be applied only to the option groups.
|
||
* - "options", the change will be applied only to the options (direct child of the object).
|
||
* - [any other string value], the default value, it indicates that the change will be applied to both
|
||
* options/option groups that matches the criteria in its value/label respectly.
|
||
*
|
||
* @param {String} [group] It it is specified must be an String making reference to an existing option group
|
||
label.
|
||
* Using this parameter, the elements to be match by the first parameter will be search only in the option groups
|
||
* that match this parameter in its label.
|
||
*
|
||
* ##Note. Removing an option group implies removing all its child options.
|
||
* @chainable
|
||
*/
|
||
DropDownListField.prototype.removeOption = function (option, group) {
|
||
this.controls[0].removeOption(option, group);
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a new option group to the Field
|
||
* @param {Object} optionGroup A JSON object with the following properties:
|
||
*
|
||
* - label {String} (required): the label for the option group.
|
||
* - disabled {Boolean}(optional): if the option group will be disabled or not.
|
||
* it defaults to false.
|
||
* - options {Array} (optional): An array of JSON object, each one represents an option and
|
||
* should have the same structure than the "option" paremeter for the
|
||
* {@link PMUI.field.DropDownListField#addOption addOption() method}.
|
||
*/
|
||
DropDownListField.prototype.addOptionGroup = function (optionGroup) {
|
||
this.controls[0].addOptionGroup(optionGroup);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Adds a new option to the list of the DropDownListField or to an option group.
|
||
* @param {Object} option An object with ther settings for the new option.
|
||
* this object can have the following properties:
|
||
*
|
||
* - value {String} (required): the value for the option.
|
||
* - label {String} (optional): the label for the option, if isn't specified the value is used instead.
|
||
* - selected {Boolean} (optional): if the option is selected. #Note. If the configuration object has the
|
||
* "value" propery set then this "selected" property will be
|
||
* - disabled {Boolean} (optional): if the option is disabled or not.
|
||
*
|
||
* @param {String} group The name of the option group in which the new option will be added. If it doesn't exist
|
||
* it will be created.
|
||
*
|
||
* usage
|
||
* // add option a groupç
|
||
*
|
||
* list.addOption({value:'5', label:'Pando', selected: true, disabled:true },'BOLIVIA')
|
||
*
|
||
* //or add option
|
||
*
|
||
* list.addOption({value:'paris', label:'Paris'})
|
||
*
|
||
* @chainable
|
||
*/
|
||
DropDownListField.prototype.addOption = function (option, group) {
|
||
this.controls[0].addOption(option, group);
|
||
if (this.getOptions().length == 1) {
|
||
this.value = this.controls[0].value;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the label from the option currently selected.
|
||
* @return {String}
|
||
*/
|
||
DropDownListField.prototype.getSelectedLabel = function () {
|
||
return this.controls[0].getSelectedLabel();
|
||
};
|
||
/**
|
||
* Sets the control for the DropDownListField
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
DropDownListField.prototype.setControls = function () {
|
||
if (this.controls.length) {
|
||
return this;
|
||
}
|
||
this.controls.push(new PMUI.control.DropDownListControl());
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Set the width for the HTML DropDownListControl(select)
|
||
* @param {Number|String} width height it can be a number or a string.
|
||
In case of using a String you only can use 'auto' or 'inherit' or ##px or ##% or ##em when ## is a number
|
||
* @chainable
|
||
*/
|
||
|
||
DropDownListField.prototype.setListWidth = function (width) {
|
||
this.listWidth = width;
|
||
this.controls[0].setWidth(this.listWidth);
|
||
return this;
|
||
};
|
||
|
||
|
||
DropDownListField.prototype.getListWidth = function (width) {
|
||
return this.listWidth;
|
||
};
|
||
|
||
DropDownListField.prototype.setValue = function (value) {
|
||
var val;
|
||
if (this.controls[0]) {
|
||
val = this.controls[0].setValue(value).getValue();
|
||
}
|
||
DropDownListField.superclass.prototype.setValue.call(this, val || value);
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.field.DropDownListField', DropDownListField);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = DropDownListField;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.field.CheckBoxGroupField
|
||
* Field where the values can be selected from a group of options.
|
||
* @extends PMUI.form.Field
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var a;
|
||
* $(function() {
|
||
* a = new PMUI.field.CheckBoxGroupField({
|
||
* label: "development tools",
|
||
* controlPositioning: 'vertical',
|
||
* maxDirectionOptions: 2,
|
||
* required: true,
|
||
* value: '1',
|
||
* helper: "what lanaguages you know?. Select others besides javascript",
|
||
* options : [
|
||
* { label: 'Java',
|
||
* disabled: false,
|
||
* value: 'java',
|
||
* selected :true
|
||
* },
|
||
* { label: 'JavaScript',
|
||
* disabled: true,
|
||
* value: 'javaScript',
|
||
* selected :true
|
||
* },
|
||
* { label: 'Python',
|
||
* disabled: false,
|
||
* value: 'python'
|
||
* },
|
||
* { label: 'C#',
|
||
* disabled: true,
|
||
* value: 'visualbasic'
|
||
* }
|
||
* ],
|
||
* onChange: function(newVal, oldVal) {
|
||
* console.log("The value for the field \"" + this.getLabel() +
|
||
* "\": has change from \"" + oldVal + "\" to \"" + newVal + "\"");
|
||
* },
|
||
* });
|
||
* document.body.appendChild(a.getHTML());
|
||
* });
|
||
*
|
||
*
|
||
* The example above will generate a field with 4 CheckBox options.
|
||
*
|
||
* @constructor Creates an instance of the class CheckBoxGroupField.
|
||
* @param {Object} options Initialization options.
|
||
* @cfg {Array} [options=[]] An array in which every element is a JSON object with the same
|
||
structure required in the
|
||
* {@link PMUI.field.CheckBoxGroupField#addOption addOption() method}.
|
||
* @cfg {String} [controlPositioning="vertical"] A string that determines the direction for the options to be added
|
||
* in the field. This string can have one of the following values:
|
||
*
|
||
* - "horizontal" (default), in this case all the options will be included in horizontal order.
|
||
* - "vertical", in this case all the options will be included in vertical order.
|
||
* @cfg {Number} [maxDirectionOptions=1] The maximum number of options to be added in the current direction
|
||
* (set by the {@link PMUI.control.CheckBoxGroupField#cfg-controlPositioning controlPositioning config option}).
|
||
*
|
||
* @cfg {String} [value='[]'] The value that determines which options will be checked. the String must have an
|
||
* array format in which each element is the value of the options that are wanted to be checked.
|
||
*/
|
||
var CheckBoxGroupField = function (settings) {
|
||
CheckBoxGroupField.superclass.call(this, settings);
|
||
/**
|
||
* @property {String} controlPositioning The direction for the options to be added in the field.
|
||
* @readonly
|
||
*/
|
||
this.controlPositioning = null;
|
||
/**
|
||
* @property {Number} maxDirectionOptions The max number of options that can be in the current options
|
||
* direction.
|
||
* @readonly
|
||
*/
|
||
this.maxDirectionOptions = null;
|
||
/**
|
||
* The status if the controls to be saved when the field is switch between enabled/disabled.
|
||
* @type {Object}
|
||
* @private
|
||
*/
|
||
this.auxControlStates = {};
|
||
|
||
this.controlTable = {};
|
||
CheckBoxGroupField.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.form.Field', CheckBoxGroupField);
|
||
|
||
CheckBoxGroupField.prototype.type = "CheckBoxGroupField";
|
||
|
||
CheckBoxGroupField.prototype.init = function (settings) {
|
||
var defaults = {
|
||
options: [],
|
||
controlPositioning: "vertical",
|
||
maxDirectionOptions: 1,
|
||
value: '[]'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
this.setOptions(defaults.options)
|
||
.setMaxDirectionOptions(defaults.maxDirectionOptions)
|
||
.setControlPositioning(defaults.controlPositioning);
|
||
};
|
||
/**
|
||
* Enables the field. Notice that the controls that initially were disabled will continue being disabled.
|
||
* @chainable
|
||
*/
|
||
CheckBoxGroupField.prototype.enable = function () {
|
||
var key,
|
||
i,
|
||
controlsLength = this.controls.length,
|
||
controls = this.controls;
|
||
CheckBoxGroupField.superclass.prototype.enable.call(this);
|
||
this.disabled = false;
|
||
for (i = 0; i < controlsLength; i += 1) {
|
||
controls[i].disable(this.auxControlStates[controls[i].id]);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the max number of controls that can be in the current direction (the direction is set by the
|
||
* CheckBoxGroupField's
|
||
* {@link PMUI.field.CheckBoxGroupField#setControlPositioning setControlPositioning() method}).
|
||
* @param {Number} max It should be an integer, otherwise it will be floor rounded. If the value is equal or minor
|
||
* than 0 it means there's no limit.
|
||
*/
|
||
CheckBoxGroupField.prototype.setMaxDirectionOptions = function (max) {
|
||
if (typeof max === 'number') {
|
||
this.maxDirectionOptions = Math.floor(max);
|
||
if (this.html) {
|
||
this.setControlPositioning(this.controlPositioning);
|
||
}
|
||
} else {
|
||
throw new Error("setMaxDirectionOptions(): it only accepts number values.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* It overrides the Field's {@link PMUI.form.Field#setControlPositioning setControlPositioning() method}.
|
||
* This new implementation sets the direction for the control addition: horizontal or vertical.
|
||
* @param {String} positioning It can be "horizontal" or "vertical".
|
||
*/
|
||
CheckBoxGroupField.prototype.setControlPositioning = function (positioning) {
|
||
var errorMessage = "The setControlPositioning() method only accepts \"horizontal\" or \"vertical\" as value.",
|
||
table,
|
||
tbody,
|
||
cell,
|
||
row,
|
||
i,
|
||
column,
|
||
rowIndex;
|
||
if (typeof positioning === 'string') {
|
||
if (!(positioning === 'horizontal' || positioning === 'vertical')) {
|
||
return this;
|
||
}
|
||
this.controlPositioning = positioning;
|
||
if (this.html && this.controls) {
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
jQuery(this.controls[i].getHTML()).detach();
|
||
}
|
||
$(this.dom.controlContainer).empty();
|
||
table = PMUI.createHTMLElement("table");
|
||
table.className = 'pmui-field-control-table';
|
||
tbody = PMUI.createHTMLElement("tbody");
|
||
if (positioning === 'horizontal') {
|
||
row = PMUI.createHTMLElement("tr");
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
cell = PMUI.createHTMLElement('td');
|
||
this.controls[i].getHTML();
|
||
this.controls[i].control.tabIndex = i;
|
||
cell.appendChild(this.controls[i].getHTML());
|
||
row.appendChild(cell);
|
||
if (this.maxDirectionOptions > 0 && (i + 1) % this.maxDirectionOptions === 0) {
|
||
tbody.appendChild(row);
|
||
row = PMUI.createHTMLElement("tr");
|
||
}
|
||
}
|
||
tbody.appendChild(row);
|
||
} else {
|
||
column = 0;
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
cell = PMUI.createHTMLElement('td');
|
||
this.controls[i].getHTML();
|
||
this.controls[i].control.tabIndex = i;
|
||
cell.appendChild(this.controls[i].getHTML());
|
||
rowIndex = this.maxDirectionOptions === 0 ? i : i % this.maxDirectionOptions;
|
||
|
||
row = jQuery(tbody).find('tr').eq(rowIndex).get(0);
|
||
if (!row) {
|
||
row = PMUI.createHTMLElement('tr');
|
||
tbody.appendChild(row);
|
||
}
|
||
row.appendChild(cell);
|
||
}
|
||
}
|
||
this.controlTable = table;
|
||
table.appendChild(tbody);
|
||
this.dom.controlContainer.appendChild(table);
|
||
this.dom.controlContainer.appendChild(this.helper.getHTML());
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets all the options for the control for checkbox button.
|
||
* @param {Array} options An array in which every element is a JSON object with the
|
||
same structure required in the
|
||
* {@link PMUI.field.CheckBoxGroupField#addOption addOption() method}.
|
||
* @chainable
|
||
*/
|
||
CheckBoxGroupField.prototype.setOptions = function (options) {
|
||
var i = 0;
|
||
|
||
this.value = [];
|
||
this.value = JSON.stringify(this.value);
|
||
|
||
if (jQuery.isArray(options)) {
|
||
for (i = 0; i < options.length; i += 1) {
|
||
this.addOption(options[i]);
|
||
}
|
||
} else {
|
||
throw new Error("setOptions(): the supplied argument must be an array.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a new option to the CheckBoxGroupField.
|
||
* @param {Object} option A JSON object, which can have the same properties that the config options
|
||
* for the {@link PMUI.control.SelectableControl SelectableControl class} except by "mode",
|
||
it will always be override by the value "checkBox".
|
||
* @chainable
|
||
*/
|
||
CheckBoxGroupField.prototype.addOption = function (option) {
|
||
var newOption;
|
||
|
||
newOption = new PMUI.control.SelectableControl(jQuery.extend(true, option, {
|
||
mode: 'checkbox',
|
||
name: this.controls.length + 1,
|
||
selected: option.selected
|
||
}));
|
||
|
||
if (newOption.isSelected()) {
|
||
this.value = JSON.parse(this.value);
|
||
this.value.push(newOption.getValue());
|
||
this.value = JSON.stringify(this.value);
|
||
}
|
||
if (this.eventsDefined) {
|
||
newOption.setOnChangeHandler(this.onChangeHandler()).getHTML();
|
||
newOption.setOnBeforeChangeHandler(this.onBeforeChangeHandler());
|
||
newOption.defineEvents();
|
||
}
|
||
this.auxControlStates[newOption.id] = newOption.disabled;
|
||
this.controls.push(newOption);
|
||
this.setControlPositioning(this.controlPositioning);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes one or more options (checkBox Button).
|
||
* @param {String|Number|PMUI.control.SelectableControl} option It can be:
|
||
*
|
||
* - A number, in that case the parameter is used as the index of the item to be removed.
|
||
* - A String, in that case the parameter is used as the item's value,
|
||
* that means that everyone item that has that value will be removed.
|
||
* - An instance of {@link PMUI.control.SelectableControl SelectableControl} which must be a control of the field.
|
||
* @chainable
|
||
*/
|
||
CheckBoxGroupField.prototype.removeOption = function (item) {
|
||
var itemToRemove,
|
||
i;
|
||
if (item instanceof PMUI.control.SelectableControl) {
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i] === item) {
|
||
itemToRemove = i;
|
||
break;
|
||
}
|
||
}
|
||
} else if (typeof item === 'string') {
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].id === item) {
|
||
itemToRemove = this.controls[i];
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
itemToRemove = item;
|
||
}
|
||
if (typeof itemToRemove === 'number') {
|
||
itemToRemove = this.controls[itemToRemove];
|
||
delete this.auxControlStates[itemToRemove.id];
|
||
jQuery(itemToRemove.html).detach();
|
||
this.controls.splice(itemToRemove, 1);
|
||
this.setControlPositioning(this.controlPositioning);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* It clears all the options from the field.
|
||
* @chainable
|
||
*/
|
||
CheckBoxGroupField.prototype.clearOptions = function () {
|
||
while (this.controls.length) {
|
||
this.removeOption(0);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Update the field's value property from the controls
|
||
* the parameter value is a clean array;
|
||
* @protected
|
||
* @chainable
|
||
*/
|
||
CheckBoxGroupField.prototype.updateValueFromControls = function () {
|
||
var value = [], i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].isSelected()) {
|
||
value.push(this.controls[i].getValue());
|
||
}
|
||
}
|
||
|
||
this.value = JSON.stringify(value);
|
||
this.data.setValue(this.value);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the value to the field's controls.
|
||
* @protected
|
||
* @param {String} value
|
||
* @chainable
|
||
*/
|
||
CheckBoxGroupField.prototype.setValueToControls = function (value) {
|
||
var i, j, values, controls, controlsLength;
|
||
|
||
try {
|
||
value = value.replace(/'/g, "\"");
|
||
values = JSON.parse(value);
|
||
} catch (e) {
|
||
values = '[]';
|
||
}
|
||
|
||
controlsLength = (controls = this.controls.slice(0)).length;
|
||
for (i = 0; i < controlsLength; i += 1) {
|
||
controls[i].deselect();
|
||
}
|
||
for (i = 0; i < values.length; i += 1) {
|
||
for (j = 0; j < controlsLength; j += 1) {
|
||
if (controls[j].getValue() === values[i]) {
|
||
controls[j].select();
|
||
controls.splice(j, 1);
|
||
controlsLength -= 1;
|
||
j -= 1;
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Evaluates the required validation.
|
||
* @return {Boolean} Returns true if the validation passes otherwise returns false.
|
||
*/
|
||
CheckBoxGroupField.prototype.evalRequired = function () {
|
||
var valid = true, value;
|
||
value = JSON.parse(this.getValue());
|
||
if (this.required && value.length === 0) {
|
||
this.showMessage(this.requiredMessage, "error");
|
||
valid = false;
|
||
} else {
|
||
this.hideMessage();
|
||
}
|
||
return valid;
|
||
};
|
||
|
||
CheckBoxGroupField.prototype.isValid = function () {
|
||
var valid = true,
|
||
validator;
|
||
|
||
valid = valid && this.evalRequired();
|
||
if (!valid) {
|
||
$(this.controlTable).addClass('error');
|
||
return valid;
|
||
}
|
||
$(this.controlTable).removeClass('error');
|
||
for (validator in this.validators) {
|
||
if (this.validators.hasOwnProperty(validator)) {
|
||
valid = valid && this.validators[validator].isValid();
|
||
if (!valid) {
|
||
this.message.setText(this.validators[validator].errorMessage);
|
||
return valid;
|
||
}
|
||
}
|
||
}
|
||
return valid;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
CheckBoxGroupField.prototype.getValue = function (format) {
|
||
var castFormat = format || this.valueType,
|
||
controls = this.controls,
|
||
i,
|
||
res = [];
|
||
|
||
for (i = 0; i < controls.length; i += 1) {
|
||
if (controls[i].isSelected()) {
|
||
res.push(PMUI.castValue(controls[i].getValue(), castFormat));
|
||
}
|
||
}
|
||
return JSON.stringify(res);
|
||
};
|
||
/**
|
||
* Disable the option
|
||
* @param {number|string} disable If the value is part of group CheckBox
|
||
* @chainable
|
||
*/
|
||
CheckBoxGroupField.prototype.disableOption = function (value) {
|
||
var i;
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].value == value || this.controls[i].label == value || value == i) {
|
||
this.controls[i].disable(true);
|
||
return this;
|
||
}
|
||
}
|
||
throw new Error('the value send is not part of group CheckBox');
|
||
};
|
||
/**
|
||
* Enable the option
|
||
* @param {number|string} disable If the value is part of group CheckBox
|
||
* Enables a field's option.
|
||
*/
|
||
CheckBoxGroupField.prototype.enableOption = function (value) {
|
||
var i;
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].value == value || this.controls[i].label == value || value == i) {
|
||
this.controls[i].disable(false);
|
||
return this;
|
||
}
|
||
}
|
||
throw new Error('the value send is not part of group CheckBox');
|
||
};
|
||
|
||
CheckBoxGroupField.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
CheckBoxGroupField.superclass.prototype.createHTML.call(this)
|
||
if (this.disabled) {
|
||
this.disable();
|
||
}
|
||
return this.html;
|
||
};
|
||
|
||
CheckBoxGroupField.prototype.checkedOption = function (option) {
|
||
var i;
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (option === i || option === this.controls[i].label || option === this.controls[i].value) {
|
||
if (!this.controls[i].selected) {
|
||
this.controls[i].select();
|
||
} else {
|
||
this.controls[i].deselect();
|
||
}
|
||
return this;
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupField.prototype.defineEvents = function () {
|
||
var that = this;
|
||
CheckBoxGroupField.superclass.prototype.defineEvents.call(this);
|
||
this.addEvent('click').listen(this.dom.labelTextContainer, function (e) {
|
||
if (that.controls.length) {
|
||
$(that.controls[0].html).find('input')[0].focus();
|
||
}
|
||
});
|
||
return this;
|
||
};
|
||
/**
|
||
* @method getOptions
|
||
* @ obtains under each option and configuration
|
||
* @chainable
|
||
*/
|
||
CheckBoxGroupField.prototype.getOptions = function () {
|
||
var i,
|
||
options = [],
|
||
option;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
option = {};
|
||
option["label"] = this.controls[i].label;
|
||
option["value"] = this.controls[i].value;
|
||
option["disabled"] = this.controls[i].disabled;
|
||
option["selected"] = this.controls[i].selected;
|
||
options.push(option);
|
||
}
|
||
return options;
|
||
};
|
||
|
||
CheckBoxGroupField.prototype.getValueFromControls = function () {
|
||
var value = [],
|
||
i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].isSelected()) {
|
||
value.push(this.controls[i].getValue());
|
||
}
|
||
}
|
||
|
||
this.value = JSON.stringify(value);
|
||
this.data.setValue(this.value);
|
||
return this.value;
|
||
};
|
||
PMUI.extendNamespace('PMUI.field.CheckBoxGroupField', CheckBoxGroupField);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = CheckBoxGroupField;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.field.RadioButtonGroupField
|
||
* Field whose value can be selected from a group of options.
|
||
* @extends PMUI.form.Field
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var a;
|
||
* $(function() {
|
||
* a = new PMUI.field.RadioButtonGroupField({
|
||
* label: "Some Text",
|
||
* controlPositioning: 'vertical',
|
||
* maxDirectionOptions: 2,
|
||
* options: [
|
||
* {
|
||
* label: "opt1",
|
||
* value: "1"
|
||
* },
|
||
* {
|
||
* label: "opt2",
|
||
* value: "2"
|
||
* },
|
||
* {
|
||
* label: "opt3",
|
||
* value: "3"
|
||
* }
|
||
* ],
|
||
* onChange: function(newVal, oldVal) {
|
||
* console.log("The value for the field \"" + this.getLabel()
|
||
* + "\": has change from \"" + oldVal + "\" to \"" + newVal + "\"");
|
||
* },
|
||
* required: true,
|
||
* value: "2"
|
||
* });
|
||
* document.body.appendChild(a.getHTML());
|
||
* });
|
||
*
|
||
*
|
||
* The example above will generate a field with 3 radio buttons.
|
||
*
|
||
* @cfg {Array} [options=[]] An array in which every element is a JSON object with the same structure required in
|
||
* the {@link PMUI.field.RadioButtonGroupField#addOption addOption() method}.
|
||
* @cfg {String} [controlPositioning="vertical"] A string that determines the direction for the options to be added
|
||
* in the field. This string can have one of the following values:
|
||
*
|
||
* - "horizontal" (default), in this case all the options will be included in horizontal order.
|
||
* - "vertical", in this case all the options will be included in vertical order.
|
||
* @cfg {Number} [maxDirectionOptions=1] The maximum number of options to be added in the current direction
|
||
* (set by the {@link PMUI.control.RadioButtonGroupField#cfg-controlPositioning controlPositioning config option}).
|
||
*/
|
||
var RadioButtonGroupField = function (settings) {
|
||
RadioButtonGroupField.superclass.call(this, settings);
|
||
/**
|
||
* @property {String} controlPositioning The direction for the options to be added in the field.
|
||
* @readonly
|
||
*/
|
||
this.controlPositioning = null;
|
||
/**
|
||
* @property {Number} maxDirectionOptions The max number of options that can be in the current options
|
||
* direction.
|
||
* @readonly
|
||
*/
|
||
this.maxDirectionOptions = null;
|
||
/**
|
||
* The status if the controls to be saved when the field is switch between enabled/disabled.
|
||
* @type {Object}
|
||
* @private
|
||
*/
|
||
this.auxControlStates = {};
|
||
this.controlTable = null;
|
||
RadioButtonGroupField.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.form.Field', RadioButtonGroupField);
|
||
|
||
RadioButtonGroupField.prototype.type = "RadioButtonGroupField";
|
||
|
||
RadioButtonGroupField.prototype.init = function (settings) {
|
||
var defaults = {
|
||
options: [],
|
||
controlPositioning: "vertical",
|
||
maxDirectionOptions: 1
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setOptions(defaults.options)
|
||
.setMaxDirectionOptions(defaults.maxDirectionOptions)
|
||
.setControlPositioning(defaults.controlPositioning);
|
||
};
|
||
/**
|
||
* Enables the field. Notice that the controls that initially were disabled will continue being disabled.
|
||
* @chainable
|
||
*/
|
||
RadioButtonGroupField.prototype.enable = function () {
|
||
var key,
|
||
i,
|
||
controlsLength = this.controls.length,
|
||
controls = this.controls;
|
||
|
||
RadioButtonGroupField.superclass.prototype.enable.call(this);
|
||
this.disabled = false;
|
||
for (i = 0; i < controlsLength; i += 1) {
|
||
controls[i].disable(this.auxControlStates[controls[i].id]);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the max number of controls that can be in the current direction (the direction is set by the
|
||
* RadioButtonGroupField's
|
||
* {@link PMUI.field.RadioButtonGroupField#setControlPositioning setControlPositioning() method}).
|
||
* @param {Number} max It should be an integer, otherwise it will be floor rounded. If the value is equal or minor
|
||
* than 0 it means there's no limit.
|
||
*/
|
||
RadioButtonGroupField.prototype.setMaxDirectionOptions = function (max) {
|
||
if (typeof max === 'number') {
|
||
this.maxDirectionOptions = Math.floor(max);
|
||
if (this.html) {
|
||
this.setControlPositioning(this.controlPositioning);
|
||
}
|
||
} else {
|
||
throw new Error("setMaxDirectionOptions(): it only accepts number values.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes one or more options (radio button)
|
||
* @param {String|Number|PMUI.control.SelectableControl} option It can be:
|
||
*
|
||
* - A number, in that case the parameter is used as the index of the item to be removed.
|
||
* - A String, in that case the parameter is used as the item's value,
|
||
* that means that everyone item that has that value will be removed.
|
||
* - An instance of {@link PMUI.control.SelectableControl SelectableControl} which must be a control of the field.
|
||
* @chainable
|
||
*/
|
||
RadioButtonGroupField.prototype.removeOption = function (item) {
|
||
var itemToRemove,
|
||
i;
|
||
|
||
if (item instanceof PMUI.control.SelectableControl) {
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i] === item) {
|
||
itemToRemove = i;
|
||
break;
|
||
}
|
||
}
|
||
} else if (typeof item === 'string') {
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].id === item) {
|
||
itemToRemove = this.controls[i];
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
itemToRemove = item;
|
||
}
|
||
if (typeof itemToRemove === 'number') {
|
||
itemToRemove = this.controls[itemToRemove];
|
||
delete this.auxControlStates[itemToRemove.id];
|
||
jQuery(itemToRemove.html).detach();
|
||
this.controls.splice(itemToRemove, 1);
|
||
this.setControlPositioning(this.controlPositioning);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* It clears all the options from the field.
|
||
* @chainable
|
||
*/
|
||
RadioButtonGroupField.prototype.clearOptions = function () {
|
||
while (this.controls.length) {
|
||
this.removeOption(0);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* It overrides the Field's {@link PMUI.form.Field#setControlPositioning setControlPositioning() method}.
|
||
* This new implementation sets the direction for the control addition: horizontal or vertical.
|
||
* @param {String} positioning It can be "horizontal" or "vertical".
|
||
*/
|
||
RadioButtonGroupField.prototype.setControlPositioning = function (positioning) {
|
||
var errorMessage = "The setControlPositioning() method only accepts \"horizontal\" or \"vertical\" as value.",
|
||
table,
|
||
tbody,
|
||
cell,
|
||
row,
|
||
i,
|
||
column,
|
||
rowIndex;
|
||
|
||
if (typeof positioning === 'string') {
|
||
if (!(positioning === 'horizontal' || positioning === 'vertical')) {
|
||
return this;
|
||
}
|
||
this.controlPositioning = positioning;
|
||
if (this.html && this.controls) {
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
jQuery(this.controls[i].getHTML()).detach();
|
||
}
|
||
$(this.dom.controlContainer).empty();
|
||
table = PMUI.createHTMLElement("table");
|
||
table.className = 'pmui-field-control-table';
|
||
tbody = PMUI.createHTMLElement("tbody");
|
||
if (positioning === 'horizontal') {
|
||
row = PMUI.createHTMLElement("tr");
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
cell = PMUI.createHTMLElement('td');
|
||
this.controls[i].getHTML();
|
||
this.controls[i].control.tabIndex = i;
|
||
cell.appendChild(this.controls[i].getHTML());
|
||
row.appendChild(cell);
|
||
if (this.maxDirectionOptions > 0 && (i + 1) % this.maxDirectionOptions === 0) {
|
||
tbody.appendChild(row);
|
||
row = PMUI.createHTMLElement("tr");
|
||
}
|
||
}
|
||
tbody.appendChild(row);
|
||
} else {
|
||
column = 0;
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
cell = PMUI.createHTMLElement('td');
|
||
this.controls[i].getHTML();
|
||
this.controls[i].control.tabIndex = i;
|
||
cell.appendChild(this.controls[i].getHTML());
|
||
rowIndex = this.maxDirectionOptions === 0 ? i : i % this.maxDirectionOptions;
|
||
|
||
row = jQuery(tbody).find('tr').eq(rowIndex).get(0);
|
||
if (!row) {
|
||
row = PMUI.createHTMLElement('tr');
|
||
tbody.appendChild(row);
|
||
}
|
||
row.appendChild(cell);
|
||
}
|
||
}
|
||
this.controlTable = table;
|
||
table.appendChild(tbody);
|
||
this.dom.controlContainer.appendChild(table);
|
||
this.dom.controlContainer.appendChild(this.helper.getHTML());
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a new option to the field.
|
||
* @param {Object} option A JSON object, which can have the same properties that the config options
|
||
* for the {@link PMUI.control.SelectableControl SelectablecControl class} except by "mode",
|
||
* it will always be override by the value "radio".
|
||
* @chainable
|
||
*/
|
||
RadioButtonGroupField.prototype.addOption = function (option) {
|
||
var newOption,
|
||
settings = {
|
||
mode: 'radio',
|
||
name: this.name,
|
||
selected: option.selected
|
||
};
|
||
|
||
newOption = new PMUI.control.SelectableControl(jQuery.extend(true, option, settings));
|
||
if (this.eventsDefined) {
|
||
newOption.setOnChangeHandler(this.onChangeHandler()).getHTML();
|
||
newOption.defineEvents();
|
||
}
|
||
this.auxControlStates[newOption.id] = newOption.disabled;
|
||
this.controls.push(newOption);
|
||
this.setControlPositioning(this.controlPositioning);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets all the options for the control.
|
||
* @param {Array} options An array in which every element is a JSON object with the same structure required in the
|
||
* {@link PMUI.field.RadioButtonGroupField#addOption addOption() method}.
|
||
* @chainable
|
||
*/
|
||
RadioButtonGroupField.prototype.setOptions = function (options) {
|
||
var i = 0;
|
||
if (jQuery.isArray(options)) {
|
||
for (i = 0; i < options.length; i += 1) {
|
||
this.addOption(options[i]);
|
||
}
|
||
} else {
|
||
throw new Error("setOptions(): the supplied argument must be an array.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Update the field's value property from the controls
|
||
* @protected
|
||
* @chainable
|
||
*/
|
||
RadioButtonGroupField.prototype.updateValueFromControls = function () {
|
||
var value = '',
|
||
i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].isSelected()) {
|
||
value = this.controls[i].getValue();
|
||
break;
|
||
}
|
||
}
|
||
|
||
this.value = value;
|
||
this.data.setValue(this.value);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the value to the field's controls.
|
||
* @protected
|
||
* @param {String} value
|
||
* @chainable
|
||
*/
|
||
RadioButtonGroupField.prototype.setValueToControls = function (value) {
|
||
var i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].getValue() === value) {
|
||
this.controls[i].select();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
RadioButtonGroupField.prototype.getValueFromControls = function () {
|
||
var value = '',
|
||
i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].isSelected()) {
|
||
value += ' ' + this.controls[i].getValue();
|
||
}
|
||
}
|
||
return value.substr(1);
|
||
};
|
||
RadioButtonGroupField.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
RadioButtonGroupField.superclass.prototype.createHTML.call(this)
|
||
if (this.disabled) {
|
||
this.disable();
|
||
}
|
||
return this.html;
|
||
};
|
||
|
||
/**
|
||
* @method selection Option
|
||
* @param {Number|String} value This is the index or the name of the option that will be selected
|
||
* @chainable
|
||
*/
|
||
RadioButtonGroupField.prototype.selectOption = function (value) {
|
||
var i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (value == this.controls[i].label || value == i) {
|
||
this.setValue(this.controls[i].value);
|
||
return this;
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
RadioButtonGroupField.prototype.disableOption = function (value) {
|
||
var i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].value === value || this.controls[i].label === value || value === i) {
|
||
this.controls[i].disable(true);
|
||
return this;
|
||
}
|
||
}
|
||
throw new Error('the value send is not part of group Radio');
|
||
};
|
||
|
||
RadioButtonGroupField.prototype.enableOption = function (value) {
|
||
var i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].value === value || this.controls[i].label === value || value === i) {
|
||
this.controls[i].disable(false);
|
||
return this;
|
||
}
|
||
}
|
||
throw new Error('the value send is not part of group Radio');
|
||
};
|
||
|
||
RadioButtonGroupField.prototype.defineEvents = function () {
|
||
var that = this;
|
||
|
||
if (this.html && !this.eventsDefined) {
|
||
RadioButtonGroupField.superclass.prototype.defineEvents.call(this);
|
||
this.addEvent('click').listen(this.dom.labelTextContainer, function (e) {
|
||
if (that.controls.length) {
|
||
$(that.controls[0].html).find('input')[0].focus();
|
||
}
|
||
});
|
||
this.eventsDefined = true;
|
||
}
|
||
return this;
|
||
};
|
||
RadioButtonGroupField.prototype.isValid = function () {
|
||
var valid = true,
|
||
validator;
|
||
|
||
valid = valid && this.evalRequired();
|
||
if (!valid) {
|
||
$(this.controlTable).addClass('error');
|
||
return valid;
|
||
}
|
||
$(this.controlTable).removeClass('error');
|
||
for (validator in this.validators) {
|
||
if (this.validators.hasOwnProperty(validator)) {
|
||
valid = valid && this.validators[validator].isValid();
|
||
if (!valid) {
|
||
this.message.setText(this.validators[validator].errorMessage);
|
||
return valid;
|
||
}
|
||
}
|
||
}
|
||
return valid;
|
||
};
|
||
/**
|
||
* @method getOptions
|
||
* @ obtains under each option and configuration
|
||
* @chainable
|
||
*/
|
||
RadioButtonGroupField.prototype.getOptions = function () {
|
||
var i,
|
||
options = [],
|
||
option;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
option = {};
|
||
option["label"] = this.controls[i].label;
|
||
option["value"] = this.controls[i].value;
|
||
option["disabled"] = this.controls[i].disabled;
|
||
option["selected"] = this.controls[i].selected;
|
||
options.push(option);
|
||
}
|
||
return options;
|
||
};
|
||
|
||
RadioButtonGroupField.prototype.getValueFromControls = function () {
|
||
var value = '', i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].isSelected()) {
|
||
value = this.controls[i].getValue();
|
||
break;
|
||
}
|
||
}
|
||
|
||
this.value = value;
|
||
this.data.setValue(this.value);
|
||
|
||
return this.value;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.field.RadioButtonGroupField', RadioButtonGroupField);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = RadioButtonGroupField;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.field.DateTimeField
|
||
* @extends {PMUI.form.Field}
|
||
* This field is to manipulate the [PMI.control.DateTimeControl]
|
||
*
|
||
* example:
|
||
*
|
||
* @example
|
||
* var dateTimePicker;
|
||
* $(function() {
|
||
* dateTimePicker = new PMUI.field.DateTimeField(
|
||
* {
|
||
* label:'Calendar',
|
||
* helper: 'This is calendar Gregorian',
|
||
* value: new Date(),
|
||
* datetime : true,
|
||
* dateFormat: 'M dd yy',
|
||
* minDate: -90,
|
||
* maxDate: "+1y -1m -4d",
|
||
* firstDay: 1,
|
||
* months: {
|
||
* "january": {
|
||
* name: "Enero",
|
||
* shortname: "Ene"
|
||
* },
|
||
* "february": {
|
||
* name: "Febrero",
|
||
* shortname: "Feb"
|
||
* },
|
||
* "march": {
|
||
* name: "Marzo",
|
||
* shortname: "Mar"
|
||
* },
|
||
* "april": {
|
||
* name: "Abril",
|
||
* shortname: "Abr"
|
||
* },
|
||
* "may": "May",
|
||
* "june": "Junio",
|
||
* "july": "July",
|
||
* "august": "Agosto",
|
||
* "september": "Septiembre",
|
||
* "october": "Octubre",
|
||
* "november": "Noviembre",
|
||
* "december": "Diciembre"
|
||
* },
|
||
* days: {
|
||
* "sunday": {
|
||
* name: "Domingo",
|
||
* shortname: "Do"
|
||
* },
|
||
* "monday": {
|
||
* name: "Lunes",
|
||
* shortname: "Lu"
|
||
* },
|
||
* "tuesday": {
|
||
* name: "Martes",
|
||
* shortname: "Ma"
|
||
* },
|
||
* "wednesday": {
|
||
* name: "Miércoles",
|
||
* shortname: "Mi"
|
||
* },
|
||
* "thursday": {
|
||
* name: "Jueves",
|
||
* shortname: "Ju"
|
||
* },
|
||
* "friday": "Viernes",
|
||
* "saturday": "Sábado"
|
||
* }
|
||
* }
|
||
* );
|
||
* document.body.appendChild(dateTimePicker.getHTML());
|
||
* dateTimePicker.defineEvents();
|
||
* });
|
||
*
|
||
* @constructor Creates an instance of the class DateTimeField.
|
||
* @param {Object} options Initialization options.
|
||
* @cfg {Boolean} [datetime=false] If the [PMUI.control.DateTimeControl] You can see more about the configuration
|
||
* in {@link PMUI.control.DateTimeControl#cfg-datetime datetime}
|
||
* @cfg {String} [dateFormat="yy-mm-dd H:i:s"|"yy-mm-dd"],necessary to set the date format property of the control
|
||
* [PMUI.control.DateTimeControl]
|
||
* You can see more about the configuration in {@link PMUI.control.DateTimeControl#cfg-dateFormat dateFormat}
|
||
* @cfg {Object} [months={"january": "January", "february": "February", "march": "March", "april": "April",
|
||
* "may": "May", "june": "June", "july": "July", "august": "August", "september": "September",
|
||
* "october": "October", "november": "November", "december": "December"}], A JSON object to set the names and
|
||
* shortnames for every month in year.
|
||
* You can see more about the configuration in {@link PMUI.control.DateTimeControl#cfg-months months}
|
||
* @cfg {Object} [days={"sunday": "Sunday","monday": "Monday","tuesday": "Tuesday","wednesday": "Wednesday",
|
||
* "thursday": "Thursday","friday": "Friday","saturday": "Saturday"}], A JSON object to set the name and shortname
|
||
* for every day of week.
|
||
* You can see more about the configuration in {@link PMUI.control.DateTimeControl#cfg-days days}
|
||
* @cfg {String|Number} [minDate=-365] A value which sets the min selectable date for the calendar. You can see
|
||
* more about the configuration in
|
||
* {@link PMUI.control.DateTimeControl#cfg-minDate minDate}
|
||
* @cfg {String|Number} [maxDate=365] A value which sets the max selectable date for the calendar.
|
||
* @cfg {Number} [firstDay=0] Sets the first day of week. You can use numbers from 0 to 6, 0 means Sunday, 1 means
|
||
* Monday and so on.
|
||
* @cfg {String} [returnFormat="UTC"] Specifies the date format that will be used for the returning date.
|
||
* The valid values are:
|
||
*
|
||
* - "UTC", returns a date in the format: yyyy-mm-ddTHH:ii:ss-HH:mm (i.e. 2013-08-31T00:08:00+04:00).
|
||
* - "@" or "timestamp", returns a date in timestamp format.
|
||
* - [any other valid format string], will return the date using the string as the dateformat. This string can
|
||
* contain any of the wilcards specified in the
|
||
* {@link PMUI.control.DateTimeControl#cfg-dateFormat dateFormat config option}.
|
||
*/
|
||
var DateTimeField = function (settings) {
|
||
DateTimeField.superclass.call(this, settings);
|
||
/**
|
||
* The default date format to be used in the returning date. Set by the {@link #cfg-returnFormat} config option
|
||
* and the {@link #method-setReturnFormat setReturnFormat()} method.
|
||
* @type {String}
|
||
*/
|
||
this.returnFormat = null;
|
||
DateTimeField.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.form.Field', DateTimeField);
|
||
|
||
DateTimeField.prototype.type = "DateTimeField";
|
||
|
||
DateTimeField.prototype.init = function (settings) {
|
||
var defaults = {
|
||
datetime: false,
|
||
dateFormat: settings && settings.datetime ? 'yy-mm-dd H:i:s' : 'yy-mm-dd',
|
||
months: {
|
||
"january": "January".translate(),
|
||
"february": "February".translate(),
|
||
"march": "March".translate(),
|
||
"april": "April".translate(),
|
||
"may": "May".translate(),
|
||
"june": "June".translate(),
|
||
"july": "July".translate(),
|
||
"august": "August".translate(),
|
||
"september": "September".translate(),
|
||
"october": "October".translate(),
|
||
"november": "November".translate(),
|
||
"december": "December".translate()
|
||
},
|
||
days: {
|
||
"sunday": "Sunday".translate(),
|
||
"monday": "Monday".translate(),
|
||
"tuesday": "Tuesday".translate(),
|
||
"wednesday": "Wednesday".translate(),
|
||
"thursday": "Thursday".translate(),
|
||
"friday": "Friday".translate(),
|
||
"saturday": "Saturday".translate()
|
||
},
|
||
minDate: -365,
|
||
maxDate: 365,
|
||
firstDay: 0,
|
||
returnFormat: 'UTC'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setDateFormat(defaults.dateFormat)
|
||
.setMonths(defaults.months)
|
||
.setDays(defaults.days)
|
||
.setMinDate(defaults.minDate)
|
||
.setMaxDate(defaults.maxDate)
|
||
.setFirstDay(defaults.firstDay)
|
||
.setReturnFormat(defaults.returnFormat)
|
||
.setValue(defaults.value)
|
||
.visibleDateTime(defaults.datetime);
|
||
};
|
||
/**
|
||
* Enables/disabled the calendar's [PMUI.control.DateTimeControl] time supporting.
|
||
* @param {Boolean} visible If it's true, then the time supporting is enabled, otherwise it's disabled.
|
||
* @chainable
|
||
*/
|
||
DateTimeField.prototype.visibleDateTime = function (visible) {
|
||
this.controls[0].visibleDateTime(visible);
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the [PMUI.control.DateTimeControl] maximum selectable date.
|
||
* @param {String} [format="UTC"] The format to applied to the returning date.
|
||
* @return {String} The maximum selectable date in string format.
|
||
*/
|
||
DateTimeField.prototype.getMaxDate = function (format) {
|
||
return this.controls[0].getMaxDate(format);
|
||
};
|
||
/**
|
||
* Returns the [PMUI.control.DateTimeControl] minimun selectable date.
|
||
* @param {String} [format="UTC"] The format to applied to the returning date.
|
||
* @return {String} The maximum selectable date in string format.
|
||
*/
|
||
DateTimeField.prototype.getMinDate = function (format) {
|
||
return this.controls[0].getMinDate(format);
|
||
};
|
||
/**
|
||
* Sets the date formatr to be used when you get the value from the object.
|
||
* @param {String} format The valid values are:
|
||
*
|
||
* - "UTC", returns a date in the format: yyyy-mm-ddTHH:ii:ss-HH:mm (i.e. 2013-08-31T00:08:00+04:00).
|
||
* - "@" or "timestamp", returns a date in timestamp format.
|
||
* - [any other valid format string], will return the date using the string as the dateformat. This string can
|
||
* contain any of the wilcards specified in the
|
||
* {@link PMUI.control.DateTimeControl#cfg-dateFormat dateFormat config option}.
|
||
* @chainable
|
||
*/
|
||
DateTimeField.prototype.setReturnFormat = function (format) {
|
||
if (typeof format === 'string') {
|
||
this.returnFormat = format;
|
||
} else {
|
||
throw new Error("setReturnFormat(): the parameter must be a string.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the day index of the first day of week.
|
||
* @return {Number} A number refering a day: 0 for Sunday, 1 for Monday and so on.
|
||
*/
|
||
DateTimeField.prototype.getFirstDay = function () {
|
||
return this.controls[0].getFirstDay();
|
||
};
|
||
/**
|
||
* Sets the value to the field's controls.
|
||
* @protected
|
||
* @param {String} value
|
||
* @param {String} utc
|
||
* @chainable
|
||
*/
|
||
DateTimeField.prototype.setValueToControls = function (value, utc) {
|
||
this.controls[0].setValue(value, utc);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the field's value.
|
||
* @param {String} value
|
||
* @param {String} utc
|
||
*/
|
||
DateTimeField.prototype.setValue = function (value, utc) {
|
||
value = value || "";
|
||
if (value instanceof Date || typeof value === 'string' || typeof value === 'number') {
|
||
if (this.controls[0]) {
|
||
this.setValueToControls(value, utc);
|
||
this.value = this.controls[0].getValue(this.returnFormat);
|
||
this.data.setValue(this.value);
|
||
}
|
||
} else {
|
||
throw new Error("The setValue() method only accepts string values!");
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the first day of week.
|
||
* @param {Number} day Use 0 for Sunday, 1 for Monday, 2 for Tuesday and so on!.
|
||
*/
|
||
DateTimeField.prototype.setFirstDay = function (day) {
|
||
this.controls[0].setFirstDay(day);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the format for the date to be displayed in the control's textbox control.
|
||
* You can see more about here [PMUI.control.DateTimeControl] in method
|
||
* {@link PMUI.control.DateTimeControl#setDateFormat setDateFormat}
|
||
**/
|
||
DateTimeField.prototype.setDateFormat = function (dateFormat) {
|
||
this.controls[0].setDateFormat(dateFormat);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the minimum date the [PMUI.control.DateTimeControl] can accept as a selectable one.
|
||
* You can see more about here [PMUI.control.DateTimeControl] in method
|
||
* {@link PMUI.control.DateTimeControl#setMinDate setMinDate}
|
||
*/
|
||
DateTimeField.prototype.setMinDate = function (date) {
|
||
this.controls[0].setMinDate(date);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the max date the [PMUI.control.DateTimeControl] can accept as a selectable one.
|
||
* You can see more about here in the class [PMUI.control.DateTimeControl] in method
|
||
{@link PMUI.control.DateTimeControl#setMaxDate setMaxDate}
|
||
*/
|
||
DateTimeField.prototype.setMaxDate = function (date) {
|
||
this.controls[0].setMaxDate(date);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the months the [PMUI.control.DateTimeControl] names/shortnames to be used by the calendar.
|
||
* @param {Object} months An object with the same structure that the [PMUI.control.DateTimeControl]
|
||
* method {@link PMUI.control.DateTimeControl#setMonths setMonths}.
|
||
* @chainable
|
||
*/
|
||
DateTimeField.prototype.setMonths = function (months) {
|
||
this.controls[0].setMonths(months);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the [PMUI.control.DateTimeControl] name/shortnames for the days to be used in the calendar.
|
||
* @param {Object} days A JSON object with the same structure than the [PMUI.control.DateTimeControl]
|
||
* method {@link PMUI.control.DateTimeControl#setDays setDays}
|
||
*/
|
||
DateTimeField.prototype.setDays = function (days) {
|
||
this.controls[0].setDays(days);
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the formated date.
|
||
* @return {String}
|
||
*/
|
||
DateTimeField.prototype.getFormatedDate = function () {
|
||
return this.controls[0].getFormatedDate();
|
||
};
|
||
/**
|
||
* Returns the field's value.
|
||
* @param {String} [format] Specifies the date format that will be used for the returning date. If it isn't
|
||
* specified, the {@link #property-returnFormat returnFormat} will be used instead.
|
||
*
|
||
* The valid values are:
|
||
*
|
||
* - "UTC", returns a date in the format: yyyy-mm-ddTHH:ii:ss-HH:mm (i.e. 2013-08-31T00:08:00+04:00).
|
||
* - "@" or "timestamp", returns a date in timestamp format.
|
||
* - [any other valid format string], will return the date using the string as the dateformat. This string can
|
||
* contain any of the wilcards specified in the
|
||
* {@link PMUI.control.DateTimeControl#cfg-dateFormat dateFormat config option}.
|
||
* @return {String}
|
||
*/
|
||
DateTimeField.prototype.getValue = function (format) {
|
||
return this.controls[0].getValue(format || this.returnFormat);
|
||
};
|
||
/**
|
||
* Sets the controls for the field.
|
||
* Since this is an abstract method, it must be implemented in its non-abstract subclasses
|
||
* @abstract
|
||
* @private
|
||
*/
|
||
DateTimeField.prototype.setControls = function () {
|
||
if (this.controls.length) {
|
||
return this;
|
||
}
|
||
this.controls.push(new PMUI.control.DateTimeControl());
|
||
return this;
|
||
};
|
||
/**
|
||
* Updates the current value from the controls which are part of the field
|
||
* @chainable
|
||
*/
|
||
DateTimeField.prototype.updateValueFromControls = function () {
|
||
this.value = this.controls[0].getValue(this.returnFormat);
|
||
this.data.setValue(this.value);
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.field.DateTimeField', DateTimeField);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = DateTimeField;
|
||
}
|
||
}());
|
||
|
||
(function () {
|
||
var TextAnnotationField = function (settings) {
|
||
TextAnnotationField.superclass.call(this, settings);
|
||
this.text = null;
|
||
this._textType = null;
|
||
this.text_Align = null;
|
||
this._labelTag = null;
|
||
TextAnnotationField.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.form.Field', TextAnnotationField);
|
||
|
||
TextAnnotationField.prototype.type = "TextAnnotationField";
|
||
|
||
TextAnnotationField.TEXT_TYPES = {
|
||
Plain: 0,
|
||
HTML: 1
|
||
};
|
||
|
||
TextAnnotationField.prototype.init = function (settings) {
|
||
var defaults = {
|
||
maxLength: 0,
|
||
text: "",
|
||
textType: TextAnnotationField.TEXT_TYPES.Plain,
|
||
text_Align: "left"
|
||
};
|
||
|
||
$.extend(true, defaults, settings);
|
||
this.setText(defaults.text);
|
||
this.setTextType(defaults.textType);
|
||
this.setText_Align(defaults.text_Align);
|
||
};
|
||
|
||
TextAnnotationField.prototype.setTextType = function (type) {
|
||
switch (type) {
|
||
case TextAnnotationField.TEXT_TYPES.Plain:
|
||
case TextAnnotationField.TEXT_TYPES.HTML:
|
||
this._textType = type;
|
||
break;
|
||
default:
|
||
throw new Error("setTextType(): Invalid argument.");
|
||
}
|
||
this.setText(this.text);
|
||
return this;
|
||
};
|
||
|
||
TextAnnotationField.prototype.setText = function (text) {
|
||
if (typeof text !== "string") {
|
||
throw new Error("setText(): The parameter is not valid");
|
||
}
|
||
this.text = text;
|
||
if (this.html) {
|
||
if (this._textType == TextAnnotationField.TEXT_TYPES.HTML) {
|
||
jQuery(this._labelTag).html(this.text);
|
||
} else {
|
||
jQuery(this._labelTag).text(this.text);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
TextAnnotationField.prototype.setText_Align = function (value) {
|
||
if (typeof value === "string") {
|
||
this.text_Align = value;
|
||
} else {
|
||
throw new Error("the enter parameter is no valid");
|
||
}
|
||
return this;
|
||
};
|
||
|
||
TextAnnotationField.prototype.setValue = function () {
|
||
return this;
|
||
};
|
||
|
||
TextAnnotationField.prototype.setControls = function () {
|
||
return this;
|
||
};
|
||
|
||
TextAnnotationField.prototype.setHelper = function () {
|
||
return this;
|
||
};
|
||
|
||
TextAnnotationField.prototype.createHTML = function () {
|
||
var labelTag, textbefore, spanRequired, sp = " ";
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
TextAnnotationField.superclass.superclass.prototype.createHTML.call(this);
|
||
labelTag = PMUI.createHTMLElement('span');
|
||
labelTag.className = 'pmui-field-label';
|
||
labelTag.style.width = "100%";
|
||
labelTag.style.textAlign = this.text_Align;
|
||
this._labelTag = labelTag;
|
||
this.html.appendChild(labelTag);
|
||
|
||
this.setText(this.text);
|
||
return this.html;
|
||
};
|
||
|
||
TextAnnotationField.prototype.isValid = function () {
|
||
return true;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.field.TextAnnotationField', TextAnnotationField);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = TextAnnotationField;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.form.FormItemFactory
|
||
* @extend PMUI.util.Factory
|
||
* Extends the factory class to produce objects to be included in containers for forms.
|
||
*
|
||
* Its default products are:
|
||
*
|
||
* - {@link PMUI.form.FormPanel FormPanel} objects: using "panel".
|
||
* - {@link PMUI.field.TextField TextField} objects: using "text".
|
||
* - {@link PMUI.field.DropDownListField DropDownListField} objects: using "dropdown".
|
||
* - {@link PMUI.field.RadioButtonGroupField RadioButtonGroupField} objects: using "radio".
|
||
* - {@link PMUI.field.CheckBoxGroupField CheckBoxGroupField} objects: using "checkbox".
|
||
* - {@link PMUI.field.TextAreaField TextAreaField} objects: using "textarea".
|
||
* - {@link PMUI.field.DateTimeField DateTimeField} objects: using "datetime".
|
||
*
|
||
* @constructor
|
||
* Creates a new instance od the class
|
||
*/
|
||
var FormItemFactory = function () {
|
||
FormItemFactory.superclass.call(this);
|
||
FormItemFactory.prototype.init.call(this);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.util.Factory', FormItemFactory);
|
||
|
||
FormItemFactory.prototype.init = function () {
|
||
var defaults = {
|
||
products: {
|
||
"field": PMUI.form.Field,
|
||
"panel": PMUI.form.FormPanel,
|
||
"text": PMUI.field.TextField,
|
||
"password": PMUI.field.PasswordField,
|
||
"dropdown": PMUI.field.DropDownListField,
|
||
"radio": PMUI.field.RadioButtonGroupField,
|
||
"checkbox": PMUI.field.CheckBoxGroupField,
|
||
"textarea": PMUI.field.TextAreaField,
|
||
"datetime": PMUI.field.DateTimeField,
|
||
"optionsSelector": PMUI.field.OptionsSelectorField,
|
||
"upload": PMUI.field.UploadField,
|
||
"buttonField": PMUI.field.ButtonField,
|
||
"annotation": PMUI.field.TextAnnotationField
|
||
},
|
||
defaultProduct: "panel"
|
||
};
|
||
this.setProducts(defaults.products)
|
||
.setDefaultProduct(defaults.defaultProduct);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.form.FormItemFactory', FormItemFactory);
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.form.FormPanel
|
||
* @extends PMUI.core.Panel
|
||
* Class to handle form containers for {@link PMUI.form.Field Field objects},
|
||
* {@link PMUI.form.FormPanel FormPanel objects}, and {@link PMUI.form.TabPanel TabPanel objects}.
|
||
*
|
||
* @example
|
||
* var p;
|
||
* $(function() {
|
||
* p = new PMUI.form.FormPanel({
|
||
* width: 600,
|
||
* height: 130,
|
||
* fieldset: true,
|
||
* legend: "my fieldset panel",
|
||
* items: [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Name",
|
||
* id: "123",
|
||
* value: "",
|
||
* placeholder: "insert your name",
|
||
* name: "name"
|
||
* },{
|
||
* pmType: "text",
|
||
* label: "Last name",
|
||
* value: "",
|
||
* placeholder: "your lastname here asshole!",
|
||
* name: "lastname"
|
||
* }, {
|
||
* pmType: "panel",
|
||
* layout: 'hbox',
|
||
* items: [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "E-mail",
|
||
* value: "",
|
||
* name: "email"
|
||
* },{
|
||
* pmType: "text",
|
||
* label: "Phone",
|
||
* value: "555",
|
||
* name: "phone"
|
||
* }
|
||
* ]
|
||
* }
|
||
* ],
|
||
* layout: "vbox"
|
||
* });
|
||
* document.body.appendChild(p.getHTML());
|
||
* console.log("haha");
|
||
* });
|
||
*
|
||
* @cfg {PMUI.form.Form} [form=null] The {@link PMUI.form.Form Form} the object belongs to.
|
||
* @cfg {Array} [items=[]] The array with the items to be contained by the object.
|
||
* //example
|
||
* {
|
||
* ......
|
||
* items: [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Name",
|
||
* id: "123",
|
||
* value: "",
|
||
* placeholder: "insert your name",
|
||
* name: "name"
|
||
* }, {
|
||
* pmType: "text",
|
||
* label: "Last name",
|
||
* value: "",
|
||
* placeholder: "your lastname here asshole!",
|
||
* name: "lastname"
|
||
* }, {
|
||
* pmType: "panel",
|
||
* layout: 'hbox',
|
||
* items: [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "E-mail",
|
||
* value: "",
|
||
* name: "email"
|
||
* },{
|
||
* pmType: "text",
|
||
* label: "Phone",
|
||
* value: "555",
|
||
* name: "phone"
|
||
* }
|
||
* ]
|
||
* }
|
||
* ],
|
||
* ......
|
||
* });
|
||
* @cfg {Boolean} [fieldset=false] If the panel will apply the fieldset behavior.
|
||
* @cfg {String} [legend=""] The text for the legend to show in case the object applies the fieldset behavior.
|
||
* (only applicable if the the object will apply the fieldset behavior).
|
||
* @cfg {Number} [legendSize=12] The size for the text in the fieldset's legend.
|
||
*/
|
||
var FormPanel = function (settings) {
|
||
/**
|
||
* @property {PMUI.util.ArrayList} fields
|
||
* Object that contains all the object's direct children that are {@link PMUI.form.Field Field} objects.
|
||
* @private
|
||
*/
|
||
this.fields = new PMUI.util.ArrayList();
|
||
/**
|
||
* @property {PMUI.util.ArrayList} formPanels
|
||
* Object that contains all the object's direct children that are {@link PMUI.form.FormPanel FormPanel}
|
||
objects.
|
||
* @private
|
||
*/
|
||
this.formPanels = new PMUI.util.ArrayList();
|
||
/**
|
||
* @property {PMUI.util.ArrayList} tabPanels
|
||
* Object that contains all the object's direct children that are {@link PMUI.form.TabPanel TabPanel} objects.
|
||
* @private
|
||
*/
|
||
this.tabPanels = new PMUI.util.ArrayList();
|
||
|
||
FormPanel.superclass.call(this, settings);
|
||
/**
|
||
* @property {Boolean} [fieldset]
|
||
* If the panel has the fieldset behavior.
|
||
* @readonly
|
||
*/
|
||
this.fieldset = null;
|
||
/**
|
||
* @property {PMUI.form.Form} [form=null] The {@link PMUI.form.Form Form} the object belongs to.
|
||
*/
|
||
this.form = null;
|
||
/**
|
||
* @property {String} [legend=""] The text for the legend to show in case of the fieldset behavior
|
||
will be applied.
|
||
*/
|
||
this.legend = null;
|
||
/**
|
||
* @property {String} [legendElement=""] The HTML element for containt the legend to show in case of the
|
||
fieldset behavior will be applied.
|
||
*/
|
||
this.legendElement = null;
|
||
/**
|
||
* @property {Number} [fieldsetLegendSize] The size for the text showed in the fieldset legend.
|
||
* @readonly
|
||
*/
|
||
this.legendSize = null;
|
||
this.onChange = null;
|
||
this._onAvailabilityChange = null;
|
||
|
||
FormPanel.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Panel', FormPanel);
|
||
|
||
FormPanel.prototype.type = 'FormPanel';
|
||
|
||
FormPanel.prototype.init = function (settings) {
|
||
var defaults = {
|
||
form: null,
|
||
fieldset: false,
|
||
legend: "",
|
||
padding: (settings && settings.fieldset) ? "5px 10px" : "10px",
|
||
borderWidth: (settings && settings.fieldset) ? 1 : "",
|
||
legendSize: 12,
|
||
onChange: null,
|
||
onAvailabilityChange: null
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setPadding(defaults.padding)
|
||
.setBorderWidth(defaults.borderWidth)
|
||
.setForm(defaults.form)
|
||
.setOnAvailabilityChange(defaults.onAvailabilityChange);
|
||
|
||
this.form = defaults.form;
|
||
this.fieldset = defaults.fieldset;
|
||
this.legend = defaults.legend;
|
||
this.legendSize = defaults.legendSize;
|
||
this.onChange = defaults.onChange;
|
||
|
||
if (this.fieldset) {
|
||
this.setElementTag("fieldset");
|
||
}
|
||
};
|
||
/**
|
||
* Sets the function to be called when the availability on any contained item changes.
|
||
* @param handler
|
||
*/
|
||
FormPanel.prototype.setOnAvailabilityChange = function (handler) {
|
||
if (!(typeof handler === 'function' || handler === null)) {
|
||
throw new Error("onAvailabilityChange(): The parameter must be a function or NULL.");
|
||
}
|
||
this._onAvailabilityChange = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns a field from the form panel.
|
||
* @param {String} name The name of the field to find.
|
||
* @return {PMUI.form.Field|null}
|
||
*/
|
||
FormPanel.prototype.getField = function (name) {
|
||
var i,
|
||
items = this.getItems(),
|
||
field = null;
|
||
|
||
for (i = 0; i < items.length; i += 1) {
|
||
if (items[i] instanceof PMUI.form.Field) {
|
||
if (items[i].getName() === name) {
|
||
return items[i];
|
||
}
|
||
} else {
|
||
field = items[i].getField(name);
|
||
if (field) {
|
||
return field;
|
||
}
|
||
}
|
||
}
|
||
return field;
|
||
};
|
||
/**
|
||
* Returns an array of items depending on the parameters the method receives.
|
||
* @param {String} [filter=undefined]
|
||
* A string which specifiest the bunch of items that will be returned.
|
||
* It defaults to {undefined}, that means that only the direct child items will be in the returned array.
|
||
*
|
||
* Alternatively this param can take one of the following values:
|
||
*
|
||
* - 'fields': it will return only the child {@link PMUI.form.Field Field} items.
|
||
* - 'formPanels': it will return only the child {@link PMUI.form.FormPanel FormPanel} items.
|
||
* - 'tabPanels': it will return only the child {@link PMUI.form.TabPanel TabPanel} items.
|
||
*
|
||
* @param {Boolean} [includeChildren=false]
|
||
*
|
||
* If the value is evaluated as false only the direct child items will be returned,
|
||
* otherwise additionaly will be added the items for all child items.
|
||
*
|
||
* Note: This parameter only has effect when the [filter] parameter is provided.
|
||
* @return {Array}
|
||
*/
|
||
FormPanel.prototype.getItems = function (filter, includeChildren) {
|
||
var res = [],
|
||
items,
|
||
size,
|
||
i,
|
||
targetArray,
|
||
the_class;
|
||
|
||
switch (filter) {
|
||
case 'fields':
|
||
the_class = PMUI.form.Field;
|
||
targetArray = this.fields;
|
||
break;
|
||
case 'formPanels':
|
||
the_class = PMUI.form.FormPanel;
|
||
targetArray = this.formPanels;
|
||
break;
|
||
case 'tabPanels':
|
||
the_class = PMUI.form.TabPanel;
|
||
targetArray = this.tabPanels;
|
||
break;
|
||
default:
|
||
return FormPanel.superclass.prototype.getItems.call(this);
|
||
}
|
||
|
||
if (includeChildren) {
|
||
if (the_class) {
|
||
items = this.items.asArray();
|
||
size = items.length;
|
||
for (i = 0; i < size; i += 1) {
|
||
if (items[i] instanceof the_class) {
|
||
res.push(items[i]);
|
||
} else {
|
||
res = res.concat(items[i].getItems(filter, true));
|
||
}
|
||
}
|
||
} else {
|
||
throw new Error('getItems(): The valid values for the "filter" parameter are: "fields",' +
|
||
'"formPanels" or "tabPanels", received: ' + filter);
|
||
}
|
||
} else {
|
||
res = targetArray.asArray().slice(0);
|
||
}
|
||
return res;
|
||
};
|
||
/**
|
||
* Sets the form the form panel belongs to.
|
||
* @param {PMUI.form.Form} form
|
||
* @chainable
|
||
*/
|
||
FormPanel.prototype.setForm = function (form) {
|
||
if (form instanceof PMUI.form.Form) {
|
||
this.form = form;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the {@link PMUI.util.Factory Factory} object for the FormPanel
|
||
* @param {PMUI.util.Factory|Object} factory It can be a {@link PMUI.util.Factory Factory} object,
|
||
or a JSON object.
|
||
* If it is a JSON object then a {@link PMUI.form.FormItemFactory FormItemFactory}
|
||
* is created using the JSON object as the config options.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
FormPanel.prototype.setFactory = function (factory) {
|
||
if (factory instanceof PMUI.util.Factory) {
|
||
this.factory = factory;
|
||
} else {
|
||
this.factory = new PMUI.form.FormItemFactory(factory);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Clear all the items.
|
||
* @chainable
|
||
*/
|
||
FormPanel.prototype.clearItems = function () {
|
||
FormPanel.superclass.prototype.clearItems.call(this);
|
||
if (this.fields) {
|
||
this.fields.clear();
|
||
this.formPanels.clear();
|
||
this.tabPanels.clear();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the text for the legend to be displayed just in case of the fieldset behavior is beign applied.
|
||
* @param {String} legend
|
||
* @chainable
|
||
*/
|
||
FormPanel.prototype.setLegend = function (legend) {
|
||
if (typeof legend === 'string') {
|
||
this.legend = legend;
|
||
if (this.legendElement) {
|
||
this.legendElement.textContent = legend;
|
||
}
|
||
} else {
|
||
throw new Error("setLegend(): this method accepts string values as only parameter.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the HTML element for the FormPanel.
|
||
* @chainable
|
||
*/
|
||
FormPanel.prototype.createHTML = function () {
|
||
var legendElement,
|
||
html;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
FormPanel.superclass.prototype.createHTML.call(this);
|
||
|
||
if (this.fieldset) {
|
||
legendElement = PMUI.createHTMLElement('legend');
|
||
legendElement.textContent = this.legend;
|
||
legendElement.className = 'pmui-formpanel-legend';
|
||
legendElement.style.fontSize = this.legendSize + "px";
|
||
this.legendElement = legendElement;
|
||
jQuery(this.html).prepend(legendElement);
|
||
}
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Returns the object's usable height.
|
||
* @return {Number|String}
|
||
*/
|
||
FormPanel.prototype.getUsableHeight = function () {
|
||
var height = FormPanel.superclass.prototype.getUsableHeight.call(this);
|
||
if (isNaN(height)) {
|
||
return height;
|
||
}
|
||
if (this.fieldset) {
|
||
height -= this.legendSize;
|
||
}
|
||
|
||
return height;
|
||
};
|
||
/**
|
||
* Sets the internal handler function for the onChange Event
|
||
* @return {Function} The handler function.
|
||
* @private
|
||
*/
|
||
FormPanel.prototype.onChangeHandler = function () {
|
||
var that = this;
|
||
return function (a, b, c) {
|
||
var target,
|
||
newValue,
|
||
previousValue;
|
||
|
||
if (this instanceof PMUI.form.Field) {
|
||
target = this;
|
||
newValue = a;
|
||
previousValue = b;
|
||
} else {
|
||
target = a;
|
||
newValue = b;
|
||
previousValue = c;
|
||
}
|
||
if (typeof that.onChange === 'function') {
|
||
that.onChange(target, newValue, previousValue);
|
||
}
|
||
if (this instanceof PMUI.form.Field && this.form) {
|
||
(this.form.onChangeHandler())(target, newValue, previousValue);
|
||
}
|
||
};
|
||
};
|
||
FormPanel.prototype._getOnAvailabilityChangeHandler = function () {
|
||
var that = this;
|
||
return function (panel, enabled) {
|
||
if (typeof that._onAvailabilityChange === 'function') {
|
||
that._onAvailabilityChange(panel, enabled);
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Add an item to the object.
|
||
* @param {Object|PMUI.form.Field|PMUI.form.FormPanel|PMUI.form.TabPanel} item
|
||
* The item parameter can be:
|
||
*
|
||
* - A JSON object, in that case, it must have at least a "pmType" property
|
||
* which can have any of the values specifed in the {@link PMUI.form.FormItemFactory FormItemFactory
|
||
documentation}.
|
||
* - A {@link PMUI.form.Field Field} object.
|
||
* - A {@link PMUI.form.FormPanel FormPanel} object.
|
||
* - A {@link PMUI.form.TabPanel TabPanel} object.
|
||
*/
|
||
FormPanel.prototype.addItem = function (item, index) {
|
||
var itemToBeAdded;
|
||
|
||
if (this.factory) {
|
||
if (typeof item === 'object' && !item.layout) {
|
||
item.layout = (this.layout && this.layout.type.toLowerCase()) || "vbox";
|
||
}
|
||
if (this.factory.isValidClass(item) || this.factory.isValidName(item.pmType)) {
|
||
itemToBeAdded = this.factory.make(item);
|
||
} else {
|
||
throw new Error('Invalid item to add.');
|
||
}
|
||
}
|
||
if (itemToBeAdded) {
|
||
itemToBeAdded.setForm(this.form);
|
||
itemToBeAdded.setDisplay("inline-block");
|
||
if (itemToBeAdded instanceof PMUI.form.FormPanel) {
|
||
itemToBeAdded.setOnAvailabilityChange(this._getOnAvailabilityChangeHandler());
|
||
this.formPanels.insert(itemToBeAdded);
|
||
} else if (itemToBeAdded instanceof PMUI.form.Field) {
|
||
this.fields.insert(itemToBeAdded);
|
||
if (this.form) {
|
||
this.form.data.addItem(itemToBeAdded.data);
|
||
}
|
||
}
|
||
FormPanel.superclass.prototype.addItem.call(this, itemToBeAdded, index);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes an item from the form panel.
|
||
* @param {String|Number|PMUI.core.Element} item
|
||
* It can be:
|
||
* - a String: in this case this string must be the id of the element to be removed.
|
||
* - a Number: in this case this number must be the index of the element to be removed.
|
||
* - a {@link PMUI.core.Element Element} object: in this case it will be removed
|
||
* (if it is contained by the current form panel).
|
||
* @chainable
|
||
*/
|
||
FormPanel.prototype.removeItem = function (item) {
|
||
var itemToRemove;
|
||
|
||
if (item instanceof PMUI.core.Element) {
|
||
itemToRemove = item;
|
||
} else {
|
||
if (typeof item === 'string') {
|
||
itemToRemove = this.items.find("id", item.id);
|
||
} else if (typeof item === 'number') {
|
||
itemToRemove = this.items.get(item);
|
||
}
|
||
}
|
||
if (itemToRemove) {
|
||
if (itemToRemove instanceof PMUI.form.Field) {
|
||
if (this.form) {
|
||
this.form.data.removeItem(itemToRemove.data);
|
||
}
|
||
}
|
||
FormPanel.superclass.prototype.removeItem.call(this, itemToRemove);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns true if the validation passes otherwise it returns false.
|
||
* @return {Boolean}
|
||
*/
|
||
FormPanel.prototype.isValid = function () {
|
||
var items = this.items.asArray(),
|
||
i,
|
||
valid = true;
|
||
|
||
for (i = 0; i < items.length; i += 1) {
|
||
if (items[i].disabled) {
|
||
continue;
|
||
}
|
||
valid = valid && items[i].isValid();
|
||
if (!valid) {
|
||
if (items[i] instanceof PMUI.form.Field) {
|
||
items[i].setFocus();
|
||
}
|
||
return valid;
|
||
}
|
||
}
|
||
|
||
return valid;
|
||
};
|
||
|
||
FormPanel.prototype.disable = function () {
|
||
FormPanel.superclass.prototype.disable.call(this);
|
||
if (typeof this._onAvailabilityChange === 'function') {
|
||
this._onAvailabilityChange(this, false);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
FormPanel.prototype.enable = function () {
|
||
FormPanel.superclass.prototype.enable.call(this);
|
||
if (typeof this._onAvailabilityChange === 'function') {
|
||
this._onAvailabilityChange(this, true);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.form.FormPanel', FormPanel);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = FormPanel;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.form.Form
|
||
* @extends PMUI.core.Panel
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var f;
|
||
* $(function() {
|
||
* f = new PMUI.form.Form({
|
||
* onSubmit: function() {
|
||
* console.log("submitting...");
|
||
* },
|
||
* onChange: function(field, newValue, previousValue) {
|
||
* console.log("The field " + field.getName() + " has changed from \"" + previousValue + "\" to \"" + newValue + "\"");
|
||
* },
|
||
* items: [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Name",
|
||
* id: "123",
|
||
* value: "",
|
||
* placeholder: "insert your name",
|
||
* name: "name",
|
||
* helper: "Introduce your name",
|
||
* required : true,
|
||
* controlsWidth: 200
|
||
* },
|
||
* {
|
||
* pmType: "datetime",
|
||
* visible : false,
|
||
* label: "birth date",
|
||
* name: "birthdate"
|
||
* },
|
||
* {
|
||
* pmType: "dropdown",
|
||
* label: "age",
|
||
* options: [
|
||
* {
|
||
* label: "",
|
||
* value: ""
|
||
* },
|
||
* {
|
||
* label: "from 0 to 7 years old",
|
||
* value: "0-7"
|
||
* },
|
||
* {
|
||
* label: "from 8 to 13 years old",
|
||
* value: "8-13"
|
||
* },
|
||
* {
|
||
* label: "from 14 to 19 years old",
|
||
* value: "14-19"
|
||
* },
|
||
* {
|
||
* label: "from 20 to 30 years old",
|
||
* value: "20-30"
|
||
* },
|
||
* {
|
||
* label: "from 31 to 45 years old",
|
||
* value: "31-45"
|
||
* },
|
||
* {
|
||
* label: "older than 45",
|
||
* value: "46+"
|
||
* }
|
||
* ],
|
||
* name: "age",
|
||
* helper: "Select one of the options",
|
||
* required: true,
|
||
* onChange: function() {
|
||
* console.log("The value has been changed");
|
||
* },
|
||
* controlsWidth: 100
|
||
* },
|
||
* {
|
||
* pmType: "radio",
|
||
* label: "Gender",
|
||
* value: "m",
|
||
* name: "gender",
|
||
* required: true,
|
||
* options: [
|
||
* {
|
||
* label: "Male",
|
||
* value: "m"
|
||
* },
|
||
* {
|
||
* label: "Female",
|
||
* value: "f"
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* pmType: "text",
|
||
* label: "E-mail",
|
||
* value: "",
|
||
* name: "email",
|
||
* helper: "you email here",
|
||
* required: true,
|
||
* validators: [
|
||
* {
|
||
* pmType: "regexp",
|
||
* criteria: /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
|
||
* errorMessage: "Please enter a valid email address"
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* pmType: "checkbox",
|
||
* label: "Things you like to do",
|
||
* value: "[\"music\"]",
|
||
* name: "hobbies",
|
||
* helper: "Check up to 3 options",
|
||
* options: [
|
||
* {
|
||
* label: "Music",
|
||
* value: "music"
|
||
* },
|
||
* {
|
||
* label: "Programming",
|
||
* value: "programming"
|
||
* },
|
||
* {
|
||
* label: "Bike ridding",
|
||
* value: "bike"
|
||
* },
|
||
* {
|
||
* label: "Gastronomy",
|
||
* value: "gastronomy"
|
||
* },
|
||
* {
|
||
* label: "Movies",
|
||
* value: "movies"
|
||
* }
|
||
* ],
|
||
* validators: [],
|
||
* required: true
|
||
* },
|
||
* {
|
||
* pmType: "panel",
|
||
* fieldset: true,
|
||
* legend: "Another Info",
|
||
* layout: "vbox",
|
||
* items: [
|
||
* {
|
||
* pmType: "panel",
|
||
* layout: 'hbox',
|
||
* items: [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Country",
|
||
* value: "Bolivia",
|
||
* name: "country"
|
||
* },
|
||
* {
|
||
* pmType: "text",
|
||
* label: "City",
|
||
* name: "city"
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* pmType: "panel",
|
||
* layout: 'hbox',
|
||
* items: [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Address",
|
||
* name: "address",
|
||
* placeholder: "Your address here"
|
||
* },
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Zip Code",
|
||
* name: "zip"
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* pmType: "panel",
|
||
* layout: 'vbox',
|
||
* items: [
|
||
* {
|
||
* pmType: "textarea",
|
||
* label: "About you",
|
||
* name: "about"
|
||
* }
|
||
* ]
|
||
* }
|
||
* ]
|
||
* }
|
||
* ],
|
||
* footerItems: [
|
||
* {
|
||
* pmType: "button",
|
||
* text: "Submit",
|
||
* handler: function() {
|
||
* f.submit();
|
||
* console.log("submitting form...");
|
||
* }
|
||
* }, {
|
||
* pmType: "button",
|
||
* text: "Reset",
|
||
* handler: function() {
|
||
* f.reset();
|
||
* }
|
||
* }
|
||
* ]
|
||
* });
|
||
* document.body.appendChild(f.getHTML());
|
||
* });
|
||
*
|
||
* The example above will generate a form with 8 fields:
|
||
* Name, Last Name, E-mail, Phone, Country, City, Address, Zip Code.
|
||
* The first four ones are required and each one has a helper.
|
||
* The email and Phone fields also have a validator for control the input.
|
||
*
|
||
* The latest four ones are contained by a fieldset.
|
||
*
|
||
* @cfg {String} title The title for the form.
|
||
* @cfg {name} [name=<the object's id>] The name for the form.
|
||
* @cfg {String} [encType="application/x-www-form-urlencoded"] The value for the form's encType attribute .
|
||
* @cfg {Array} [items=[]] An array in which every element can be
|
||
* a JSON Object or a supported object by Form:
|
||
*
|
||
* - In case to be a JSON object, it should includes a "pmType" property with a valid value.
|
||
* The valid values for the pmType property are specified in the
|
||
* {@link PMUI.form.FormItemFactory FormItemFactory documentation}.
|
||
*
|
||
* - In case of objects, use an object that the {@link PMUI.form.FormItemFactory FormItemFactory} can produce.
|
||
*
|
||
* Example:
|
||
* var form, items;
|
||
*
|
||
* items = [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Name",
|
||
* id: "123",
|
||
* value: "",
|
||
* placeholder: "insert your name",
|
||
* name: "name",
|
||
* helper: "Introduce your name",
|
||
* required: true
|
||
* },
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Last name",
|
||
* value: "",
|
||
* placeholder: "your lastname here asshole!",
|
||
* name: "lastname",
|
||
* helper: "Introduce your lastname",
|
||
* required: true
|
||
* }
|
||
* ];
|
||
*
|
||
* form = new PMUI.form.Form({
|
||
* name: "My form",
|
||
* items: items
|
||
* });
|
||
*
|
||
* Depending on the type of element you add, it can contain a nested items property to define its child items:
|
||
*
|
||
* f = new PMUI.form.Form({
|
||
* items: [
|
||
* .......
|
||
* {
|
||
* pmType: "panel",
|
||
* fieldset: true,
|
||
* legend: "Another Info",
|
||
* layout: "vbox",
|
||
* items: [
|
||
* {
|
||
* pmType: "panel",
|
||
* layout: 'hbox',
|
||
* items: [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Country",
|
||
* value: "Bolivia",
|
||
* name: "country"
|
||
* },
|
||
* {
|
||
* pmType: "text",
|
||
* label: "City",
|
||
* name: "city"
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* pmType: "panel",
|
||
* layout: 'hbox',
|
||
* items: [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Address",
|
||
* name: "address",
|
||
* placeholder: "Your address here"
|
||
* },
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Zip Code",
|
||
* name: "zip"
|
||
* }
|
||
* ]
|
||
* }
|
||
* ]
|
||
* }
|
||
* ]
|
||
* });
|
||
*
|
||
* As you can see in the example above, only the container type objects can have an "item" property.
|
||
*
|
||
* @cfg {Number} [fontSize=12] The size to be use for the font in the form.
|
||
* @cfg {Number} [width=600] The width for the form.
|
||
* In case of using a String you only can use 'auto' or 'inherit' or ##px or ##% or ##em when ## is a number.
|
||
* @cfg {Number} [height=400] The height for the form.
|
||
* In case of using a String you only can use 'auto' or 'inherit' or ##px or ##% or ##em when ## is a number.
|
||
* @cfg {Boolean} [visibleHeader=true] If the header is visible or not.
|
||
* @cfg {String} [layout='vbox'] The layout type to apply to the form.
|
||
* @cfg {Array} [buttons=[]] An array in which each element is JSON Object or a
|
||
* {@link Form.ui.Button Button object}
|
||
* @deprecated This config option will be removed soon, please use the {@link #cfg-footerItems footerItems} config
|
||
* option instead.
|
||
* @cfg {Function} [onChange=null] A callback function to be called everytime a form's field changes.
|
||
* This callback function will be called in the current object context and will receive three parameters:
|
||
*
|
||
* - The field that changed.
|
||
* - The new field's value.
|
||
* - The previous field's value.
|
||
*
|
||
* var f = new PMUI.form.Form({
|
||
* onChange: function(field, newValue, previousValue) {
|
||
* console.log("Action in the form named \"" + this.getName() + "\":");
|
||
* console.log("The field " + field.getName() + " has changed from \"" + previousValue +
|
||
"\" to \"" + newValue + "\"");
|
||
* },
|
||
* ......
|
||
* };
|
||
*
|
||
* @cfg {Function} [onSubmit=null] A callback function to be called when the form is submitted.
|
||
* This callback function will be called in the form object context.
|
||
*
|
||
* var f = new PMUI.form.Form({
|
||
* onSubmit: function() {
|
||
* console.log("Submitting the form named \"" + this.getName() + "\"...");
|
||
* },
|
||
* ......
|
||
* };
|
||
* @cfg {Array} [footerItems=[]] Sets the elements in the window footer, this elements can be instances of Button
|
||
* and/or instances of Label. The value for this config option must be an array in which each element can be:
|
||
*
|
||
* - An object literal, in this case the object literal must have the property "pmType" with its value set to
|
||
* "button" (if you want the element be a {@link PMUI.ui.Button Button}) or "label" (if you want the element be a
|
||
* {@link PMUI.ui.TextLabel Label}). Optionally you can add the respective config options for each case.
|
||
*
|
||
* - A PMUI object, in this case it must be an instance of {@link PMUI.ui.Button Button} or an instance of
|
||
* {@link PMUI.ui.TextLabel Label}.
|
||
* @cfg {Function} [onLoad=null] The callback function to be executed when the form is ready to use. for info about
|
||
* the parameters received by the callback please read the {@link #event-onLoad onLoad event} documentation.
|
||
* @cfg {Srting} [buttonPanelPosition='bottom'] The position for the form's footer. It can be 'bottom' or 'top'.
|
||
*/
|
||
var Form = function (settings) {
|
||
Form.superclass.call(this, settings);
|
||
/**
|
||
* The name for the form
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.name = null;
|
||
/**
|
||
* The form's encType property
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.encType = null;
|
||
/**
|
||
* The text for the form's title.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.title = null;
|
||
/**
|
||
* The size for the font in the form.
|
||
* @type {Number}
|
||
* @readonly
|
||
*/
|
||
this.fontSize = null;
|
||
/**
|
||
* If the header is visible or not.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.visibleHeader = null;
|
||
/**
|
||
* The callback function to be called when a form's field changes.
|
||
* @type {Function}
|
||
*/
|
||
this.onChange = null;
|
||
/**
|
||
* The callback functionto be called when the form is submitted.
|
||
* @type {Function}
|
||
*/
|
||
this.onSubmit = null;
|
||
/**
|
||
* The form's data object.
|
||
* @type {PMUI.data.DataSet}
|
||
* @private
|
||
*/
|
||
this.data = null;
|
||
/**
|
||
* The DOM object that plays the role of title container in the form.
|
||
* @type {HTMLElement}
|
||
* @private
|
||
*/
|
||
this.header = null;
|
||
/**
|
||
* The form footer.
|
||
* @type {PMUI.panel.ButtonPanel}
|
||
* @private
|
||
*/
|
||
this.footer = null;
|
||
/**
|
||
* The height for the footer area in the Form
|
||
* @type {Number}
|
||
* @readonly
|
||
*/
|
||
this.footerHeight = null;
|
||
/**
|
||
* @event onLoad
|
||
* Fired when the form is ready to use.
|
||
* @param {PMUI.form.Form} form The form.
|
||
*/
|
||
this.onLoad = null;
|
||
/**
|
||
* If the form is dirty.
|
||
* @type {Boolean}
|
||
*/
|
||
this.dirty = null;
|
||
this._requiredFieldNotification = null;
|
||
/**
|
||
* The position for the form's footer.
|
||
* @type {String}
|
||
*/
|
||
this.buttonPanelPosition = null;
|
||
this.dependencies = {};
|
||
this.alignmentButtons = null;
|
||
Form.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Panel', Form);
|
||
|
||
Form.prototype.type = 'PMForm';
|
||
|
||
Form.prototype.family = 'PMForm';
|
||
|
||
Form.prototype.init = function (settings) {
|
||
var defaults = {
|
||
title: "Untitled form",
|
||
name: this.id,
|
||
encType: "application/x-www-form-urlencoded",
|
||
items: [],
|
||
fontSize: 12,
|
||
width: 600,
|
||
height: 400,
|
||
visibleHeader: true,
|
||
layout: 'vbox',
|
||
buttons: [],
|
||
footerItems: [],
|
||
buttonPanelPosition: 'bottom',
|
||
onChange: null,
|
||
onSubmit: null,
|
||
onLoad: null,
|
||
alignmentButtons: 'right'
|
||
};
|
||
|
||
$.extend(true, defaults, settings);
|
||
|
||
this.panel = new PMUI.form.FormPanel({
|
||
form: this,
|
||
width: defaults.width,
|
||
layout: defaults.layout,
|
||
style: {
|
||
cssProperties: {
|
||
"overflow": "auto"
|
||
}
|
||
},
|
||
onChange: this.onChangeHandler()
|
||
});
|
||
|
||
this.footer = new PMUI.panel.ButtonPanel({
|
||
style: {
|
||
cssClasses: ['pmui-form-footer']
|
||
}
|
||
});
|
||
|
||
this.data = new PMUI.data.DataSet();
|
||
|
||
this.buttons = new PMUI.util.ArrayList();
|
||
|
||
this.visibleHeader = defaults.visibleHeader;
|
||
this.onChange = defaults.onChange;
|
||
this.onSubmit = defaults.onSubmit;
|
||
|
||
this.setLayout(defaults.layout)
|
||
.setFontSize(defaults.fontSize)
|
||
.setWidth(defaults.width)
|
||
.setTitle(defaults.title)
|
||
.setName(defaults.name)
|
||
.setEncType(defaults.encType)
|
||
.setItems(defaults.items)
|
||
.setOnLoadHandler(defaults.onLoad)
|
||
.setButtonPanelPosition(defaults.buttonPanelPosition)
|
||
.setAlignmentButtons(defaults.alignmentButtons);
|
||
|
||
//TODO tell the guys about the deprecated methods
|
||
if (defaults.footerItems && defaults.footerItems.length) {
|
||
this.setFooterItems(defaults.footerItems);
|
||
} else {
|
||
this.setButtons(defaults.buttons);
|
||
}
|
||
if (typeof this.onLoad === 'function') {
|
||
this.onLoad(this);
|
||
}
|
||
};
|
||
|
||
Form.prototype.updateDependencies = function () {
|
||
var dependencies = {},
|
||
i,
|
||
j,
|
||
fields = this.getFields(),
|
||
dependent,
|
||
dependents;
|
||
|
||
for (i = 0; i < fields.length; i += 1) {
|
||
dependents = fields[i].dependentFields;
|
||
for (j = 0; j < dependents.length; j += 1) {
|
||
if (this.getField(dependents[j])) {
|
||
if (!dependencies[dependents[j]]) {
|
||
dependencies[dependents[j]] = [];
|
||
}
|
||
dependencies[dependents[j]].push(fields[i]);
|
||
}
|
||
}
|
||
}
|
||
this.dependencies = dependencies;
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* Sets the position for the form's footer.
|
||
* @param {String} position A string with the text 'bottom' or 'top', this sets the position for the form's footer.
|
||
*/
|
||
Form.prototype.setButtonPanelPosition = function (position) {
|
||
if (position === 'top' || position === 'bottom') {
|
||
this.buttonPanelPosition = position;
|
||
if (this.html) {
|
||
if (position === 'top') {
|
||
this.html.insertBefore(this.footer.html, this.panel.html);
|
||
} else {
|
||
this.html.appendChild(this.footer.html);
|
||
}
|
||
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback to be executed when the {@link #event-onLoad onLoad event} is fired.
|
||
* @param {Function|null} handler The callback function or the null constant, in the latter case no callback
|
||
* function will be executed.
|
||
* @chainable
|
||
*/
|
||
Form.prototype.setOnLoadHandler = function (handler) {
|
||
if (!(typeof handler === 'function' || handler === null)) {
|
||
throw new Error('setOnLoadHandler(): the parameter must be a function or null.');
|
||
}
|
||
this.onLoad = handler;
|
||
return this;
|
||
}
|
||
/**
|
||
* Removes an iten from the form's footer.
|
||
* @param {PMUI.core.Element|String|Number} item It can be a string (id of the child to remove),
|
||
a number (index of the child to remove) or a {Element} object.
|
||
* @chainable
|
||
*/
|
||
Form.prototype.removeFooterItem = function (item) {
|
||
this.footer.removeItem(item);
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes all the items in the form's footer.
|
||
* @chainable
|
||
*/
|
||
Form.prototype.clearFooterItems = function () {
|
||
this.footer.clearItems();
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds an item into the forms footer.
|
||
* @param {Object|PMUI.ui.Button|PMUI.ui.Button} item It can be:
|
||
*
|
||
* - An object literal, in this case it can have the config options for create a {@link PMUI.ui.Button Button} or a
|
||
* {@link PMUI.ui.TextLabel Label}, additionally it must include the respective pmType ('button' for Button and 'label'
|
||
* for Label).
|
||
*
|
||
* -A PMUI object, in this case it must be an instance of {@link PMUI.ui.Button Button} or an instance of {@link
|
||
* PMUI.ui.TextLabel Label}.
|
||
*/
|
||
Form.prototype.addFooterItem = function (item) {
|
||
this.footer.addItem(item);
|
||
this.showFooter();
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the items to be shown in the form's footer.
|
||
* @param {Array} items An array in which each element can be:
|
||
*
|
||
* - An object literal, in this case it can have the config options for create a {@link PMUI.ui.Button Button} or a
|
||
* {@link PMUI.ui.TextLabel Label}, additionally it must include the respective pmType ('button' for Button and 'label'
|
||
* for Label).
|
||
*
|
||
* -A PMUI object, in this case it must be an instance of {@link PMUI.ui.Button Button} or an instance of {@link
|
||
* PMUI.ui.TextLabel Label}.
|
||
*/
|
||
Form.prototype.setFooterItems = function (items) {
|
||
var i;
|
||
|
||
if (!jQuery.isArray(items)) {
|
||
throw new Error('setFooterItems(): The parameter must be an array.');
|
||
}
|
||
this.clearFooterItems();
|
||
this.hideFooter();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
this.addFooterItem(items[i]);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* The method which sets the internal callback function for the onChange event.
|
||
* @return {Function}
|
||
* @private
|
||
*/
|
||
Form.prototype.onChangeHandler = function () {
|
||
var that = this;
|
||
return function (field, newValue, previousValue) {
|
||
if (field.initialValue === newValue) {
|
||
that.dirty = false;
|
||
} else {
|
||
that.dirty = true;
|
||
}
|
||
if (typeof that.onChange === 'function') {
|
||
that.onChange(field, newValue, previousValue);
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Sets the form to dirty/clean.
|
||
* @param {Boolean} dirty True to set the form to dirty, False to set it to clean.
|
||
* @chainable
|
||
*/
|
||
Form.prototype.setDirty = function (dirty) {
|
||
this.dirty = !!dirty;
|
||
return this;
|
||
};
|
||
/**
|
||
* Check if the form is dirty
|
||
* @return {Boolean} Returns true if the for is dirty, otherwise it returns false.
|
||
*/
|
||
Form.prototype.isDirty = function () {
|
||
return this.dirty;
|
||
};
|
||
/**
|
||
* Removes any button previously added to the form.
|
||
* @param {String|Number|PMUI.ui.Button} button
|
||
* This param can be:
|
||
* - String: in that case the string must be the id of the button to remove.
|
||
* - Number: in that case the number is evaluated as the index of the button to remove.
|
||
* - Button: the button to remove.
|
||
* @chainable
|
||
* @deprecated This method will be removed soon, please use the {@link #method-removeFooterItem removeFooterItem()}
|
||
* method instead.
|
||
*/
|
||
Form.prototype.removeButton = function (button) {
|
||
return this.removeFooterItem(button);
|
||
};
|
||
/**
|
||
* Remove all the buttons from the form.
|
||
* @chainable
|
||
* @deprecated This method will be removed soon, please use the {@link #method-clearFooterItems clearFooterItems()}
|
||
* method instead.
|
||
*/
|
||
Form.prototype.clearButtons = function () {
|
||
return this.clearFooterItems();
|
||
};
|
||
/**
|
||
* Adds a button into the form. The button will be added to the form's footer.
|
||
* @param {Object|PMUI.ui.Button} button
|
||
* It can be a:
|
||
*
|
||
* - {@link PMUI.ui.Button Button} object.
|
||
* - JSON Object: use the same JSON structure for create {@link PMUI.ui.Button Button} objects.
|
||
*
|
||
* @chainable
|
||
* @deprecated This method will be removed soon, please use the {@link #method-addFooterItem addFooterItem()}
|
||
* method instead.
|
||
*/
|
||
Form.prototype.addButton = function (button) {
|
||
return this.addFooterItem(button);
|
||
};
|
||
/**
|
||
* Sets the buttons for the form. They will be added to the footer.
|
||
* @param {Array} buttons An array in which each element is a JSON object or a {@link PMUI.ui.Button Button}.
|
||
* @chainable
|
||
* @deprecated This method will be removed soon, please use the {@link #method-setFooterItems setFooterItems()}
|
||
* method instead.
|
||
*/
|
||
Form.prototype.setButtons = function (buttons) {
|
||
return this.setFooterItems(buttons);
|
||
};
|
||
/**
|
||
* Updates the dimensions for the form's areas.
|
||
* @chainable
|
||
*/
|
||
Form.prototype.updateDimensions = function () {
|
||
var headerHeight = 0,
|
||
footerHeight = 0,
|
||
bodyHeight;
|
||
|
||
if (!this.panel) {
|
||
return this;
|
||
}
|
||
if (this.getHeight() !== 'auto') {
|
||
if (this.visibleHeader && this.title) {
|
||
headerHeight = 2 * this.fontSize;
|
||
}
|
||
if (this.footer.getItems().length) {
|
||
footerHeight = (1.7 * this.fontSize) + 12;
|
||
}
|
||
bodyHeight = this.getHeight() - headerHeight - footerHeight;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the form's height.
|
||
* @param {Number|String} height it can be a number or a string.
|
||
* In case of using a String you only can use 'auto' or 'inherit' or ##px or ##% or ##em when ## is a number
|
||
* @chainable
|
||
*/
|
||
Form.prototype.setHeight = function (height) {
|
||
Form.superclass.prototype.setHeight.call(this, height);
|
||
this.updateDimensions();
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the form's width.
|
||
* @param {Number|String} width it can be a number or a string.
|
||
* In case of using a String you only can use 'auto' or 'inherit' or ##px or ##% or ##em when ## is a number
|
||
* @chainable
|
||
*/
|
||
Form.prototype.setWidth = function (width) {
|
||
Form.superclass.prototype.setWidth.call(this, width);
|
||
this.updateDimensions();
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the size for the font toi be used in the form.
|
||
* @param {Number} fontSize
|
||
*/
|
||
Form.prototype.setFontSize = function (fontSize) {
|
||
if (typeof fontSize === 'number') {
|
||
this.fontSize = fontSize;
|
||
this.style.addProperties({
|
||
"font-size": fontSize + "px"
|
||
});
|
||
this.updateDimensions();
|
||
} else {
|
||
throw new Error("setFontSize(): this method only accepts a number as parameter.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns a field from the form.
|
||
* @param {String} name The name of the field to find.
|
||
* @return {PMUI.form.Field|null}
|
||
*/
|
||
Form.prototype.getField = function (name) {
|
||
return this.panel.getField(name);
|
||
};
|
||
/**
|
||
* Returns all the fields contained by the form.
|
||
* @return {Array} An array in which each element is a {PMUI.form.Field}.
|
||
*/
|
||
Form.prototype.getFields = function () {
|
||
return this.panel.getItems("fields", true);
|
||
};
|
||
/**
|
||
* Returns the items from the form's body.
|
||
* @return {Array} An array with all the form's items.
|
||
*/
|
||
Form.prototype.getItems = function () {
|
||
return this.panel.getItems();
|
||
};
|
||
/**
|
||
* Sets the layout mode for the form's root panel.
|
||
* @param {String} layout it can take one of the following values:
|
||
*
|
||
* - "vbox" for vertical positioning.
|
||
* - "hbox" for horizontal positioning.
|
||
* - "box" without layout.
|
||
*/
|
||
Form.prototype.setLayout = function (layout) {
|
||
var factory;
|
||
|
||
if (this.panel) {
|
||
factory = new PMUI.layout.LayoutFactory();
|
||
this.panel.layout = factory.make(layout);
|
||
this.panel.layout.setContainer(this.panel);
|
||
if (this.html) {
|
||
this.panel.layout.applyLayout();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds an item to the form's root panel. It only creates one of
|
||
* the {@link PMUI.form.FormItemFactory FormItemFactory} supported products.
|
||
* @param {String|Object|PMUI.form.FormPanel|PMUI.form.Field} item
|
||
* It can accept one of the following data types:
|
||
*
|
||
* - a String: one of the supported pmTypes by the {@link PMUI.form.FormItemFactory FormItemFactory} object.
|
||
* - a JSON Object: use the JSON structure the object's constructor needs, additionally add the pmType property,
|
||
* you can use any of the pmTypes supported by the {@link PMUI.form.FormItemFactory FormItemFactory}.
|
||
* - a {@link PMUI.form.FormPanel FormPanel} object.
|
||
* - a{@link PMUI.form.Field Field} object
|
||
*/
|
||
Form.prototype.addItem = function (item) {
|
||
if (this.panel) {
|
||
this.panel.addItem(item);
|
||
this.updateDependencies();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Set items for the form's root panel.
|
||
* @param {Array} items An array in which each element can be one of the accepted parameters
|
||
* in the {@link PMUI.form.Form#addItem addItem() method}.
|
||
* @chainable
|
||
*/
|
||
Form.prototype.setItems = function (items) {
|
||
if (this.panel) {
|
||
this.panel.setItems(items);
|
||
this.updateDependencies();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns all the form's direct items.
|
||
* @param {String|Number} id If the parameter is a string then
|
||
* it will be take as the id for the element to find and return,
|
||
* but if the element is a Number it will return the object with that
|
||
* index position.
|
||
* @returns {Object}
|
||
*/
|
||
Form.prototype.getItem = function (i) {
|
||
return Form.superclass.prototype.getItem.call(this.panel, i);
|
||
};
|
||
/**
|
||
* Sets the title text for the form.
|
||
* @param {String} title
|
||
* @chainable
|
||
*/
|
||
Form.prototype.setTitle = function (title) {
|
||
if (typeof title === 'string') {
|
||
this.title = title;
|
||
if (this.header) {
|
||
$(this.header).empty();
|
||
if (title) {
|
||
$(this.header).append('<h2 class="pmui-form-title"></h2>').find('h2').text(title);
|
||
} else {
|
||
$(this.header).append('<h2 class="pmui-form-title"></h2>').find('h2').html(" ");
|
||
}
|
||
this.updateDimensions();
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the name for the form
|
||
* @param {String} name
|
||
* @chainable
|
||
*/
|
||
Form.prototype.setName = function (name) {
|
||
this.name = name;
|
||
if (this.html) {
|
||
this.html.name = name;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the enctype property for the form
|
||
* @param {String} encType
|
||
* @chainable
|
||
*/
|
||
Form.prototype.setEncType = function (encType) {
|
||
this.encType = encType;
|
||
if (this.html) {
|
||
this.html.setAttribute("encType", encType);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows the form header
|
||
* @chainable
|
||
*/
|
||
Form.prototype.showHeader = function () {
|
||
this.visibleHeader = true;
|
||
this.header.style.display = "";
|
||
this.updateDimensions();
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Hides the form's header
|
||
* @chainable
|
||
*/
|
||
Form.prototype.hideHeader = function () {
|
||
this.visibleHeader = false;
|
||
this.header.style.display = "none";
|
||
this.updateDimensions();
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns true if all the form's fields assert the their validations otherwise returns false.
|
||
* @return {Boolean}
|
||
*/
|
||
Form.prototype.isValid = function () {
|
||
var res = this.panel.isValid();
|
||
|
||
if (res) {
|
||
this.hideRequiredFieldNotification();
|
||
} else {
|
||
this.showRequiredFieldNotification();
|
||
}
|
||
|
||
return res;
|
||
};
|
||
/**
|
||
* Submits the form.
|
||
* @chainable
|
||
*/
|
||
Form.prototype.submit = function () {
|
||
if (this.isValid()) {
|
||
if (typeof this.onSubmit === 'function') {
|
||
this.onSubmit(this.getData());
|
||
}
|
||
//TODO: call send() method from proxy
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Resets the form to their initial values.
|
||
* @chainable
|
||
*/
|
||
Form.prototype.reset = function () {
|
||
var fields,
|
||
i;
|
||
|
||
fields = this.getFields();
|
||
for (i = 0; i < fields.length; i += 1) {
|
||
fields[i].reset();
|
||
}
|
||
if (this.dirty) {
|
||
this.dirty = false;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the form's data.
|
||
* @param {String} [format='object'] The format in which the data will be returned, it can take three values:
|
||
*
|
||
* - 'xml', the data will be returned in xml format.
|
||
* - 'json', the data will be returned in a json-formated string.
|
||
* - 'object', the data will be returned in a object literal format.
|
||
* - otherwise or nothing, the data will be returned in a object literal format but only containing the name and values from
|
||
* fields.
|
||
* @return {Object|String} The data type of the returned item will depend on the input parameter, please read the
|
||
* method description for more info.
|
||
*/
|
||
Form.prototype.getData = function (format) {
|
||
var fields,
|
||
i,
|
||
res,
|
||
data = new PMUI.data.DataSet();
|
||
|
||
fields = this.getFields();
|
||
if (format !== 'xml' && format !== 'json' && format !== 'object') {
|
||
res = {};
|
||
for (i = 0; i < fields.length; i += 1) {
|
||
if (!fields[i].disabled) {
|
||
res[fields[i].getName()] = fields[i].getValue();
|
||
}
|
||
}
|
||
} else {
|
||
for (i = 0; i < fields.length; i += 1) {
|
||
if (!fields[i].disabled) {
|
||
data.addItem(fields[i].data);
|
||
}
|
||
}
|
||
if (format === 'xml') {
|
||
return data.getXML();
|
||
} else if (format === 'json') {
|
||
return data.getJSON();
|
||
} else if (format === 'object') {
|
||
return data.getData();
|
||
}
|
||
}
|
||
return res;
|
||
};
|
||
Form.prototype.hideRequiredFieldNotification = function () {
|
||
if (this._requiredFieldNotification) {
|
||
this._requiredFieldNotification.style.display = 'none';
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Form.prototype.showRequiredFieldNotification = function () {
|
||
if (this._requiredFieldNotification) {
|
||
this._requiredFieldNotification.style.display = '';
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Define the event listeners for the form.
|
||
* @chainable
|
||
*/
|
||
Form.prototype.defineEvents = function () {
|
||
var that = this;
|
||
|
||
if (this.html && !this.eventsDefined) {
|
||
this.panel.defineEvents();
|
||
this.footer.defineEvents();
|
||
this.addEvent('submit').listen(this.html, function (e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
});
|
||
this.panel.setOnAvailabilityChange(function () {
|
||
that.isValid();
|
||
});
|
||
this.eventsDefined = true;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the HTML for the form.
|
||
* @return {HTMLElement}
|
||
*/
|
||
Form.prototype.createHTML = function () {
|
||
var html,
|
||
header,
|
||
notificationArea,
|
||
notification,
|
||
notificationText = "Fields marked with an asterisk (%%ASTERISK%%) are required.".translate()
|
||
.replace(/%%ASTERISK%%/g, '<span style="color: #e84c3d">*</span>');
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
html = PMUI.createHTMLElement('form');
|
||
html.id = this.id;
|
||
html.className = 'pmui-form';
|
||
|
||
header = PMUI.createHTMLElement('div');
|
||
header.className = 'pmui-form-header';
|
||
|
||
notification = new PMUI.field.TextAnnotationField({
|
||
id: "requiredMessage",
|
||
name: "Message",
|
||
textType: PMUI.field.TextAnnotationField.TEXT_TYPES.HTML,
|
||
text: notificationText,
|
||
text_Align: "center"
|
||
});
|
||
notificationArea = PMUI.createHTMLElement('div');
|
||
notificationArea.style.display = 'none';
|
||
notificationArea.appendChild(notification.getHTML());
|
||
this._requiredFieldNotification = notificationArea;
|
||
|
||
this.header = header;
|
||
|
||
html.appendChild(header);
|
||
html.appendChild(this.panel.getHTML());
|
||
html.appendChild(notificationArea);
|
||
html.appendChild(this.footer.getHTML());
|
||
this.html = html;
|
||
|
||
this.setTitle(this.title)
|
||
.setName(this.name)
|
||
.setEncType(this.encType);
|
||
|
||
if (this.visibleHeader) {
|
||
this.showHeader();
|
||
} else {
|
||
this.hideHeader();
|
||
}
|
||
|
||
this.panel.setPadding('20px 10px 20px 10px');
|
||
|
||
this.style.applyStyle();
|
||
if (this.layout) {
|
||
this.layout.applyLayout();
|
||
}
|
||
if (this.getFields().length && this.setFocus) {
|
||
this.setFocus(0);
|
||
}
|
||
this.setButtonPanelPosition(this.buttonPanelPosition);
|
||
|
||
this.defineEvents();
|
||
|
||
return this.html;
|
||
};
|
||
/**
|
||
* clean all form fields
|
||
* @chainable
|
||
*/
|
||
Form.prototype.clearItems = function () {
|
||
this.panel.clearItems();
|
||
return this;
|
||
};
|
||
/**
|
||
* clear all form fields
|
||
* @chainable
|
||
*/
|
||
Form.prototype.removeItem = function (item) {
|
||
var i = 0;
|
||
Form.superclass.prototype.removeItem.call(this, item);
|
||
this.panel.removeItem(item);
|
||
return this;
|
||
};
|
||
/**
|
||
* hides the footer where the buttons are located
|
||
* @chainable
|
||
*/
|
||
Form.prototype.hideFooter = function () {
|
||
this.footer.setVisible(false);
|
||
return this;
|
||
};
|
||
/**
|
||
* shows the footer where the buttons are located
|
||
* @chainable
|
||
*/
|
||
Form.prototype.showFooter = function () {
|
||
this.footer.setVisible(true);
|
||
return this;
|
||
};
|
||
/**
|
||
* @method setFocus
|
||
* set the focus on a form field
|
||
* @chainable
|
||
*/
|
||
Form.prototype.setFocus = function () {
|
||
var j,
|
||
fields = this.getFields();
|
||
|
||
for (j = 0; j < fields.length; j += 1) {
|
||
if ((!fields[j].isReadOnly || !fields[j].isReadOnly()) && !fields[j].disabled && fields[j].isVisible() && fields[j].setFocus) {
|
||
fields[j].setFocus();
|
||
break;
|
||
}
|
||
}
|
||
return this;
|
||
}
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = Form;
|
||
}
|
||
Form.prototype.setAlignmentButtons = function (value) {
|
||
if (typeof value == "string") {
|
||
this.alignmentButtons = value;
|
||
this.footer.setAlignment(value);
|
||
return this;
|
||
}
|
||
throw new Error('setAlignmentButtons(), the value is no type valid')
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.form.Form', Form);
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.form.Validator
|
||
* Handles the validations of the fields
|
||
* @extend PMUI.core.Base
|
||
*
|
||
* @constructor
|
||
* Create a new instance of the class
|
||
* @param {Object} settings
|
||
* @param {PMUI.form.Field} parent
|
||
*
|
||
* @cfg {*} [criteria=null] This is the criteria info to execute the validation,
|
||
* each validator needs a different data type criteria,
|
||
* so please read about the criteria config option for every validator object.
|
||
* @cfg {String} [errorMessage='the validation has failed'] This property defines
|
||
* the error message to display if validation fails when filled fields
|
||
* @cfg {PMUI.form.Field} [parent=null] Defines the field the validator belongs to.
|
||
*/
|
||
var Validator = function (settings) {
|
||
|
||
Validator.superclass.call(this, settings);
|
||
/**
|
||
* Defines the Field parent
|
||
* @type {PMUI.form.Field}
|
||
*/
|
||
this.parent = null;
|
||
/**
|
||
* Defines the criteria object
|
||
* @type {Object}
|
||
*/
|
||
this.criteria = null;
|
||
/**
|
||
* Defines if the object is validated
|
||
* @type {Boolean}
|
||
*/
|
||
this.validated = false;
|
||
/**
|
||
* Defines the validation state
|
||
* @type {null/Boolean}
|
||
*/
|
||
this.valid = null;
|
||
/**
|
||
* Defines the error message to show in case of the validation fails
|
||
* @type {null/Boolean}
|
||
*/
|
||
this.errorMessage = null;
|
||
|
||
Validator.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Base', Validator);
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
Validator.prototype.type = 'Validator';
|
||
/**
|
||
* Defines the object's family
|
||
* @type {String}
|
||
*/
|
||
Validator.prototype.family = 'Validator';
|
||
/**
|
||
* Initializes the object with default values
|
||
* @param {Object} settings
|
||
* @param {PMUI.form.Field} parent
|
||
*/
|
||
Validator.prototype.init = function (settings) {
|
||
var defaults = {
|
||
criteria: null,
|
||
errorMessage: 'the validation has failed',
|
||
parent: null
|
||
};
|
||
jQuery.extend(true, defaults, settings);
|
||
this.setCriteria(defaults.criteria)
|
||
.setParent(defaults.parent)
|
||
.setErrorMessage(defaults.errorMessage);
|
||
};
|
||
/**
|
||
* Sets the validation error message to show in case of the validation fails
|
||
* @param {String} errorMessage
|
||
* @chainable
|
||
*/
|
||
Validator.prototype.setErrorMessage = function (errorMessage) {
|
||
this.errorMessage = errorMessage;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the validation error message to show in case of the validation fails
|
||
* @param {String} errorMessage
|
||
* @chainable
|
||
*/
|
||
Validator.prototype.getErrorMessage = function () {
|
||
return this.errorMessage;
|
||
};
|
||
/**
|
||
* Sets the validation criteria
|
||
* @param {Object} criteria
|
||
* @chainable
|
||
*/
|
||
Validator.prototype.setCriteria = function (criteria) {
|
||
this.criteria = criteria;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the parent field
|
||
* @param {PMUI.form.Field|GridControlCell} parent
|
||
* @chainable
|
||
*/
|
||
Validator.prototype.setParent = function (parent) {
|
||
if (parent) {
|
||
if (parent instanceof PMUI.form.Field || parent instanceof PMUI.grid.GridControlCell) {
|
||
this.parent = parent;
|
||
} else {
|
||
throw new Error("setParent() method only accepts a Field object as parameter.");
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the parent field
|
||
* @return {PMUI.form.Field}
|
||
*/
|
||
Validator.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
/**
|
||
* Evaluates the validator
|
||
*/
|
||
Validator.prototype.validate = function () {
|
||
this.valid = true;
|
||
};
|
||
/**
|
||
* Returns the validation response
|
||
* @chainable
|
||
*/
|
||
Validator.prototype.isValid = function () {
|
||
this.validate();
|
||
this.updateTooltip();
|
||
return this.valid;
|
||
};
|
||
/**
|
||
* Updates de the tooltip message
|
||
*/
|
||
Validator.prototype.updateTooltip = function () {
|
||
if (this.parent && this.parent.message) {
|
||
if (this.valid) {
|
||
this.parent.hideMessage();
|
||
} else {
|
||
this.parent.showMessage(this.errorMessage, "error");
|
||
}
|
||
}
|
||
};
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = Validator;
|
||
}
|
||
|
||
PMUI.extendNamespace('PMUI.form.Validator', Validator);
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.form.TextLengthValidator
|
||
* @extend PMUI.form.Validator
|
||
*
|
||
* Create a new instace abstrac of the TextLengthValidator class
|
||
* @param {Object} settings
|
||
*
|
||
* @cfg {String} [errorMessage='the validation has failed'] This property defines the error
|
||
* message to display if the validation text size entered is not valid
|
||
*/
|
||
var TextLengthValidator = function (settings) {
|
||
|
||
TextLengthValidator.superclass.call(this, settings);
|
||
TextLengthValidator.prototype.init.call(this, settings);
|
||
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.form.Validator', TextLengthValidator);
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
TextLengthValidator.prototype.type = 'TextLengthValidator';
|
||
|
||
TextLengthValidator.prototype.init = function (settings) {
|
||
var maxMessage = settings.criteria.maxLength ? " at most " + settings.criteria.maxLength + " characters" : "",
|
||
minMessage = settings.criteria.minLength ? "at least " + settings.criteria.minLength + " characters" : "",
|
||
defaults = {
|
||
errorMessage: "The text length must have " + minMessage + (maxMessage ? " and " : "") + maxMessage
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setErrorMessage(defaults.errorMessage);
|
||
};
|
||
/**
|
||
* Evaluates the validator
|
||
* this method is for validate the length of the string on control the value
|
||
* input in text field, cutting spaces white in use trim of the jquery function
|
||
* @chainable
|
||
*/
|
||
TextLengthValidator.prototype.validate = function () {
|
||
var res = false,
|
||
value = this.criteria.trim ? jQuery.trim(this.parent.value) : this.parent.value;
|
||
|
||
this.valid = true;
|
||
|
||
if (this.criteria.maxLength) {
|
||
this.valid = value.length <= parseInt(this.criteria.maxLength, 10);
|
||
}
|
||
if (this.criteria.minLength) {
|
||
this.valid = (this.valid !== null ? this.valid : true) &&
|
||
value.length >= parseInt(this.criteria.minLength, 10);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.form.TextLengthValidator', TextLengthValidator);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = TextLengthValidator;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.form.RegExpValidator
|
||
* @extends PMUI.form.Validator
|
||
* A text validator based in regular expressions.
|
||
*
|
||
* Usually this object won't be instatiate directly, it will be instantiate through a
|
||
* {@link PMUI.form.Field Field} object just like is shown in the
|
||
* {@link PMUI.field.TextField TextField documentation}. We recommend to use it this way.
|
||
*
|
||
* The other way to instantiate an object from this class:
|
||
*
|
||
* var myValidator,
|
||
* field,
|
||
* callback = function() {
|
||
* this.isValid();
|
||
* };
|
||
*
|
||
* field = new PMUI.field.TextField({
|
||
* onChange: callback
|
||
* });
|
||
*
|
||
* myValidator = new RegExpValidator({
|
||
* criteria: /^\d+$/,
|
||
* errorMessage: "You must introduce only number digits."
|
||
* });
|
||
*
|
||
* field.addValidator(myValidator);
|
||
*
|
||
* document.body.appendChild(field.getHTML());
|
||
*
|
||
* @cfg {Object|RegExp} criteria The criteria config option can be:
|
||
*
|
||
* - a JSON object: in this case it must have two porperties:
|
||
* - pattern (String): the pattern string to be use as the regular expression
|
||
(don't forget to escape special characters)
|
||
* - modifiers (String): this is optional, this is the modifier for the regular expression.
|
||
* - a RegExp object
|
||
*/
|
||
var RegExpValidator = function (options) {
|
||
RegExpValidator.superclass.call(this, options);
|
||
RegExpValidator.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.form.Validator', RegExpValidator);
|
||
|
||
RegExpValidator.prototype.type = "RegExpValidator";
|
||
|
||
RegExpValidator.prototype.init = function (options) {
|
||
var defaults = {
|
||
errorMessage: "The text pattern doesn't match"
|
||
};
|
||
|
||
$.extend(true, defaults, options);
|
||
|
||
this.setErrorMessage(defaults.errorMessage);
|
||
};
|
||
/**
|
||
* Execute the validation.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
RegExpValidator.prototype.validate = function () {
|
||
var res = false,
|
||
regExp;
|
||
|
||
if (this.parent) {
|
||
if (this.criteria instanceof RegExp) {
|
||
if ((this.parent.valueType == 'integer' || this.parent.valueType == 'float' || this.parent.valueType == 'number') && !this.parent.value) {
|
||
this.valid = this.criteria.test(0);
|
||
} else {
|
||
this.valid = this.criteria.test(this.parent.value);
|
||
}
|
||
} else if (typeof this.criteria === 'string') {
|
||
regExp = new RegExp(this.criteria.pattern, this.criteria.modifiers);
|
||
this.valid = regExp.text(this.parent.value);
|
||
}
|
||
} else {
|
||
this.valid = false;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.form.RegExpValidator', RegExpValidator);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = RegExpValidator;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.form.ValidatorFactory
|
||
* @extend PMUI.util.Factory
|
||
* Extends the factory class to produce field validators.
|
||
*
|
||
* Its default products are:
|
||
*
|
||
* - {@link PMUI.form.TextLengthValidator TextLengthValidator} objects: using "textLength".
|
||
* - {@link PMUI.form.RegExpValidator RegExpValidator} objects: using "regexp".
|
||
*
|
||
* @constructor
|
||
* Creates a new instance od the class
|
||
*/
|
||
var ValidatorFactory = function () {
|
||
ValidatorFactory.superclass.call(this);
|
||
ValidatorFactory.prototype.init.call(this);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.util.Factory', ValidatorFactory);
|
||
|
||
ValidatorFactory.prototype.init = function () {
|
||
var defaults = {
|
||
products: {
|
||
"textLength": PMUI.form.TextLengthValidator,
|
||
"regexp": PMUI.form.RegExpValidator
|
||
},
|
||
defaultProduct: "textLength"
|
||
};
|
||
this.setProducts(defaults.products)
|
||
.setDefaultProduct(defaults.defaultProduct);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.form.ValidatorFactory', ValidatorFactory);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ValidatorFactory;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.panel.LayoutPanel
|
||
* @extends PMUI.core.Panel
|
||
* Handles layouts to be inserted into panels.
|
||
* It is composed by five main elements: north, south, west, east and center
|
||
*
|
||
* Example:
|
||
*
|
||
* @example
|
||
*
|
||
* layout = new PMUI.panel.LayoutPanel({
|
||
* id: "myLayout",
|
||
* center: {
|
||
* cssProperties: {
|
||
* "background-color": "#91b3e0"
|
||
* },
|
||
* cssClasses: ['my-class']
|
||
* },
|
||
* west: {
|
||
* resizable: false,
|
||
* closed: true
|
||
* },
|
||
* south: new PMUI.panel.LayoutPanel({
|
||
* north:{
|
||
* size: 50
|
||
* }
|
||
* }),
|
||
* southConfig:{
|
||
* size: 200
|
||
* },
|
||
* north: {
|
||
* size: 50,
|
||
* togglerOpen: 80,
|
||
* overflow: false
|
||
* },
|
||
* east: {
|
||
* closable: false
|
||
* }
|
||
* });
|
||
* document.body.appendChild(layout.getHTML());
|
||
* layout.render(true);
|
||
*
|
||
* @constructor
|
||
* Create a new instance of the LayoutPanel class
|
||
* @param {Object} options Contructor object
|
||
*/
|
||
var LayoutPanel = function (options) {
|
||
LayoutPanel.superclass.call(this, options);
|
||
|
||
/**
|
||
* @property {String} prefixPlugin
|
||
* The prefix for the classes in jquery.layout plugin
|
||
* @private
|
||
*/
|
||
var prefixPlugin = 'ui-layout-',
|
||
/**
|
||
* @property {Array} positions
|
||
* The array with the position accepted in the layout
|
||
* @private
|
||
*/
|
||
positions = ['north', 'center', 'south', 'east', 'west'],
|
||
/**
|
||
* @property {Object} settings
|
||
* Defines the settings acceptted by the layout panel
|
||
* @private
|
||
*/
|
||
settings = {
|
||
size: "size",
|
||
closed: "initClosed",
|
||
resizable: "resizable",
|
||
closable: "closable",
|
||
togglerOpen: "togglerLength_open",
|
||
togglerClosed: "togglerLength_closed",
|
||
overflow: "allowOverflow",
|
||
hidden: "initHidden",
|
||
cssProperties: "cssProperties",
|
||
cssClasses: "cssClasses"
|
||
};
|
||
|
||
/**
|
||
* @property {Object} panels
|
||
* The settings for the plugin organized by section
|
||
* @private
|
||
*/
|
||
this.panels = {};
|
||
|
||
/**
|
||
* North panel pointer
|
||
* @type {HTMLElement}
|
||
*/
|
||
this.north = null;
|
||
|
||
/**
|
||
* Center panel pointer
|
||
* @type {HTMLElement}
|
||
*/
|
||
this.center = null;
|
||
|
||
/**
|
||
* South panel pointer
|
||
* @type {HTMLElement}
|
||
*/
|
||
this.south = null;
|
||
|
||
/**
|
||
* East panel pointer
|
||
* @type {HTMLElement}
|
||
*/
|
||
this.east = null;
|
||
|
||
/**
|
||
* West panel pointer
|
||
* @type {HTMLElement}
|
||
*/
|
||
this.west = null;
|
||
|
||
/**
|
||
* Javascript pointer to the jquery layout plugin instance
|
||
* @type {Object}
|
||
*/
|
||
this.instance = null;
|
||
|
||
this.onClose = null;
|
||
this.onOpen = null;
|
||
/**
|
||
* Returns the config object
|
||
* @return {Object}
|
||
*/
|
||
LayoutPanel.prototype.getConfig = function () {
|
||
return {
|
||
panels: this.panels,
|
||
onclose_end: this.onClose,
|
||
onopen_start: this.onOpen,
|
||
prefix: prefixPlugin,
|
||
positions: positions,
|
||
isSetting: function (value) {
|
||
var valid = settings[value];
|
||
return (typeof valid !== 'undefined');
|
||
},
|
||
transformSetting: function (value) {
|
||
return settings[value];
|
||
}
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Sets the panel settings
|
||
* @param {String} pos Position (north, center, south, east or west)
|
||
* @param {Object} settings Object settings
|
||
*/
|
||
LayoutPanel.prototype.setConfig = function (pos, settings) {
|
||
this.panels[pos] = settings;
|
||
return this;
|
||
};
|
||
|
||
LayoutPanel.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Panel', LayoutPanel);
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
LayoutPanel.prototype.type = 'LayoutPanel';
|
||
|
||
/**
|
||
* @private
|
||
* Initializes the object with default values
|
||
* @param {Object} options
|
||
*/
|
||
LayoutPanel.prototype.init = function (options) {
|
||
var defaults = {
|
||
center: {
|
||
cssProperties: {},
|
||
cssClasses: []
|
||
},
|
||
factory: {
|
||
products: {
|
||
"layout": PMUI.panel.LayoutPanel,
|
||
"treePanel": PMUI.panel.TreePanel,
|
||
"panel": PMUI.core.Panel
|
||
},
|
||
defaultProduct: "panel"
|
||
},
|
||
onClose: null,
|
||
onOpen: null
|
||
};
|
||
jQuery.extend(true, defaults, options);
|
||
this.setFactory(defaults.factory)
|
||
.setPluginSettings(defaults)
|
||
.setPanels(defaults);
|
||
this.setOnCloseHandler(defaults.onClose);
|
||
this.setOnOpenHandler(defaults.onOpen);
|
||
};
|
||
|
||
LayoutPanel.prototype.setOnCloseHandler = function (hanlder) {
|
||
if (!(typeof hanlder === "function" || hanlder === null)) {
|
||
throw new Error("setOnCloseHandler(): hanlder should be a funtion");
|
||
}
|
||
this.onClose = hanlder;
|
||
return this;
|
||
};
|
||
LayoutPanel.prototype.setOnOpenHandler = function (hanlder) {
|
||
if (!(typeof hanlder === "function" || hanlder === null)) {
|
||
throw new Error("setOnOpenHandler(): hanlder should be a funtion");
|
||
}
|
||
this.onOpen = hanlder;
|
||
return this;
|
||
};
|
||
/**
|
||
* Calculate and sets the settings for each panel
|
||
* @param {Object} obj Object constructor
|
||
*/
|
||
LayoutPanel.prototype.setPluginSettings = function (obj) {
|
||
var config = this.getConfig(),
|
||
that = this;
|
||
|
||
jQuery.each(config.positions, function (index, pos) {
|
||
var panel = obj[pos],
|
||
panelSettings = {};
|
||
|
||
if (panel) {
|
||
if (that.factory && that.factory.isValidClass(panel)) {
|
||
panelSettings = obj[pos + "Config"] || {};
|
||
} else {
|
||
jQuery.each(panel, function (key, value) {
|
||
if (config.isSetting(key)) {
|
||
panelSettings[config.transformSetting(key)] = value;
|
||
}
|
||
});
|
||
}
|
||
if (!(panelSettings.cssClasses && jQuery.isArray(panelSettings.cssClasses))) {
|
||
panelSettings.cssClasses = [];
|
||
}
|
||
panelSettings.cssClasses.push(config.prefix + pos);
|
||
that.setConfig(pos, panelSettings);
|
||
}
|
||
});
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Set panels into north, south, center, west and east pointers
|
||
* @param {Object} obj Constructor object
|
||
*/
|
||
LayoutPanel.prototype.setPanels = function (obj) {
|
||
var config = this.getConfig(),
|
||
that = this,
|
||
treeOptions;
|
||
jQuery.each(config.positions, function (index, pos) {
|
||
if (obj[pos]) {
|
||
|
||
that[pos] = that.factory.make(obj[pos]);
|
||
|
||
if (that[pos] instanceof PMUI.panel.LayoutPanel) {
|
||
that.setConfig(pos, jQuery.extend(true, config.panels[pos], {instance: that[pos]}));
|
||
}
|
||
if (that[pos] instanceof PMUI.panel.TreePanel) {
|
||
treeOptions = {
|
||
cssProperties: that[pos].style.cssProperties,
|
||
cssClasses: that[pos].style.cssClasses
|
||
};
|
||
that.setConfig(pos, jQuery.extend(true, config.panels[pos], treeOptions));
|
||
}
|
||
|
||
that[pos].style.cssProperties = config.panels[pos].cssProperties || {};
|
||
that[pos].style.cssClasses = config.panels[pos].cssClasses || [config.prefix + pos];
|
||
|
||
that.addItem(that[pos]);
|
||
}
|
||
});
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* Create html for each item to container
|
||
* @return {Object} the current object html
|
||
*/
|
||
LayoutPanel.prototype.createHTML = function () {
|
||
var i,
|
||
items;
|
||
|
||
items = this.items.asArray();
|
||
LayoutPanel.superclass.prototype.createHTML.call(this);
|
||
for (i = 0; i < items.length; i += 1) {
|
||
$(this.html).append(items[i].getHTML());
|
||
}
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Render all the html object
|
||
* @param {Boolean} [recursive] Defines if the render must be recursive
|
||
*/
|
||
LayoutPanel.prototype.render = function (recursive) {
|
||
var that = this,
|
||
options,
|
||
renderRecursive = recursive || false;
|
||
options = that.getConfig().panels;
|
||
options.onclose_end = that.getConfig().onclose_end;
|
||
options.onopen_start = that.getConfig().onopen_start;
|
||
if (jQuery(that.html).height() === 0) {
|
||
jQuery(that.html).height(jQuery(document).height() - 20);
|
||
}
|
||
this.instance = jQuery(that.html).layout(options);
|
||
|
||
jQuery.each(options, function (position, val) {
|
||
if (options[position] !== null) {
|
||
if (options[position].instance && renderRecursive) {
|
||
options[position].instance.render(renderRecursive);
|
||
}
|
||
if (options[position].allowOverflow === true) {
|
||
that.instance.allowOverflow(position);
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Remove each html related to the layout from the DOM and destroy the layout instance
|
||
*/
|
||
LayoutPanel.prototype.destroy = function () {
|
||
if (this.instance.destroy !== undefined) {
|
||
this.instance.destroy();
|
||
}
|
||
if (this.html !== undefined) {
|
||
jQuery(this.html).remove();
|
||
this.html = null;
|
||
}
|
||
this.instance = null;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.panel.LayoutPanel', LayoutPanel);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = LayoutPanel;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.layout.Layout
|
||
* Defines the properties for the different layouts in the panels
|
||
* @abstract
|
||
**/
|
||
var Layout = function (options) {
|
||
/**
|
||
* Defines the container to apply the layout
|
||
* @type {Object}
|
||
*/
|
||
this.belongsTo = null;
|
||
Layout.prototype.init.call(this, options);
|
||
};
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
Layout.prototype.type = "Layout";
|
||
|
||
/**
|
||
* Defines the object's family
|
||
* @type {String}
|
||
*/
|
||
Layout.prototype.family = "Layout";
|
||
|
||
Layout.prototype.init = function (options) {
|
||
var defaults = {
|
||
belongsTo: null
|
||
};
|
||
|
||
jQuery.extend(true, defaults, options);
|
||
this.setContainer(defaults.belongsTo);
|
||
};
|
||
|
||
/**
|
||
* Applies the layout to the container
|
||
* @abstract
|
||
*/
|
||
Layout.prototype.applyLayout = function () {
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the parent container
|
||
* @param {Object} parent Container Object
|
||
*/
|
||
Layout.prototype.setContainer = function (parent) {
|
||
this.belongsTo = parent;
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.layout.Layout', Layout);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Layout;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.layout.HBox
|
||
* @extends PMUI.layout.Layout
|
||
* Class created to handle Horizontal Box layout changes
|
||
*
|
||
* @constructor
|
||
* Creates a new isntance of the object
|
||
* @param {Object} options Constructor object
|
||
*/
|
||
var HBox = function (options) {
|
||
HBox.superclass.call(this, options);
|
||
HBox.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.layout.Layout', HBox);
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
HBox.prototype.type = "HBox";
|
||
|
||
/**
|
||
* @private
|
||
* Initializes the object with default values
|
||
* @param {Object} options
|
||
*/
|
||
HBox.prototype.init = function (options) {
|
||
var defaults = {};
|
||
jQuery.extend(true, defaults, options);
|
||
};
|
||
|
||
/**
|
||
* Applies the layout to the current element
|
||
*/
|
||
HBox.prototype.applyLayout = function () {
|
||
// get the object of this layout
|
||
var owner = this.belongsTo,
|
||
items = owner.items,
|
||
totalProportion = 0,
|
||
usableWidth = owner.getUsableWidth(),
|
||
usableHeight = owner.getUsableHeight(),
|
||
i,
|
||
width,
|
||
item;
|
||
|
||
var ownerParent = owner;
|
||
// search the width in anysome parent
|
||
if (owner != null) {
|
||
if (owner.getWidth() != "auto" && owner.parent != null) {
|
||
ownerParent = owner.parent;
|
||
}
|
||
if (owner.html) {
|
||
owner.html.style.width = ownerParent.getUsableWidth();
|
||
}
|
||
}
|
||
// compute totalProportion
|
||
for (i = 0; i < items.getSize(); i += 1) {
|
||
item = items.get(i);
|
||
totalProportion += item.proportion;
|
||
}
|
||
|
||
xPosition = 0;
|
||
for (i = 0; i < items.getSize(); i += 1) {
|
||
item = items.get(i);
|
||
if (item.html) {
|
||
item.setDisplay("inline-block");
|
||
}
|
||
width = usableWidth * (item.proportion / totalProportion);
|
||
item.setWidth(width);
|
||
item.setHeight(usableHeight);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.layout.HBox', HBox);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = HBox;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.layout.VBox
|
||
* @extends PMUI.layout.Layout
|
||
* Class created to handle Vertical Box layout changes
|
||
*
|
||
* @constructor
|
||
* Creates a new isntance of the object
|
||
* @param {Object} options Constructor object
|
||
*/
|
||
var VBox = function (options) {
|
||
VBox.superclass.call(this, options);
|
||
VBox.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.layout.Layout', VBox);
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
VBox.prototype.type = "VBox";
|
||
|
||
/**
|
||
* @private
|
||
* Initializes the object with default values
|
||
* @param {Object} options
|
||
*/
|
||
VBox.prototype.init = function (options) {
|
||
var defaults = {};
|
||
|
||
jQuery.extend(true, defaults, options);
|
||
};
|
||
|
||
/**
|
||
* Applies the layout to the current element
|
||
*/
|
||
VBox.prototype.applyLayout = function () {
|
||
// get the object of this layout
|
||
var owner = this.belongsTo,
|
||
items = owner.items,
|
||
totalProportion = 0,
|
||
usableWidth = owner.getUsableWidth(),
|
||
usableHeight = owner.getUsableHeight(),
|
||
i,
|
||
height,
|
||
item;
|
||
|
||
// compute totalProportion
|
||
for (i = 0; i < items.getSize(); i += 1) {
|
||
item = items.get(i);
|
||
totalProportion += item.proportion;
|
||
}
|
||
|
||
// set the width of each object based on the width of its parent
|
||
for (i = 0; i < items.getSize(); i += 1) {
|
||
item = items.get(i);
|
||
if (item.html) {
|
||
item.setDisplay("block");
|
||
}
|
||
height = usableHeight * (item.proportion / totalProportion);
|
||
item.setHeight(height);
|
||
item.setWidth(usableWidth);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.layout.VBox', VBox);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = VBox;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.layout.Box
|
||
* @extends PMUI.layout.Layout
|
||
* Class created to no layout changes
|
||
*
|
||
* @constructor
|
||
* Creates a new isntance of the object
|
||
* @param {Object} options Constructor object
|
||
*/
|
||
var Box = function (options) {
|
||
Box.superclass.call(this, options);
|
||
Box.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.layout.Layout', Box);
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
Box.prototype.type = "Box";
|
||
|
||
/**
|
||
* @private
|
||
* Initializes the object with default values
|
||
* @param {Object} options
|
||
*/
|
||
Box.prototype.init = function (options) {
|
||
var defaults = {};
|
||
|
||
jQuery.extend(true, defaults, options);
|
||
};
|
||
|
||
/**
|
||
* Applies the layout to the current element
|
||
*/
|
||
Box.prototype.applyLayout = function () {
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.layout.Box', Box);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Box;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.layout.LayoutFactory
|
||
* @extends {PMUI.util.Factory}
|
||
* Extends the functionality of Factory to set the constructor for layouts
|
||
*
|
||
* @constructor
|
||
* Makes a new instance of the class
|
||
* @param {Object} options
|
||
*/
|
||
var LayoutFactory = function (options) {
|
||
LayoutFactory.superclass.call(this, options);
|
||
LayoutFactory.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.util.Factory', LayoutFactory);
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
LayoutFactory.prototype.type = 'LayoutFactory';
|
||
|
||
/**
|
||
* @private
|
||
* Initializes the object with default values
|
||
* @param {Object} options
|
||
*/
|
||
LayoutFactory.prototype.init = function (options) {
|
||
var defaults = {
|
||
products: {
|
||
"hbox": PMUI.layout.HBox,
|
||
"vbox": PMUI.layout.VBox,
|
||
"box": PMUI.layout.Box
|
||
},
|
||
defaultProduct: "box"
|
||
};
|
||
jQuery.extend(true, defaults, options);
|
||
this.setProducts(defaults.products)
|
||
.setDefaultProduct(defaults.defaultProduct);
|
||
};
|
||
|
||
LayoutFactory.prototype.make = function (obj) {
|
||
var product,
|
||
productType = obj.pmType || '';
|
||
|
||
if (this.isValidClass(obj)) {
|
||
product = obj;
|
||
} else if (this.isValidName(productType)) {
|
||
product = this.build.call(this, productType, obj);
|
||
} else if (this.isValidName(obj)) {
|
||
product = this.build.call(this, obj, {});
|
||
} else {
|
||
product = this.build.call(this, this.defaultProduct, obj);
|
||
}
|
||
return product;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.layout.LayoutFactory', LayoutFactory);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = LayoutFactory;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.panel.TreePanel
|
||
* A panel that contains {@link PMUI.item.TreeNode TreeNode items}.
|
||
* @extends {PMUI.core.Panel}
|
||
*
|
||
* An example of a TreePanel with descendant nodes (using the items {@link #cfg-items config option}):
|
||
*
|
||
* @example
|
||
* var t = new PMUI.panel.TreePanel({
|
||
* style: {
|
||
* cssClasses: ['xxxxxxxx']
|
||
* },
|
||
* items: [
|
||
* {
|
||
* label: "America",
|
||
* items: [
|
||
* {
|
||
* label: "North America",
|
||
* items: [
|
||
* {
|
||
* label: "Canada"
|
||
* },
|
||
* {
|
||
* label: "USA"
|
||
* },
|
||
* {
|
||
* label: "Mexico"
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* label: "Central America and Caribbean",
|
||
* items: [
|
||
* {
|
||
* label: "Guatemala"
|
||
* },
|
||
* {
|
||
* label: "Cuba"
|
||
* },
|
||
* {
|
||
* label: "Costa Rica"
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* label: "South America",
|
||
* items: [
|
||
* {
|
||
* label: "Argentina"
|
||
* },
|
||
* {
|
||
* label: "Bolivia"
|
||
* },
|
||
* {
|
||
* label: "Brasil"
|
||
* }
|
||
* ]
|
||
* }
|
||
* ]
|
||
* }
|
||
* ]
|
||
* });
|
||
* document.body.appendChild(t.getHTML());
|
||
* t.defineEvents();
|
||
*
|
||
* An example of a TreePanel with descendant nodes (using the {@link #cfg-dataItems dataItems} config option):
|
||
*
|
||
* @example
|
||
* t2 = new PMUI.panel.TreePanel({
|
||
* nodeDefaultSettings: {
|
||
* labelDataBind: 'name',
|
||
* itemsDataBind: 'regions',
|
||
* recursiveChildrenDefaultSettings: true,
|
||
* childrenDefaultSettings: {
|
||
* labelDataBind: 'name',
|
||
* itemsDataBind: 'countries',
|
||
* autoBind: true
|
||
* },
|
||
* autoBind: true
|
||
* },
|
||
* dataItems: [
|
||
* {
|
||
* name: 'America',
|
||
* regions: [
|
||
* {
|
||
* name: 'North America',
|
||
* countries: [
|
||
* {
|
||
* name: 'Canada'
|
||
* },
|
||
* {
|
||
* name: 'USA'
|
||
* },
|
||
* {
|
||
* name: 'Mexico'
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* name: 'Central America and Caribbean',
|
||
* countries: [
|
||
* {
|
||
* name: 'Guatemala'
|
||
* },
|
||
* {
|
||
* name: 'Cuba'
|
||
* },
|
||
* {
|
||
* name: 'Costa Rica'
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* name: 'South America',
|
||
* countries: [
|
||
* {
|
||
* name: 'Argentina'
|
||
* },
|
||
* {
|
||
* name: 'Bolivia'
|
||
* },
|
||
* {
|
||
* name: 'Brasil'
|
||
* }
|
||
* ]
|
||
* }
|
||
* ]
|
||
* }
|
||
* ]
|
||
* });
|
||
* document.body.appendChild(t2.getHTML());
|
||
* t2.defineEvents();
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class.
|
||
* @param {Object} settings The config options.
|
||
*
|
||
* @cfg {Object|null} [nodeDefaultSettings=null] The default settings for all the direct child nodes of the tree panel.
|
||
* It is an object with the config options for {@link PMUI.item.TreeNode TreeNode}.
|
||
* @cfg {Object|null} [dataItems=null] An object with the data for the items in the tree panel.
|
||
* @cfg {Array} [data=[]] An array in which each element is an object with the config options for
|
||
* {@link PMUI.item.TreeNode TreeNode} an instance of it. If you use both dataItems and this config option, this
|
||
* config option will be ignored and the dataItems will be used instead.
|
||
* @cfg {String} [filterPlaceholder="search"] The text to show as placeholder for the text control for filtering.
|
||
* @cfg {Function|String|null} [emptyMessage=null] The message to show when the grid is showing no items. It
|
||
* can be:
|
||
*
|
||
* - A String, in this case the string will be displayed in both cases, when the treepanel has no items and when no
|
||
* treepanel's item meet the filter.
|
||
* - A Function, in this case the function must return a string or an HTML Element to be displayed. The function
|
||
* will receive two parameters: the {@link PMUI.panel.TreePanel TreePanel}, a boolean If it is true it means the returned
|
||
* value will be used when a filter is applied, otherwise it means that the returned value will be used when
|
||
* there are no items in the treepanel.
|
||
* - null, in this case a default message will be used for each situation.
|
||
* @cfg {Boolean} [visibleTitle=false] If the title will be displayed.
|
||
* @cfg {String} [title=""] The text for the title.
|
||
* @cfg {Function} [onNodeClick=null] The callback function to be executed everytime the
|
||
* {@link #event-onNodeClick onNodeClick} event fires. For info about the parameters sent to the callback please
|
||
* read the {@link #event-onNodeClick onNodeClick} event documentation.
|
||
* @cfg {Function|null} [onBeforeAppend=null] A callback function to be called everytime the
|
||
* {@link #event-onBeforeAppend onBeforeAppend} event is fired. For info about the parameters used for this
|
||
* callback please read the documentation for this event.
|
||
* @cfg {Function|null} [onAppend=null] A callback function to be called everytime the
|
||
* {@link #event-onAppend onAppend} event is fired. For info about the parameters used for this callback please
|
||
* read the documentation for this event.
|
||
*/
|
||
var TreePanel = function (settings) {
|
||
TreePanel.superclass.call(this, jQuery.extend(settings, {
|
||
factory: {
|
||
products: {
|
||
'node': PMUI.item.TreeNode
|
||
},
|
||
defaultProduct: 'node'
|
||
}
|
||
}));
|
||
/**
|
||
* The default settings for all the direct child nodes of the tree panel.
|
||
* @type {Object}
|
||
*/
|
||
this.nodeDefaultSettings = null;
|
||
/**
|
||
* The filter criteria being applied currently.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.filterCriteria = "";
|
||
/**
|
||
* If the tree panel is filterable or not.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.filterable = null;
|
||
/**
|
||
* The text control in which the user can introduce a text to filter.
|
||
* @type {PMUI.control.TextControl}
|
||
* @private
|
||
*/
|
||
this.filterControl = null;
|
||
/**
|
||
* A string or a function or null. Determines the text/HTML Element to show when there are no items to show.
|
||
* @type {Function|String|null}
|
||
* @readonly
|
||
*/
|
||
this.emptyMessage = null;
|
||
/**
|
||
* The title for the TreePanel
|
||
* @type {String}
|
||
*/
|
||
this.title = null;
|
||
/**
|
||
* If the title is visible or not.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.visibleTitle = null;
|
||
/**
|
||
* @event onItemClick
|
||
* Fired everytime an tree item is clicked.
|
||
* @param {PMUI.panel.TreePanel} treePanel The TreePanel in which the event was fired.
|
||
* @param {PMUI.item.TreeNode} node The node that was clicked.
|
||
*/
|
||
this.onNodeClick = null;
|
||
/**
|
||
* An private object to store the DOM elements that compose the object's HTML.
|
||
* @type {Object}
|
||
* @private
|
||
*/
|
||
this.dom = {};
|
||
/**
|
||
* @event onBeforeAppend
|
||
* Fired before a child node is appended to the current node or to any of its children nodes.
|
||
* @param {PMUI.item.TreeNode} node The node in which the event is being fired.
|
||
* @param {PMUI.item.TreeNode} newNode The new node to be appended.
|
||
*/
|
||
this.onBeforeAppend = null;
|
||
/**
|
||
* @event onAppend
|
||
* Fired everytime a child node is appended to the current node or to any of its children nodes.
|
||
* @param {PMUI.item.TreeNode} node The node in which the event is being fired.
|
||
* @param {PMUI.item.TreeNode} newNode The appended node.
|
||
*/
|
||
this.onAppend = null;
|
||
TreePanel.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Panel', TreePanel);
|
||
/**
|
||
* The object's type.
|
||
* @type {String}
|
||
*/
|
||
TreePanel.prototype.type = 'TreePanel';
|
||
/**
|
||
* The class family.
|
||
* @type {String}
|
||
*/
|
||
TreePanel.prototype.family = 'Panel';
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} settings The config options for the object.
|
||
* @private
|
||
*/
|
||
TreePanel.prototype.init = function (settings) {
|
||
var defaults = {
|
||
nodeDefaultSettings: null,
|
||
dataItems: null,
|
||
data: [],
|
||
filterPlaceholder: 'search',
|
||
filterable: false,
|
||
emptyMessage: null,
|
||
visibleTitle: false,
|
||
title: "",
|
||
onNodeClick: null,
|
||
onAppend: null,
|
||
onBeforeAppend: null,
|
||
collapse: false,
|
||
onStop : function(){console.log("trepanel")}
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setNodeDefaultSettings(defaults.nodeDefaultSettings)
|
||
.setEmptyMessage(defaults.emptyMessage)
|
||
.setTitle(defaults.title)
|
||
.setOnNodeClickHandler(defaults.onNodeClick)
|
||
.setOnAppendHandler(defaults.onAppend)
|
||
.setOnBeforeAppendHandler(defaults.onBeforeAppend);
|
||
this.filterControl = new PMUI.control.TextControl({
|
||
onKeyUp: this.onFilterControlChangeHandler(),
|
||
placeholder: defaults.filterPlaceholder
|
||
});
|
||
|
||
if (jQuery.isArray(defaults.dataItems)) {
|
||
this.setDataItems(defaults.dataItems);
|
||
} else {
|
||
this.setItems(defaults.items);
|
||
}
|
||
if (defaults.filterable) {
|
||
this.enableFiltering();
|
||
} else {
|
||
this.disableFiltering();
|
||
}
|
||
if (defaults.visibleTitle) {
|
||
this.showTitle();
|
||
} else {
|
||
this.hideTitle();
|
||
}
|
||
if (defaults.collapse) {
|
||
this.collapse(true);
|
||
} else {
|
||
this.expand(true);
|
||
}
|
||
};
|
||
/**
|
||
* Sets the callback function to be called everytime the {@link #event-onBeforeAppend onBeforeAppend} event is
|
||
* fired. For info about the parameters used for this callback please read the documentation for this event.
|
||
* @param {Function|null} handler
|
||
*/
|
||
TreePanel.prototype.setOnBeforeAppendHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnBeforeAppendHandler(): The parameter must be a function or null.");
|
||
}
|
||
this.onBeforeAppend = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback function to be called everytime the
|
||
* {@link #event-onAppend onAppend} event is fired. For info about the parameters used for this callback please
|
||
* read the documentation for this event.
|
||
* @param {Function|null} handler
|
||
*/
|
||
TreePanel.prototype.setOnAppendHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnAppendHandler(): The parameter must be a function or null.");
|
||
}
|
||
this.onAppend = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback function to be executed everytime the {@link #event-onNodeclick onNodeClick} is fired. For
|
||
* info about the parameters sent to the callback read the document for that event.
|
||
* @param {Function} handler It can be a function or null.
|
||
*/
|
||
TreePanel.prototype.setOnNodeClickHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnNodeClickHandler(): The parameter must be a function.");
|
||
}
|
||
this.onNodeClick = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
TreePanel.prototype.clearItems = function () {
|
||
TreePanel.superclass.prototype.clearItems.call(this);
|
||
return this.showEmptyMessage();
|
||
};
|
||
/**
|
||
* Hides the title bar.
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.hideTitle = function () {
|
||
this.visibleTitle = false;
|
||
if (this.dom.title) {
|
||
this.dom.title.style.display = 'none';
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows the title.
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.showTitle = function () {
|
||
this.visibleTitle = true;
|
||
if (this.dom.title) {
|
||
this.dom.title.style.display = '';
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the title for the tree panel.
|
||
* @param {String} title
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.setTitle = function (title) {
|
||
if (typeof title !== 'string') {
|
||
throw new Error('showTitle(): The parameter must be a string.');
|
||
}
|
||
this.title = jQuery.trim(title);
|
||
if (this.dom.title) {
|
||
this.dom.title.textContent = this.title;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the message to display when there are no items to display in the tree panel.
|
||
* @param {String|Function|null} emptyMessage It can be:
|
||
*
|
||
* - A String, in this case the string will be displayed in both cases, when the tree has no items and when no
|
||
* tree's items meet the filter.
|
||
* - A Function, in this case the function must return a string or an HTML Element to be displayed. The function
|
||
* will receive two parameters: the {@link PMUI.panel.TreePanel tree panel}, a boolean If it is true it means the returned
|
||
* value will be used when a filter is applied, otherwise it means that the returned value will be used when
|
||
* there are no items in the tree panel.
|
||
* - null, in this case a default message will be used for each situation.
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.setEmptyMessage = function (emptyMessage) {
|
||
if (!(emptyMessage === null || typeof emptyMessage === 'string' || typeof emptyMessage === 'function')) {
|
||
throw new Error("setEmptyMessage(): the parameter must be a string, a function or null.");
|
||
}
|
||
this.emptyMessage = emptyMessage;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the filter for the text control's placeholder.
|
||
* @param {String} placeholder The text for the placeholder.
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.setFilterPlaceholder = function (placeholder) {
|
||
this.filterControl.setPlaceholder(placeholder);
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the placeholder for the text control for filtering.
|
||
* @return {String}
|
||
*/
|
||
TreePanel.prototype.getFilterPlaceholder = function () {
|
||
return this.filterControl.placeholder;
|
||
};
|
||
/**
|
||
* Returns the handler to be executed when the filter changes.
|
||
* @return {Function}
|
||
* @private
|
||
*/
|
||
TreePanel.prototype.onFilterControlChangeHandler = function () {
|
||
var that = this;
|
||
return function () {
|
||
var nextFilter = this.getHTML().value;
|
||
if (that.filterCriteria !== nextFilter) {
|
||
that.filter(nextFilter);
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Enables the filtering functionality.
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.enableFiltering = function () {
|
||
this.filterable = true;
|
||
this.clearFilter().filterControl.setValue("");
|
||
if (this.dom.toolbar) {
|
||
this.dom.toolbar.style.display = '';
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables the filtering functionality.
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.disableFiltering = function () {
|
||
this.filterable = false;
|
||
this.clearFilter().filterControl.setValue("");
|
||
if (this.dom.toolbar) {
|
||
this.dom.toolbar.style.display = 'none';
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the default settings for the direct child nodes of the tree panel.
|
||
* @param {Object} settings The config options to be applied to new child nodes to be added in case they are
|
||
* missing any config option.
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.setNodeDefaultSettings = function (settings) {
|
||
if (typeof settings !== 'object') {
|
||
throw new Error('setNodeDefaultSettings(): The parameter must be an object.');
|
||
}
|
||
this.nodeDefaultSettings = settings;
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
TreePanel.prototype.setFactory = function () {
|
||
this.factory = new PMUI.util.Factory({
|
||
products: {
|
||
'node': PMUI.item.TreeNode
|
||
},
|
||
defaultProduct: 'node'
|
||
});
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* The private handler fot the {@link #event-onBeforeAppend onBeforeAppend} event.
|
||
* @private
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.onBeforeAppendHandler = function (treeNode) {
|
||
if (typeof this.onBeforeAppend === 'function') {
|
||
this.onBeforeAppend(this, treeNode);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* The private handler for the {@link #event-onAppend} event.
|
||
* @private
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.onAppendHandler = function (treeNode) {
|
||
if (typeof this.onAppend === 'function') {
|
||
this.onAppend(this, treeNode);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a new node to the tree panel.
|
||
* @param {Object|PMUI.item.TreeNode} item An instance of {@link PMUI.item.TreeNode TreeNode}, or an object with
|
||
* the config options to create a new one. In the latter case, if any config option is missing then will be used
|
||
* the respective one in the set by the {@link #method-setNodeDefaultSettings setNodeDefaultSettings()} method.
|
||
* @param {Number} [index] The position index in which will be added the new item. If not specified the will be
|
||
* added to the end.
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.addItem = function (item, index) {
|
||
var settings = {},
|
||
itemToAdd;
|
||
|
||
if (item instanceof PMUI.item.TreeNode) {
|
||
item.setParent(this);
|
||
} else if (typeof item === 'object') {
|
||
jQuery.extend(true, settings, this.nodeDefaultSettings || {}, item);
|
||
settings.parent = this;
|
||
item = settings;
|
||
} else {
|
||
throw new Error('addItem(): The parameter must be an instance of PMUI.item.TreeNode or an object.');
|
||
}
|
||
itemToAdd = this.factory.make(item);
|
||
if (itemToAdd) {
|
||
this.hideEmptyMessage();
|
||
this.onBeforeAppendHandler(itemToAdd);
|
||
TreePanel.superclass.prototype.addItem.call(this, itemToAdd, index);
|
||
this.onAppendHandler(itemToAdd);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
TreePanel.prototype.removeItem = function (item) {
|
||
TreePanel.superclass.prototype.removeItem.call(this, item);
|
||
if (!this.items.getSize()) {
|
||
this.showEmptyMessage();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
TreePanel.prototype.setItems = function (items) {
|
||
if (this.onAppend !== undefined) {
|
||
TreePanel.superclass.prototype.setItems.call(this, items);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Expands the child nodes.
|
||
* @param {Boolean} [expandAll=false] If the expand function will be applied to all the sub child items or not.
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.expand = function (expandAll) {
|
||
var i,
|
||
items = this.items.asArray();
|
||
|
||
for (i = 0; i < items.length; i += 1) {
|
||
items[i].expand(expandAll);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Collapse the child nodes.
|
||
* @param {Boolean} [collapseAll=false] If the collapse function will be applied to all the sub child items or
|
||
* not.
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.collapse = function (collapseAll) {
|
||
var i,
|
||
items = this.items.asArray();
|
||
|
||
for (i = 0; i < items.length; i += 1) {
|
||
items[i].collapse(collapseAll);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Hides the message to show when there are no items to display.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
TreePanel.prototype.hideEmptyMessage = function () {
|
||
jQuery(this.html).find('.pmui-treepanel-emptymessage').hide();
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows an empty message when there are no items to display.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
TreePanel.prototype.showEmptyMessage = function () {
|
||
var node,
|
||
message;
|
||
|
||
if (!this.html) {
|
||
return this;
|
||
}
|
||
node = jQuery(this.html).find('.pmui-treepanel-emptymessage').empty().get(0);
|
||
if (!node) {
|
||
node = PMUI.createHTMLElement('div');
|
||
node.className = 'pmui-treepanel-emptymessage';
|
||
}
|
||
if (typeof this.emptyMessage === 'function') {
|
||
message = this.emptyMessage(this, !!this.filterCriteria);
|
||
} else if (typeof this.emptyMessage === 'string') {
|
||
message = this.emptyMessage;
|
||
} else {
|
||
if (this.filterCriteria) {
|
||
message = 'No matches found for \"' + this.filterCriteria + '\"';
|
||
} else {
|
||
message = 'No items found.';
|
||
}
|
||
}
|
||
if (typeof message === 'string') {
|
||
node.appendChild(document.createTextNode(message));
|
||
} else if (PMUI.isHTMLElement(message)) {
|
||
node.appendChild(message);
|
||
}
|
||
node.style.display = '';
|
||
this.html.appendChild(node);
|
||
return this;
|
||
};
|
||
/**
|
||
* Clears the current filter.
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.clearFilter = function () {
|
||
return this.filter("");
|
||
};
|
||
/**
|
||
* Filters the tree using a criteria.
|
||
* @param {String} filterCriteria The criteria.
|
||
* @chainable
|
||
*/
|
||
TreePanel.prototype.filter = function (filterCriteria) {
|
||
var i,
|
||
childNodes = this.items.asArray(),
|
||
partialRes,
|
||
res = false;
|
||
|
||
filterCriteria = filterCriteria.toString(10);
|
||
this.filterCriteria = filterCriteria;
|
||
jQuery(this.html).find('.pmui-treepanel-emptymessage').remove();
|
||
for (i = 0; i < childNodes.length; i += 1) {
|
||
childNodes[i].setVisible(partialRes = childNodes[i].filter(filterCriteria));
|
||
res = res || partialRes;
|
||
}
|
||
if (!res) {
|
||
this.showEmptyMessage();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
TreePanel.prototype.defineEvents = function () {
|
||
TreePanel.superclass.prototype.defineEvents.call(this);
|
||
this.filterControl.defineEvents();
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
TreePanel.prototype.createHTML = function () {
|
||
var list,
|
||
toolbar,
|
||
title;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
html = PMUI.createHTMLElement(this.elementTag || "div");
|
||
html.id = this.id;
|
||
PMUI.linkToPMUIObject(html, this);
|
||
this.html = html;
|
||
this.actionHTML = html;
|
||
this.applyStyle();
|
||
this.containmentArea = this.html;
|
||
|
||
title = PMUI.createHTMLElement('h2');
|
||
title.className = 'pmui-treepanel-title';
|
||
this.html.appendChild(title);
|
||
this.dom.title = title;
|
||
list = PMUI.createHTMLElement('ul');
|
||
list.className = 'pmui-treepanel-list';
|
||
this.dom.list = list;
|
||
this.containmentArea = list;
|
||
toolbar = PMUI.createHTMLElement('div');
|
||
toolbar.className = 'pmui-treepanel-toolbar';
|
||
toolbar.style.display = 'none';
|
||
toolbar.appendChild(this.filterControl.getHTML());
|
||
this.dom.toolbar = toolbar;
|
||
this.html.appendChild(toolbar);
|
||
this.html.appendChild(list);
|
||
this.setTitle(this.title);
|
||
if(this.items.getSize() > 0){
|
||
this.paintItems();
|
||
}
|
||
if (this.filterable) {
|
||
this.enableFiltering();
|
||
} else {
|
||
this.disableFiltering();
|
||
}
|
||
if (this.visibleTitle) {
|
||
this.showTitle();
|
||
} else {
|
||
this.hideTitle();
|
||
}
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.panel.TreePanel', TreePanel);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports === TreePanel;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.panel.TabPanel
|
||
* @extends PMUI.core.Panel
|
||
* Is the container for every {@link PMUI.item.TabItem TabItem} class
|
||
*
|
||
* Example:
|
||
*
|
||
* @example
|
||
var a,p,f,tree,w;
|
||
|
||
//Form Panel*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
||
p = new PMUI.form.FormPanel({
|
||
width: 604,
|
||
height: 130,
|
||
fieldset: true,
|
||
legend: "my fieldset panel",
|
||
items: [
|
||
{
|
||
pmType: "text",
|
||
label: "Name",
|
||
id: "123",
|
||
value: "",
|
||
placeholder: "insert your name",
|
||
name: "name"
|
||
},{
|
||
pmType: "text",
|
||
label: "Last name",
|
||
value: "",
|
||
placeholder: "your lastname here asshole!",
|
||
name: "lastname"
|
||
}
|
||
],
|
||
layout: "vbox"
|
||
});
|
||
//treePanel *-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
||
tree = new PMUI.panel.TreePanel({
|
||
items: [
|
||
{
|
||
label: "America",
|
||
items: [
|
||
{
|
||
label: "North America",
|
||
items: [
|
||
{
|
||
label: "Canada"
|
||
},
|
||
{
|
||
label: "USA"
|
||
},
|
||
{
|
||
label: "Mexico"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
});
|
||
//Layout Panel *-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
||
f = new PMUI.form.Form({
|
||
onSubmit: function() {
|
||
console.log("submitting...");
|
||
},
|
||
onChange: function(field, newValue, previousValue) {
|
||
console.log("The field " + field.getName() + " has changed from \"" + previousValue + "\" to \"" + newValue + "\"");
|
||
},
|
||
items: [
|
||
{
|
||
pmType: "dropdown",
|
||
label: "age",
|
||
options: [
|
||
{
|
||
label: "from 0 to 7 years old",
|
||
value: "0-7"
|
||
},
|
||
{
|
||
label: "from 8 to 13 years old",
|
||
value: "8-13"
|
||
}
|
||
],
|
||
name: "age",
|
||
helper: "Select one of the options",
|
||
required: true
|
||
},
|
||
{
|
||
pmType: "radio",
|
||
label: "Gender",
|
||
value: "m",
|
||
name: "gender",
|
||
required: true,
|
||
options: [
|
||
{
|
||
label: "Male",
|
||
value: "m"
|
||
},
|
||
{
|
||
label: "Female",
|
||
value: "f"
|
||
}
|
||
]
|
||
}
|
||
],
|
||
buttons: [
|
||
{
|
||
text: "Submit",
|
||
handler: function() {
|
||
f.submit();
|
||
console.log("submitting form...");
|
||
}
|
||
}
|
||
]
|
||
});
|
||
//Tab Item*--**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
|
||
a = new PMUI.panel.TabPanel({
|
||
height : 400,
|
||
width : 600,
|
||
items:[
|
||
{
|
||
icon :'pmui-gridpanel-engranaje',
|
||
title:'Tree Panel',
|
||
panel:tree
|
||
},
|
||
{
|
||
icon :'pmui-gridpanel-engranaje',
|
||
title:'Form Panel',
|
||
panel:p
|
||
},
|
||
{ icon :'pmui-gridpanel-engranaje',
|
||
title:'Form',
|
||
panel:f
|
||
}
|
||
],
|
||
itemsPosition : {position:"left",percentageWidth : 22}
|
||
//itemsPosition : 'top'
|
||
});
|
||
//document.body.appendChild(a.getHTML());
|
||
//a.defineEvents();
|
||
w = new PMUI.ui.Window({
|
||
title: "TabPanel",
|
||
width: 650,
|
||
height: 460,
|
||
footerHeight: 'auto',
|
||
bodyHeight: 'auto',
|
||
modal:true,
|
||
buttons: [
|
||
{
|
||
text: 'Saves',
|
||
handler: function() {
|
||
alert('save');
|
||
}
|
||
},
|
||
{
|
||
text: 'Close',
|
||
handler: function() {
|
||
alert('close');
|
||
}
|
||
},
|
||
{
|
||
text: "third button"
|
||
}
|
||
],
|
||
buttonsPosition : 'center',
|
||
spaceButtons : 30
|
||
});
|
||
w.open();
|
||
w.addItem(a);
|
||
w.defineEvents();
|
||
|
||
* In the example, we use as a treePanel panels, FormPanel and layoutPanel, each TabItem can also use a className
|
||
* to put an icon, see {@link PMUI.item.TabItem}, {@link PMUI.item.TabItem#cfg-icon icon}. The pocision of items [TabItem]
|
||
* can be "top", "left", "right" and "bottom", see the configuration options.
|
||
*
|
||
* Note: used a window for a best visualisation.
|
||
*
|
||
* @cfg {Array} [items = []]
|
||
* The items should be a Array, that Array should have Object JSON for config of the TabItems
|
||
* for more detail see {@link PMUI.item.TabItem}
|
||
*
|
||
* @cfg {String|Object} [itemsPosition = 'top']
|
||
* This option config can be of type:
|
||
*
|
||
* Object, when position is "left" or "right", example:
|
||
* itemsPosition: {position: "left", percentageWidth: 20}
|
||
* itemsPosition: {position: "right", percentageWidth: 20}
|
||
* JSON options:
|
||
* position: must be a string (can only be "left" or "right")
|
||
* percentageWidth: must be a number between 0 and 100
|
||
*
|
||
* String, when the position is "top" or "bottom", example:
|
||
* itemsPosition: "top"
|
||
* itemsPosition: "bottom"
|
||
* percentageWidth is not require
|
||
*/
|
||
var TabPanel = function (settings) {
|
||
TabPanel.superclass.call(this, settings);
|
||
/**
|
||
* Defines the tabpanel panelContainer HTML Element where is fix the content of the family Panel
|
||
* @type {HTMLElement}
|
||
*/
|
||
this.dom = {};
|
||
/**
|
||
* a property to assign events to see if the tabs is selected or not
|
||
* @type {PMUI.ite.TabItem}
|
||
*/
|
||
this.selectedTab = null;
|
||
/**
|
||
* a property that can be true or false values, when set to true indicates
|
||
* that the items will be collapsible
|
||
* @type {boolean}
|
||
*/
|
||
this.collapsible = null;
|
||
/**
|
||
* this posision items should be 'top', 'left', 'right' or 'bottom'
|
||
* @type {String}
|
||
*/
|
||
this.itemsPosition = null;
|
||
/**
|
||
* represents the space busy for the containerItems HTMLElement, default value
|
||
* this property is 0, when itemsPosition is "right" or "left " this value is different 0
|
||
* @type {Number}
|
||
*/
|
||
this.percentageWidth = null;
|
||
this.onTabClick = null;
|
||
TabPanel.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom("PMUI.core.Panel", TabPanel);
|
||
|
||
TabPanel.prototype.type = "tabpanel";
|
||
TabPanel.prototype.family = "tabpanel";
|
||
|
||
TabPanel.prototype.init = function (settings) {
|
||
var defaults = {
|
||
items: [],
|
||
itemsPosition: 'top',
|
||
onTabClick: null,
|
||
collapsible: true
|
||
};
|
||
jQuery.extend(true, defaults, settings);
|
||
this.setItems(defaults.items);
|
||
this.setItemsPosition(defaults.itemsPosition);
|
||
this.setOnTabClick(defaults.onTabClick);
|
||
this.setCollapsible(defaults.collapsible);
|
||
};
|
||
|
||
TabPanel.prototype.setCollapsible = function (collapsible) {
|
||
if (typeof collapsible !== 'boolean') {
|
||
throw new Error('setCollapsible(): the parameter collapsible should be type "boolean"');
|
||
}
|
||
this.collapsible = collapsible;
|
||
return this;
|
||
};
|
||
|
||
TabPanel.prototype.setOnTabClick = function (tabClick) {
|
||
if (typeof tabClick !== 'function' && tabClick !== null) {
|
||
throw new Error("setOnTabClick(): the parameter is not valid, should be a function.");
|
||
}
|
||
this.onTabClick = tabClick;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* set in this method and call addItem to create the TabItem
|
||
* @param {Array} The JSON array with objects with parameters for creating TabItem
|
||
* @chainable
|
||
*/
|
||
TabPanel.prototype.setItems = function (items) {
|
||
var i;
|
||
|
||
if (jQuery.isArray(items)) {
|
||
this.clearItems();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
this.addItem(items[i]);
|
||
}
|
||
} else {
|
||
throw new Error("setTabs(): the parameter is not a valid, should to be as Array");
|
||
}
|
||
for (i = 0; i < this.items.getSize(); i += 1) {
|
||
if (i == 0) {
|
||
this.items.get(0).select();
|
||
} else {
|
||
this.items.get(i).deselect();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* [onTabClickHandler description]
|
||
* @return {[type]} [description]
|
||
* @private
|
||
*/
|
||
TabPanel.prototype.onTabClickHandler = function () {
|
||
var that = this;
|
||
|
||
return function (tabItem) {
|
||
if (typeof that.onTabClick === 'function') {
|
||
that.onTabClick(tabItem);
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Add an item to the panel.
|
||
* @param {PMUI.item.TabItem} item
|
||
* It can be a valid JSON object or an object that inherits from {@link PMUI.item.TabItem}.
|
||
* @chainable
|
||
*/
|
||
TabPanel.prototype.addItem = function (item) {
|
||
var tabItem;
|
||
|
||
item.onSelect = this.onTabSelectHandler();
|
||
tabItem = new PMUI.item.TabItem(item);
|
||
tabItem.deselect();
|
||
tabItem.setOnClick(this.onTabClickHandler());
|
||
this.items.insert(tabItem);
|
||
if (this.html) {
|
||
this.dom.listContainer.appendChild(tabItem.getHTML());
|
||
this.updatePosition();
|
||
if (this.eventsDefined) {
|
||
tabItem.defineEvents();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @event
|
||
* defines the function to be determined in each tabItem when it is selected, to
|
||
* call the event set
|
||
* @chainable
|
||
*/
|
||
TabPanel.prototype.onTabSelectHandler = function () {
|
||
var that = this,
|
||
i;
|
||
|
||
return function () {
|
||
if (that.selectedTab) {
|
||
jQuery(that.selectedTab.panel.getHTML()).detach();
|
||
}
|
||
that.selectedTab = this;
|
||
for (i = 0; i < that.items.getSize(); i += 1) {
|
||
if (that.items.get(i) !== that.selectedTab) {
|
||
that.items.get(i).deselect();
|
||
}
|
||
}
|
||
jQuery(that.dom.panelContainer).append(this.getPanel().getHTML());
|
||
if (!this.getPanel().eventsDefined) {
|
||
this.getPanel().defineEvents();
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* @method setItemsPosition
|
||
* changes the position of the elements [PM UI.item.TabItem] within the sizes assigned to TabPanel.
|
||
* @param {String|Object}
|
||
* Position where items are positioned, the more info about input value see {@link PMUI.panel.TabPanel}
|
||
* config option: {@link PMUI.panel.TabPanel#cfg-itemsPosition itemsPosition}
|
||
* @chainable
|
||
*/
|
||
TabPanel.prototype.setItemsPosition = function (itemsPosition) {
|
||
var validPosition,
|
||
percentageWidth;
|
||
|
||
if (typeof itemsPosition == "string" || typeof itemsPosition == "object") {
|
||
if (typeof itemsPosition == "object") {
|
||
if (itemsPosition.position == "left" || itemsPosition.position == "right") {
|
||
this.itemsPosition = itemsPosition.position;
|
||
this.percentageWidth = itemsPosition.percentageWidth || 20;
|
||
} else {
|
||
throw new Error("setItemsPosition(): JSON no valid, send position : 'left' or 'right' with percentage width");
|
||
}
|
||
} else {
|
||
if (itemsPosition == "top" || itemsPosition == "bottom") {
|
||
this.itemsPosition = itemsPosition;
|
||
this.percentageWidth = 0;
|
||
} else {
|
||
throw new Error("setItemsPosition(): no valid, send position : 'top' or 'bottom' ");
|
||
}
|
||
}
|
||
|
||
this.style.removeClasses(['pmui-tabpanel-left', 'pmui-tabpanel-right', 'pmui-tabpanel-top', 'pmui-tabpanel-bottom']);
|
||
this.style.addClasses(['pmui-tabpanel-' + this.itemsPosition]);
|
||
|
||
if (this.html) {
|
||
this.updatePosition();
|
||
}
|
||
} else {
|
||
throw new Error("setItemsPosition(): the parameter is not a valid, should to be as string or Object JSON");
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @private
|
||
* update the position for the HTMLElement.
|
||
* exists the next elements HTMLElements:
|
||
*
|
||
* - containerItems
|
||
* - listContainer
|
||
* - barCollaspible
|
||
* - panelContainer
|
||
*
|
||
* this elements should update your position in the DOM, also update dimensions respect to the property itemsPosition
|
||
* @chainable
|
||
*/
|
||
TabPanel.prototype.updatePosition = function () {
|
||
var i,
|
||
itemsDisplay;
|
||
|
||
switch (this.itemsPosition) {
|
||
case 'top' :
|
||
case 'left':
|
||
$(this.dom.containerItems).prepend(this.dom.listContainer);
|
||
$(this.html).prepend(this.dom.containerItems);
|
||
|
||
|
||
this.dom.containerItems.style.display = this.itemsPosition === 'left' ? "inline-block" : "block";
|
||
this.dom.listContainer.style.display = this.itemsPosition === 'left' ? "inline-block" : "block";
|
||
this.dom.collapsibleBar.style.display = this.itemsPosition === 'left' ? "inline-block" : "none";
|
||
this.dom.panelContainer.style.display = this.itemsPosition === 'left' ? "inline-block" : "block";
|
||
$(this.dom.containerItems).css("float", this.itemsPosition === 'left' ? "left" : "");
|
||
|
||
itemsDisplay = this.itemsPosition === 'left' ? "block" : "inline-block";
|
||
|
||
for (i = 0; i < this.items.getSize(); i += 1) {
|
||
this.items.get(i).setDisplay(itemsDisplay);
|
||
}
|
||
|
||
if (this.itemsPosition == 'left') {
|
||
this.dom.containerItems.style.width = this.getWidth() * (this.percentageWidth / 100) + 'px';
|
||
this.dom.containerItems.style.height = this.getHeight() + "px";
|
||
this.dom.panelContainer.style.width = this.getWidth() - (this.getWidth() * (this.percentageWidth / 100)) + 'px';
|
||
this.dom.panelContainer.style.height = this.getHeight() + 'px';
|
||
this.dom.collapsibleBar.style.height = this.getHeight() + 'px';
|
||
jQuery(this.dom.listContainer).css("float", 'left');
|
||
for (i = 0; i < this.items.getSize(); i += 1) {
|
||
this.items.get(i).setWidth(this.getWidth() * (this.percentageWidth / 100) - 12);
|
||
}
|
||
} else {
|
||
this.dom.containerItems.style.width = this.getWidth() + 'px';
|
||
this.dom.containerItems.style.height = '40px';
|
||
this.dom.panelContainer.style.width = this.getWidth() + 'px';
|
||
this.dom.panelContainer.style.height = this.getHeight() - 40 + 'px';
|
||
this.dom.collapsibleBar.style.height = this.getHeight() + 'px';
|
||
$(this.dom.listContainer).css("float", 'left');
|
||
for (i = 0; i < this.items.getSize(); i += 1) {
|
||
this.items.get(i).setWidth('auto');
|
||
}
|
||
}
|
||
break;
|
||
case 'right' :
|
||
case 'bottom' :
|
||
$(this.dom.containerItems).prepend(this.dom.collapsibleBar);
|
||
$(this.html).prepend(this.dom.panelContainer);
|
||
this.dom.containerItems.style.display = this.itemsPosition === 'right' ? "inline-block" : "block";
|
||
this.dom.listContainer.style.display = this.itemsPosition === 'right' ? "inline-block" : "block";
|
||
this.dom.collapsibleBar.style.display = this.itemsPosition === 'right' ? "inline-block" : "none";
|
||
this.dom.panelContainer.style.display = this.itemsPosition === 'right' ? "inline-block" : "block";
|
||
$(this.dom.containerItems).css("float", this.itemsPosition === 'right' ? "right" : "");
|
||
|
||
itemsDisplay = this.itemsPosition === 'right' ? "block" : "inline-block";
|
||
|
||
for (i = 0; i < this.items.getSize(); i += 1) {
|
||
this.items.get(i).setDisplay(itemsDisplay);
|
||
}
|
||
|
||
if (this.itemsPosition == 'right') {
|
||
this.dom.containerItems.style.width = this.getWidth() * (this.percentageWidth / 100) + 'px';
|
||
this.dom.containerItems.style.height = this.getHeight() + "px";
|
||
this.dom.panelContainer.style.width = this.getWidth() - (this.getWidth() * (this.percentageWidth / 100)) + 'px';
|
||
this.dom.panelContainer.style.height = this.getHeight() + 'px';
|
||
this.dom.collapsibleBar.style.height = this.getHeight() + 'px';
|
||
$(this.dom.listContainer).css("float", 'right');
|
||
for (i = 0; i < this.items.getSize(); i += 1) {
|
||
this.items.get(i).setWidth(this.getWidth() * (this.percentageWidth / 100));
|
||
}
|
||
} else {
|
||
this.dom.containerItems.style.width = this.getWidth() + 'px';
|
||
this.dom.containerItems.style.height = '40px';
|
||
this.dom.panelContainer.style.width = this.getWidth() + 'px';
|
||
this.dom.panelContainer.style.height = this.getHeight() + 'px';
|
||
this.dom.collapsibleBar.style.height = this.getHeight() + 'px';
|
||
$(this.dom.listContainer).css("float", 'none');
|
||
for (i = 0; i < this.items.getSize(); i += 1) {
|
||
this.items.get(i).setWidth('auto');
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Create html for each item to container
|
||
* @return {Object} the current object html
|
||
*/
|
||
TabPanel.prototype.createHTML = function () {
|
||
var containerItems,
|
||
panelContainer,
|
||
collapsibleBar,
|
||
listContainer,
|
||
i;
|
||
|
||
if (this.html) {
|
||
return html;
|
||
}
|
||
this.html = PMUI.createHTMLElement('div');
|
||
this.html.className = 'pmui-tabpanel';
|
||
this.html.id = this.id;
|
||
containerItems = PMUI.createHTMLElement('div');
|
||
listContainer = PMUI.createHTMLElement('ul');
|
||
collapsibleBar = PMUI.createHTMLElement('div');
|
||
panelContainer = PMUI.createHTMLElement('div');
|
||
|
||
containerItems.className = "pmui-tabpanel-tabs_container";
|
||
listContainer.className = "pmui-tabpanel-tabs";
|
||
collapsibleBar.className = "pmui-collapsibleBar";
|
||
panelContainer.className = "pmui-tabpanel-container";
|
||
|
||
this.dom.containerItems = containerItems;
|
||
this.dom.listContainer = listContainer;
|
||
this.dom.collapsibleBar = collapsibleBar;
|
||
this.dom.panelContainer = panelContainer;
|
||
this.dom.panelContainer.style.overflow = 'auto';
|
||
this.setItems(this.items.asArray().slice(0));
|
||
|
||
this.dom.containerItems.appendChild(this.dom.listContainer);
|
||
this.dom.containerItems.appendChild(this.dom.collapsibleBar);
|
||
this.html.appendChild(this.dom.containerItems);
|
||
this.html.appendChild(this.dom.panelContainer);
|
||
|
||
if (this.itemsPosition == 'left' || this.itemsPosition == 'right') {
|
||
this.setItemsPosition({position: this.itemsPosition, percentageWidth: this.percentageWidth});
|
||
} else {
|
||
this.setItemsPosition(this.itemsPosition);
|
||
}
|
||
this.applyStyle();
|
||
if (this.eventsDefined) {
|
||
this.defineEvents();
|
||
}
|
||
|
||
for (i = 0; i < this.items.getSize(); i += 1) {
|
||
if (!this.getItems()[i].visible) {
|
||
this.hideTab(i)
|
||
}
|
||
}
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Executes children events defined
|
||
* @chainable
|
||
*/
|
||
TabPanel.prototype.defineEvents = function () {
|
||
var that = this,
|
||
i,
|
||
auxPercentageWidth;
|
||
|
||
this.removeEvents().eventsDefined = true;
|
||
if (this.dom.collapsibleBar && this.collapsible) {
|
||
this.addEvent('click').listen(this.dom.collapsibleBar, function (e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
auxPercentageWidth = that.percentageWidth;
|
||
if (that.collapsible) {
|
||
that.setItemsPosition({position: that.itemsPosition, percentageWidth: 9});
|
||
that.collapsible = false;
|
||
that.style.addClasses(['pmui-collipsable']);
|
||
} else {
|
||
that.setItemsPosition({position: that.itemsPosition, percentageWidth: auxPercentageWidth});
|
||
that.style.removeClasses(['pmui-collipsable']);
|
||
that.collapsible = true;
|
||
|
||
}
|
||
that.percentageWidth = auxPercentageWidth;
|
||
|
||
if (typeof that.onTabClick == 'function') {
|
||
|
||
}
|
||
});
|
||
for (i = 0; i < that.items.getSize(); i += 1) {
|
||
that.items.get(i).defineEvents();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
TabPanel.prototype.setWidth = function (width) {
|
||
TabPanel.superclass.prototype.setWidth.call(this, width);
|
||
this.updatePosition();
|
||
return this;
|
||
};
|
||
|
||
TabPanel.prototype.setHeight = function (height) {
|
||
TabPanel.superclass.prototype.setHeight.call(this, height);
|
||
this.updatePosition();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* hides a TabItem, if hidden the last TabItem passes focus to the previous,
|
||
* otherwise the selection will move to the next always
|
||
* @param {Number} index Is the selection of the TabItem that is concealed,
|
||
* must be within the range of the length of existing items
|
||
* @param {[type]} current [when hidden a tabItem, can fix focus in other tabItem]
|
||
* @chainable
|
||
*/
|
||
TabPanel.prototype.hideTab = function (index, current) {
|
||
var item,
|
||
currentTab,
|
||
i,
|
||
len;
|
||
|
||
for (i = 0; i < this.getItems().length; i += 1) {
|
||
if (i === index) {
|
||
item = this.getItems()[i];
|
||
}
|
||
}
|
||
if (!current) {
|
||
if (item.selected) {
|
||
len = index - 1;
|
||
while (len > -1) {
|
||
if (this.getItems()[len].visible === true) {
|
||
currentTab = this.getItems()[len];
|
||
len = -1;
|
||
} else {
|
||
len--;
|
||
}
|
||
}
|
||
if (!currentTab) {
|
||
i = index + 1;
|
||
while (i < this.items.getSize()) {
|
||
if (this.getItems()[i].visible === true) {
|
||
currentTab = this.getItems()[i];
|
||
i = this.items.getSize();
|
||
} else {
|
||
i++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
currentTab = this.getItems()[current];
|
||
}
|
||
|
||
item.setVisible(false);
|
||
item.panel.setVisible(false);
|
||
if (currentTab) {
|
||
currentTab.select();
|
||
}
|
||
return this;
|
||
}
|
||
/**
|
||
* tab shows a hidden item
|
||
* @param {Number} index Este valor es necesario para mostrar TabItem, debe estar dentro de un rango de la longitud de los elementos
|
||
* @chainable
|
||
*/
|
||
TabPanel.prototype.showTab = function (index) {
|
||
|
||
if (typeof index == 'number') {
|
||
if (!this.getItems()[index].visible) {
|
||
this.getItems()[index].setVisible(true);
|
||
this.getItems()[index].panel.setVisible(true);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
|
||
TabPanel.prototype.itemClick = function (index) {
|
||
$($(this.dom.listContainer).find('a')[index]).trigger('click');
|
||
return this;
|
||
};
|
||
|
||
if (typeof exports != 'undefined') {
|
||
module.exports = TabPanel;
|
||
}
|
||
PMUI.extendNamespace("PMUI.panel.TabPanel", TabPanel);
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.panel.AccordionPanel
|
||
* @extends PMUI.core.Panel
|
||
*
|
||
* Class to handle an Accordion component, this is a container for {@link PMUI.item.AccordionItem AccordionItem}.
|
||
*
|
||
* The way of usage the class is showed on the example above
|
||
*
|
||
* @example
|
||
* accordion = new PMUI.panel.AccordionPanel({
|
||
* width: 400,
|
||
* height: 500,
|
||
* hiddenTitle: true,
|
||
* //multipleSelection : true,
|
||
* title: "My accordion",
|
||
* items: [
|
||
* {
|
||
* iconClass: "",
|
||
* title: "First item",
|
||
* selected: true
|
||
* },
|
||
* {
|
||
* iconClass: "pmui-icon pmui-icon-warning",
|
||
* title: "Second item",
|
||
* body: "<a href=\"http://www.google.com\">Google Link</a>",
|
||
* style: {
|
||
* cssProperties: {
|
||
* "background-color": "#f2eaea"
|
||
* }
|
||
* }
|
||
* },
|
||
* {
|
||
* title: "Third item <span class=\"classname-accordion\"></span>"
|
||
* },
|
||
* {
|
||
* title: "Fourth"
|
||
* }, new PMUI.item.AccordionItem({
|
||
* title: "Five"
|
||
* })
|
||
* ],
|
||
* listeners: {
|
||
* select: function (obj, event) {
|
||
* console.log("Selected...", obj);
|
||
* }
|
||
* }
|
||
* });
|
||
* document.body.appendChild(accordion.getHTML());
|
||
* accordion.defineEvents();
|
||
*
|
||
*
|
||
* @constructor
|
||
* Creates a new component
|
||
* @param {Object} [settings] settings The configuration options may be specified as the follow sentence
|
||
* {
|
||
* items: [
|
||
* {
|
||
* title: "First element",
|
||
* body: item // This item can be any element that inherit from {@link PMUI.core.Panel Panel}
|
||
* },
|
||
* {
|
||
* title: "Second element"
|
||
* }
|
||
* ]
|
||
* }
|
||
* @cfg {String} name The name for the field.
|
||
*
|
||
* @cfg {Boolean} [hiddenTitle=true] Represents wether the title of the component will be showed, the
|
||
* otherwise the panel will rendered without title.
|
||
* @cfg {Array} [items=[]] The array contains the basic elements for {@PMUI.panel.AccordionPanel AccordionPanel class}
|
||
* multipleSelection.
|
||
* @cfg {String} [title=""] The title for the panel.
|
||
* @cfg {Number} [heightItem = 'current height * 0.3'] Represents the height for every item
|
||
* @cfg {Object} factory If it necessary is possible replace the current elements by default.
|
||
* factory: {
|
||
* products: {
|
||
* 'accordionitem': PMUI.item.AccordionItem
|
||
* },
|
||
* defaultProduct: "accordionitem"
|
||
* }
|
||
*
|
||
*/
|
||
|
||
var AccordionPanel = function (settings) {
|
||
AccordionPanel.superclass.call(this, settings);
|
||
/**
|
||
* @property {String} [title= ""] The text represents the title of the panel,
|
||
* Whether the {PMUI.panel.AccordionPanel this.hiddenTitle} is false.
|
||
*/
|
||
this.title = null;
|
||
/**
|
||
* @property {Boolean} [hiddenTitle=false] The property represents whether the title
|
||
* will be showed.
|
||
*/
|
||
this.hiddenTitle = null;
|
||
/**
|
||
* @property {Boolean} [multipleSelection=false] If the property is enabled, the {@link PMUI.item.AccordionItem items} can
|
||
* be selected more than one time
|
||
*/
|
||
this.multipleSelection = null;
|
||
/**
|
||
* @property {Object} [listeners] A config object containing one or more handlers to be added
|
||
* to this object during initialization. by default the 'select' handler is enabled
|
||
*/
|
||
this.listeners = {
|
||
/**
|
||
* @event select
|
||
* Fires when a {@link PMUI.item.AccordionItem component} has been selected.
|
||
* @param {Object} accordionItem {@link PMUI.item.AccordionItem AccordionItem}
|
||
* @param {Object} event event
|
||
*/
|
||
select: function () {
|
||
}
|
||
};
|
||
/**
|
||
* @property {HTMLElement} [header=null]
|
||
* The property encapsulate the HTMLElement header for the panel.
|
||
*/
|
||
this.header = null;
|
||
/**
|
||
* @property {HTMLElement} [body=null]
|
||
* The property is related to HTMLElement body that will be used by
|
||
* {@link PMUI.item.AccordionItem items}
|
||
*/
|
||
this.body = null;
|
||
/**
|
||
* @property {HTMLElement} [footer=null]
|
||
* The property encapsulate the HTMLElement footer for the panel.
|
||
*/
|
||
this.footer = null;
|
||
/**
|
||
* @property {String} [iconClass='pmui-accordion-panel-icon']
|
||
* Represents the class name for the icon.
|
||
* It can be replaced on the config JSON if it is necessary
|
||
* @private
|
||
*/
|
||
this.iconClass = null;
|
||
/**
|
||
* @property {String} [headerClass='pmui-accordion-panel-header']
|
||
* Represents the class name for the header of the panel.
|
||
* It can be replaced on the config JSON if it is necessary
|
||
* @private
|
||
*/
|
||
this.headerClass = null;
|
||
/**
|
||
* @property {String} [bodyClass='pmui-accordion-panel-body']
|
||
* Represents the class name for the body of the panel.
|
||
* It can be replaced on the config JSON if it is necessary
|
||
* @private
|
||
*/
|
||
this.bodyClass = null;
|
||
/**
|
||
* @property {String} [footerClass='pmui-accordion-panel-footer']
|
||
* Represents the class name for footer of the panel.
|
||
* It can be replaced on the config JSON if it is necessary
|
||
* @private
|
||
*/
|
||
this.footerClass = null;
|
||
/**
|
||
* @property {String} [containerClass='pmui-accordion-panel-container']
|
||
* Represents the class name for the father container.
|
||
* It can be replaced on the config JSON if it is necessary
|
||
* @private
|
||
*/
|
||
this.containerClass = null;
|
||
/**
|
||
* @property {Number} [heightItem = 'current height * 0.3']
|
||
* Represents the size height for every {@link PMUI.item.AccordionItem item}
|
||
*/
|
||
this.heightItem = null;
|
||
/**
|
||
* determines whether the items of the accordion panel is automatically set when adding a new item
|
||
* @type {Boolean}
|
||
*/
|
||
this.selfAdjusting = null;
|
||
AccordionPanel.prototype.init.call(this, settings);
|
||
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Panel', AccordionPanel);
|
||
/**
|
||
* Defines the object type of the element
|
||
*/
|
||
AccordionPanel.prototype.type = 'Accordion';
|
||
/**
|
||
* Defines the object family of the element
|
||
*/
|
||
AccordionPanel.prototype.family = 'Panel';
|
||
|
||
AccordionPanel.prototype.init = function (settings) {
|
||
var defaults = {
|
||
multipleSelection: false,
|
||
hiddenTitle: false,
|
||
title: '',
|
||
iconClass: 'pmui-accordion-panel-icon',
|
||
headerClass: 'pmui-accordion-panel-header',
|
||
bodyClass: 'pmui-accordion-panel-body',
|
||
footerClass: 'pmui-accordion-panel-footer',
|
||
containerClass: 'pmui-accordion-panel-container',
|
||
heightItem: this.height * 0.3,
|
||
items: [],
|
||
factory: {
|
||
products: {
|
||
'accordionitem': PMUI.item.AccordionItem
|
||
},
|
||
defaultProduct: "accordionitem"
|
||
},
|
||
listeners: {
|
||
select: function () {
|
||
}
|
||
},
|
||
selfAdjusting: false
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setFactory(defaults.factory)
|
||
.setMultipleSelection(defaults.multipleSelection)
|
||
.setHiddenTitle(defaults.hiddenTitle)
|
||
.setTitle(defaults.title)
|
||
.setIconClass(defaults.iconClass)
|
||
.setHeaderClass(defaults.headerClass)
|
||
.setBodyClass(defaults.bodyClass)
|
||
.setFooterClass(defaults.footerClass)
|
||
.setContainerClass(defaults.containerClass)
|
||
.setHeightItem(defaults.heightItem)
|
||
.setChildren(defaults.items)
|
||
.setListeners(defaults.listeners)
|
||
.setSelfAdjusting(defaults.selfAdjusting);
|
||
};
|
||
|
||
AccordionPanel.prototype.adjustHeightItems = function () {
|
||
var maxHeight = this.height,
|
||
headPanel = jQuery(this.header).outerHeight(),
|
||
footerPanel = jQuery(this.footer).outerHeight(),
|
||
headItems = 0,
|
||
footerItems = 0,
|
||
bodyHeight = 0,
|
||
items,
|
||
i,
|
||
j;
|
||
|
||
items = this.getItems();
|
||
|
||
for (i = 0; i < items.length; i += 1) {
|
||
headItems += jQuery(items[i].header.html).outerHeight() + 2;
|
||
if (items[i].footer) {
|
||
footerItems += jQuery(items[i].footer.html).outerHeight();
|
||
}
|
||
}
|
||
|
||
bodyHeight = maxHeight - (headPanel + footerPanel + headItems + footerItems);
|
||
for (j = 0; j < items.length; j += 1) {
|
||
jQuery(items[j].body.html).height(bodyHeight);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Clear all the object's current child items and add new ones
|
||
* @param {Array} items An array where each element can be a {Element} object or a JSON object
|
||
* where is specified the setting for the child item to be added
|
||
* @chainable
|
||
*/
|
||
AccordionPanel.prototype.setChildren = function (items) {
|
||
var i;
|
||
|
||
if (jQuery.isArray(items)) {
|
||
this.clearItems();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
this.addItem(items[i]);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Defines and sets whether the {@link PMUI.item.AccordionItem items} from {@link PMUI.panel.AccordionPanel Accordion}
|
||
* will be selectable
|
||
* @param {Boolean} parameter
|
||
* @return {PMUI.panel.AccordionPanel} this
|
||
*/
|
||
AccordionPanel.prototype.setMultipleSelection = function (parameter) {
|
||
if (typeof parameter === 'boolean') {
|
||
this.multipleSelection = parameter;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets whether the title will be rendered or not inside the header
|
||
* @param {Boolean} enabled
|
||
*/
|
||
AccordionPanel.prototype.setHiddenTitle = function (enabled) {
|
||
if (typeof enabled === 'boolean') {
|
||
this.hiddenTitle = enabled;
|
||
|
||
if (this.html) {
|
||
if (this.hiddenTitle === true) {
|
||
this.header.setAttribute("style", "display:none")
|
||
} else {
|
||
this.header.removeAttribute("style");
|
||
}
|
||
this.adjustHeightItems();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the label for the Accordion title
|
||
* @param {String} title
|
||
*/
|
||
AccordionPanel.prototype.setTitle = function (title) {
|
||
if (typeof title === "string") {
|
||
this.title = title;
|
||
|
||
if (this.html) {
|
||
this.header.children[1].innerHTML = title;
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name for the header
|
||
* @param {String} iconCls
|
||
* @private
|
||
*/
|
||
AccordionPanel.prototype.setIconClass = function (iconCls) {
|
||
this.iconClass = iconCls;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name for the Accordion's header
|
||
* @param {String} class name
|
||
* @private
|
||
*/
|
||
AccordionPanel.prototype.setHeaderClass = function (className) {
|
||
if (typeof className === 'string') {
|
||
this.headerClass = className;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name for the Accordion's body
|
||
* @param {String} class name
|
||
* @private
|
||
*/
|
||
AccordionPanel.prototype.setBodyClass = function (className) {
|
||
if (typeof className === 'string') {
|
||
this.bodyClass = className;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name for the Accordion's footer
|
||
* @param {String} class name
|
||
* @private
|
||
*/
|
||
AccordionPanel.prototype.setFooterClass = function (className) {
|
||
if (typeof className === 'string') {
|
||
this.footerClass = className;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name for the object's container
|
||
* @param {String} class name
|
||
* @private
|
||
*/
|
||
AccordionPanel.prototype.setContainerClass = function (className) {
|
||
if (typeof className === 'string') {
|
||
this.containerClass = className;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the height for every {@link PMUI.item.AccordionItem item}
|
||
* @param {String} height
|
||
*/
|
||
AccordionPanel.prototype.setHeightItem = function (height) {
|
||
this.heightItem = height;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the listeners for the object
|
||
* @param {Object} events
|
||
*/
|
||
AccordionPanel.prototype.setListeners = function (events) {
|
||
if (typeof events === 'object') {
|
||
this.listeners = events;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates all the elements with their corresponding attributes
|
||
* for make a container that encapsulate {@link PMUI.item.AccordionItem items}
|
||
* @return {HTMLElement} HTMLElement
|
||
*/
|
||
AccordionPanel.prototype.createHTML = function () {
|
||
var container,
|
||
header,
|
||
body,
|
||
footer,
|
||
title,
|
||
icon,
|
||
itemsLen,
|
||
i;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
container = AccordionPanel.superclass.prototype.createHTML.call(this);
|
||
header = PMUI.createHTMLElement("div");
|
||
header.setAttribute('class', this.headerClass);
|
||
body = PMUI.createHTMLElement("div");
|
||
body.setAttribute('class', this.bodyClass);
|
||
footer = PMUI.createHTMLElement("div");
|
||
footer.setAttribute('class', this.footerClass);
|
||
|
||
title = PMUI.createHTMLElement("span");
|
||
title.innerHTML = this.title;
|
||
icon = PMUI.createHTMLElement("span");
|
||
icon.setAttribute('class', this.iconClass);
|
||
header.appendChild(icon);
|
||
header.appendChild(title);
|
||
if (this.hiddenTitle) {
|
||
header.setAttribute("style", "display:none;");
|
||
}
|
||
itemsLen = this.items.getSize();
|
||
if (typeof itemsLen === 'number') {
|
||
for (i = 0; i < itemsLen; i += 1) {
|
||
body.appendChild(this.getItems()[i].getHTML());
|
||
}
|
||
}
|
||
|
||
this.header = header;
|
||
this.body = body;
|
||
this.footer = footer;
|
||
|
||
container.appendChild(header);
|
||
container.appendChild(body);
|
||
container.appendChild(footer);
|
||
container.className = this.containerClass;
|
||
this.containmentArea = body;
|
||
this.html = container;
|
||
return this.html;
|
||
};
|
||
|
||
/**
|
||
* Defines events related to the component and call to every DefineEvents method from
|
||
* {@link PMUI.item.AccordionItem items}
|
||
* @return {Object} {@link PMUI.panel.AccordionPanel Accordion}
|
||
*/
|
||
AccordionPanel.prototype.defineEvents = function () {
|
||
var j,
|
||
children,
|
||
that = this;
|
||
|
||
if (that.items.getSize() > 0 && this.eventsDefined !== true) {
|
||
children = that.getItems();
|
||
for (j = 0; j < children.length; j += 1) {
|
||
children[j].defineEvents();
|
||
}
|
||
if (this.selfAdjusting) {
|
||
this.adjustHeightItems();
|
||
}
|
||
this.eventsDefined = true;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
AccordionPanel.prototype.setSelfAdjusting = function (value) {
|
||
if (typeof value === "boolean") {
|
||
this.selfAdjusting = value;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.panel.AccordionPanel', AccordionPanel);
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = AccordionPanel;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.panel.ButtonPanel
|
||
* A panel that contains instances of {@link PMUI.ui.Button Button} and instances of {@link PMUI.ui.TextLabel Label}.
|
||
* @extends {PMUI.core.Panel}
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var a = new PMUI.panel.ButtonPanel({
|
||
* items: [
|
||
* {
|
||
* pmType: 'button',
|
||
* text: 'Click Me'
|
||
* },
|
||
* {
|
||
* pmType: 'label',
|
||
* text: 'and then'
|
||
* },
|
||
* {
|
||
* pmType: 'button',
|
||
* text: 'Click Me'
|
||
* }
|
||
* ]
|
||
* });
|
||
* document.body.appendChild(a.getHTML());
|
||
* a.defineEvents();
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class.
|
||
* @param {Object} [settings={}] An object literal with the config options for the class.
|
||
*
|
||
* @cfg {Array} [items=[]] An array in which each element can be:
|
||
*
|
||
* - An object literal, in this case it can have the config options for create a {@link PMUI.ui.Button Button} or a
|
||
* {@link PMUI.ui.TextLabel Label}, additionally it must include the respective pmType ('button' for Button and 'label'
|
||
* for Label).
|
||
*
|
||
* -A PMUI object, in this case it must be an instance of {@link PMUI.ui.Button Button} or an instance of {@link
|
||
* PMUI.ui.TextLabel Label}.
|
||
*/
|
||
var ButtonPanel = function (settings) {
|
||
ButtonPanel.superclass.call(this, settings);
|
||
this.alignment = null;
|
||
ButtonPanel.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Panel', ButtonPanel);
|
||
/**
|
||
* The object's type.
|
||
* @type {String}
|
||
*/
|
||
ButtonPanel.prototype.type = 'ButtonPanel';
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} [settings={}] An object literal with the config options the new object will be initialized
|
||
* with.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
ButtonPanel.prototype.init = function (settings) {
|
||
var defaults = {
|
||
items: [],
|
||
factory: {
|
||
products: {
|
||
'button': PMUI.ui.Button,
|
||
'label': PMUI.ui.TextLabel
|
||
},
|
||
defaultProduct: 'button'
|
||
},
|
||
layout: 'box',
|
||
alignment: 'center'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setFactory(defaults.factory)
|
||
.setLayout(defaults.layout)
|
||
.setItems(defaults.items)
|
||
.setAlignment(defaults.alignment);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the alignment for the items in the panel.
|
||
* @param {String} alignment A string which can take the values of 'center', 'left', 'right'.
|
||
*/
|
||
ButtonPanel.prototype.setAlignment = function (alignment) {
|
||
if (alignment === 'center' || alignment === 'left' || alignment === 'right') {
|
||
this.alignment = alignment;
|
||
this.style.addProperties({'text-align': alignment});
|
||
return this;
|
||
}
|
||
throw new Error('setAlignment(): The parameter must be "center" or "left" or "right".');
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.panel.ButtonPanel', ButtonPanel);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ButtonPanel;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.panel.List
|
||
*/
|
||
var ListPanel = function (settings) {
|
||
this.dom = {};
|
||
ListPanel.superclass.call(this, settings);
|
||
this.orientation = null;
|
||
this.actions = null;
|
||
this.dataItems = null;
|
||
this.filterable = null;
|
||
this.filterCriteria = null;
|
||
this.filterControl = null;
|
||
this.filterPlaceholder = null;
|
||
this.statusBarMessage = null;
|
||
this.visibleHeader = null;
|
||
this.visibleStatusBar = null;
|
||
this.listHeight = null;
|
||
this.onItemClick = null;
|
||
this.filteredItems = null;
|
||
ListPanel.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Container', ListPanel);
|
||
|
||
ListPanel.prototype.type = "ListPanel";
|
||
|
||
ListPanel.prototype.init = function (settings) {
|
||
var defaults = {
|
||
orientation: 'vertical',
|
||
actions: [],
|
||
dataItems: null,
|
||
itemTextDataBind: null,
|
||
statusBarMessage: null,
|
||
title: "[untitled list]",
|
||
filterPlaceholder: "Search",
|
||
visibleHeader: true,
|
||
visibleStatusBar: true,
|
||
filterable: true,
|
||
listHeight: "auto",
|
||
onItemClick: null
|
||
};
|
||
this.filteredItems = [];
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.filterControl = new PMUI.control.TextControl({
|
||
onKeyUp: this.onFilterControlChangeHandler(),
|
||
style: {
|
||
cssClasses: [
|
||
"pmui-listpanel-search"
|
||
]
|
||
}
|
||
});
|
||
|
||
this.setItemTextDataBind(defaults.itemTextDataBind)
|
||
.setOrientation(defaults.orientation)
|
||
.setElementTag(defaults.elementTag)
|
||
.setActions(defaults.actions)
|
||
.setStatusBarMessage(defaults.statusBarMessage)
|
||
.setFilterPlaceholder(defaults.filterPlaceholder)
|
||
.setTitle(defaults.title)
|
||
.setListHeight(defaults.listHeight)
|
||
.setOnItemClickHandler(defaults.onItemClick);
|
||
|
||
if (defaults.filterable) {
|
||
this.enableFiltering();
|
||
} else {
|
||
this.disableFiltering();
|
||
}
|
||
|
||
if (defaults.visibleHeader) {
|
||
this.showHeader();
|
||
} else {
|
||
this.hideHeader();
|
||
}
|
||
|
||
if (defaults.visibleStatusBar) {
|
||
this.showStatusBar();
|
||
} else {
|
||
this.hideStatusBar();
|
||
}
|
||
};
|
||
|
||
ListPanel.prototype.onItemClickHandler = function (listItem) {
|
||
if (typeof this.onItemClick === 'function') {
|
||
this.onItemClick(this, listItem);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.setOnItemClickHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnItemClickHandler(): The parameter must be a function or a handler.");
|
||
}
|
||
this.onItemClick = handler;
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.setListHeight = function (height) {
|
||
if (typeof height === 'number') {
|
||
this.listHeight = height;
|
||
} else if (/^\d+(\.\d+)?px$/.test(height)) {
|
||
this.listHeight = parseInt(height, 10);
|
||
} else if (/^\d+(\.\d+)?%$/.test(height)) {
|
||
this.listHeight = height;
|
||
} else if (/^\d+(\.\d+)?em$/.test(height)) {
|
||
this.listHeight = height;
|
||
} else if (height === 'auto' || height === 'inherit') {
|
||
this.listHeight = height;
|
||
} else {
|
||
throw new Error('setHeight: height param is not a number');
|
||
}
|
||
if (this.dom.list) {
|
||
this.dom.list.style.height = height + (typeof height === 'number' ? 'px' : '');
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.hideStatusBar = function () {
|
||
this.visibleStatusBar = false;
|
||
if (this.dom.statusBar) {
|
||
this.dom.statusBar.style.display = 'none';
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.showStatusBar = function () {
|
||
this.visibleStatusBar = true;
|
||
if (this.dom.statusBar) {
|
||
this.dom.statusBar.style.display = '';
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.showHeader = function () {
|
||
this.visibleHeader = true;
|
||
if (this.dom.header) {
|
||
this.dom.header.style.display = '';
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.hideHeader = function () {
|
||
this.visibleHeader = false;
|
||
if (this.dom.header) {
|
||
this.dom.header.style.display = 'none';
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.enableFiltering = function () {
|
||
this.filterable = true;
|
||
if (this.dom.toolbar) {
|
||
this.dom.toolbar.style.display = '';
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.disableFiltering = function () {
|
||
this.filterable = false;
|
||
if (this.dom.toolbar) {
|
||
this.dom.toolbar.style.display = 'none';
|
||
}
|
||
this.clearFilter();
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.setTitle = function (title) {
|
||
if (typeof title !== 'string') {
|
||
throw new Error("setTitle(): The parameter must be a string.");
|
||
}
|
||
this.title = title;
|
||
if (this.html) {
|
||
this.dom.header.textContent = title;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.setFilterPlaceholder = function (filterPlaceholder) {
|
||
this.filterControl.setPlaceholder(filterPlaceholder);
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.onFilterControlChangeHandler = function () {
|
||
var that = this;
|
||
return function () {
|
||
var nextFilter = this.getHTML().value;
|
||
if (that.filterCriteria !== nextFilter) {
|
||
that.filter(nextFilter);
|
||
}
|
||
};
|
||
};
|
||
|
||
ListPanel.prototype.setStatusBarMessage = function (statusBarMessage) {
|
||
if (!(statusBarMessage === null || typeof statusBarMessage === 'function')) {
|
||
throw new Error("setStatusBarMessage(): The parameter must be a function or null.")
|
||
}
|
||
this.statusBarMessage = statusBarMessage;
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.setItemTextDataBind = function (itemTextDataBind) {
|
||
var i,
|
||
size;
|
||
|
||
if (!(itemTextDataBind === null || typeof itemTextDataBind === 'string')) {
|
||
throw new Error("setItemTextDataBind(): the parameter must be a string or null.");
|
||
}
|
||
this.itemTextDataBind = itemTextDataBind;
|
||
size = this.items.getSize();
|
||
for (i = 0; i < size; i += 1) {
|
||
this.items.get(i).setTextDataBind(itemTextDataBind);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.setActions = function (actions) {
|
||
if (!jQuery.isArray(actions)) {
|
||
throw new Error("setActions(): The parameter must be an array.");
|
||
}
|
||
this.actions = actions;
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.addItem = function (item) {
|
||
if (item instanceof PMUI.item.ListItem) {
|
||
item.setActions(this.actions).setTextDataBind(this.itemTextDataBind);
|
||
} else if (!item.actions) {
|
||
item.actions = this.actions;
|
||
item.setTextDataBind = this.itemTextDataBind;
|
||
}
|
||
|
||
ListPanel.superclass.prototype.addItem.call(this, item);
|
||
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.setItems = function (items) {
|
||
if (this.actions !== null) {
|
||
ListPanel.superclass.prototype.setItems.call(this, items);
|
||
this.updateStatusBar();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.updateStatusBar = function () {
|
||
var msg,
|
||
size;
|
||
|
||
if (this.dom.statusBar) {
|
||
size = this.filterCriteria ? jQuery(this.containmentArea).find('>li').length : this.items.getSize();
|
||
if (typeof this.statusBarMessage === 'function') {
|
||
msg = this.statusBarMessage(this, size, !!this.filterCriteria, this.filterCriteria);
|
||
} else {
|
||
msg = size + (this.filterCriteria ? " result(s) matching \"" + this.filterCriteria + "\"" : " item(s).");
|
||
}
|
||
this.dom.statusBar.textContent = msg;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.setOrientation = function (orientation) {
|
||
var items,
|
||
displayBlock,
|
||
i;
|
||
|
||
if (orientation !== 'horizontal' && orientation !== 'vertical') {
|
||
throw new Error("setOrientation(): The parameter must be \"horizontal\" or \"vertical\"");
|
||
}
|
||
this.orientation = orientation;
|
||
displayBlock = orientation === 'vertical' ? 'block' : 'inline-block';
|
||
items = this.items.asArray();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
items[i].setDisplay(displayBlock);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.setFactory = function () {
|
||
this.factory = new PMUI.util.Factory({
|
||
products: {
|
||
'listitem': PMUI.item.ListItem
|
||
},
|
||
defaultProduct: 'listitem'
|
||
});
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.getData = function () {
|
||
var i,
|
||
items = this.items.asArray(),
|
||
data = [];
|
||
|
||
for (i = 0; i < items.length; i += 1) {
|
||
data.push(items[i].getData());
|
||
}
|
||
|
||
return data;
|
||
};
|
||
|
||
ListPanel.prototype.clearFilter = function () {
|
||
var i,
|
||
items = this.items.asArray();
|
||
|
||
this.filterCriteria = "";
|
||
if (this.html) {
|
||
for (i = 0; i < items.length; i += 1) {
|
||
jQuery(items[i].html).detach();
|
||
}
|
||
for (i = 0; i < items.length; i += 1) {
|
||
this.containmentArea.appendChild(items[i].getHTML());
|
||
}
|
||
}
|
||
this.updateStatusBar();
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.getFilteredItems = function () {
|
||
return this.filteredItems;
|
||
};
|
||
ListPanel.prototype.filter = function (criteria) {
|
||
var i,
|
||
regExp,
|
||
itemsCopy;
|
||
|
||
this.filteredItems = [];
|
||
if (typeof criteria === 'string') {
|
||
if (criteria === "") {
|
||
this.clearFilter();
|
||
return this;
|
||
}
|
||
this.filterCriteria = criteria;
|
||
} else if (typeof criteria === 'number') {
|
||
this.filterCriteria = criteria.toString(10);
|
||
} else {
|
||
throw new Error("filter(): The parameter must be a string or number");
|
||
}
|
||
|
||
if (!this.containmentArea) {
|
||
return this;
|
||
}
|
||
|
||
regExp = new RegExp(this.filterCriteria.replace(/([\\\.\[\]\^\$\(\)\?\*\+\|\{\}])/g, "\\\$1"), "i");
|
||
itemsCopy = this.items.asArray();
|
||
|
||
for (i = 0; i < itemsCopy.length; i += 1) {
|
||
jQuery(itemsCopy[i].html).detach();
|
||
}
|
||
|
||
for (i = 0; i < itemsCopy.length; i += 1) {
|
||
if (regExp.test(itemsCopy[i].text)) {
|
||
this.containmentArea.appendChild(itemsCopy[i].getHTML());
|
||
this.filteredItems.push(itemsCopy[i]);
|
||
}
|
||
}
|
||
|
||
this.updateStatusBar();
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.defineEvents = function () {
|
||
this.removeEvents().eventsDefined = true;
|
||
this.filterControl.defineEvents();
|
||
return this;
|
||
};
|
||
|
||
ListPanel.prototype.createHTML = function () {
|
||
var list,
|
||
toolbar,
|
||
statusBar,
|
||
header;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
ListPanel.superclass.prototype.createHTML.call(this);
|
||
|
||
list = PMUI.createHTMLElement('ul');
|
||
list.className = 'pmui-listpanel-list';
|
||
toolbar = PMUI.createHTMLElement('div');
|
||
toolbar.className = 'pmui-listpanel-toolbar';
|
||
statusBar = PMUI.createHTMLElement('div');
|
||
statusBar.className = 'pmui-listpanel-statusbar';
|
||
header = PMUI.createHTMLElement('div');
|
||
header.className = 'pmui-listpanel-title';
|
||
this.containmentArea = list;
|
||
|
||
this.dom.list = list;
|
||
this.dom.toolbar = toolbar;
|
||
this.dom.statusBar = statusBar;
|
||
this.dom.header = header;
|
||
|
||
toolbar.appendChild(this.filterControl.getHTML());
|
||
this.html.appendChild(header);
|
||
this.html.appendChild(toolbar);
|
||
this.html.appendChild(list);
|
||
this.html.appendChild(statusBar);
|
||
|
||
this.setTitle(this.title)
|
||
.setListHeight(this.listHeight);
|
||
|
||
if (this.filterable) {
|
||
this.enableFiltering();
|
||
this.filter(this.filterCriteria || "");
|
||
} else {
|
||
this.disableFiltering();
|
||
}
|
||
|
||
if (this.visibleHeader) {
|
||
this.showHeader();
|
||
} else {
|
||
this.hideHeader();
|
||
}
|
||
|
||
if (this.visibleStatusBar) {
|
||
this.showStatusBar();
|
||
} else {
|
||
this.hideStatusBar();
|
||
}
|
||
|
||
this.defineEvents();
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.panel.ListPanel', ListPanel);
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.grid.GridPanel
|
||
* Class to display data in a grid format.
|
||
* @extends PMUI.core.Container
|
||
*
|
||
|
||
*
|
||
* Single grid example:
|
||
|
||
*
|
||
* @example
|
||
* var g;
|
||
|
||
*
|
||
* $(function(){
|
||
* g = new PMUI.grid.GridPanel({
|
||
* pageSize: 6,
|
||
* columns:[
|
||
* {
|
||
* title:'columna1',
|
||
* dataType:'string',
|
||
* columnData: "name"
|
||
* },
|
||
* {
|
||
* title:'columna2',
|
||
* dataType:'number',
|
||
* width : 150,
|
||
* columnData: "lastName",
|
||
* sortable: true
|
||
* },
|
||
* {
|
||
* title:'columna3',
|
||
* dataType:'button',
|
||
* width : "200px",
|
||
* onButtonClick: function(row, grid) {
|
||
* console.log(row, grid);
|
||
* }
|
||
* }
|
||
* ],
|
||
* dataItems: [
|
||
* {
|
||
* name: "Daniel",
|
||
* lastName: "Canedo"
|
||
* }, {
|
||
* name: "John",
|
||
* lastName: "McAllister"
|
||
* }, {
|
||
* name: "Ximena",
|
||
* lastName: "Jimenez"
|
||
* }, {
|
||
* name: "Fernando",
|
||
* lastName: "Fernandez"
|
||
* }, {
|
||
* name: "Rodrigo",
|
||
* lastName: "Rodriguez"
|
||
* }, {
|
||
* name: "Andrea",
|
||
* lastName: "Postigo"
|
||
* }, {
|
||
* name: "Hernando",
|
||
* lastName: "Hernandez"
|
||
* }, {
|
||
* name: "Ramiro",
|
||
* lastName: "Ramirez"
|
||
* }, {
|
||
* name: "Domingo",
|
||
* lastName: "Dominguez"
|
||
* }, {
|
||
* name: "Gonzalo",
|
||
* lastName: "Gonzales"
|
||
* }
|
||
|
||
* ]
|
||
* });
|
||
* document.body.appendChild(g.getHTML());
|
||
* g.defineEvents();
|
||
* });
|
||
*
|
||
* Example with two grids with interchangeable rows.
|
||
*
|
||
* @example
|
||
* var g, g2;
|
||
|
||
*
|
||
* $(function(){
|
||
* g2 = new PMUI.grid.GridPanel({
|
||
* behavior: 'dragdropsort',
|
||
* pageSize: 0,
|
||
* columns: [
|
||
* {
|
||
* title: 'lastName',
|
||
* columnData: 'lastName',
|
||
* sortable: true
|
||
* }
|
||
* ],
|
||
* dataItems: [
|
||
* {
|
||
* name: "Ramiro",
|
||
* lastName: "Ramirez"
|
||
* }, {
|
||
* name: "Pedro",
|
||
* lastName: "Pedraza"
|
||
* }, {
|
||
* name: "Domingo",
|
||
* lastName: "Dominguez"
|
||
* }, {
|
||
* name: "Oliva",
|
||
* lastName: "Olivares"
|
||
* }, {
|
||
* name: "Gonzalo",
|
||
* lastName: "Gonzales"
|
||
* }, {
|
||
* name: "Enrique",
|
||
* lastName: "Enriquez"
|
||
* }
|
||
* ],
|
||
* onDrop: function(container, draggableItem) {
|
||
* var subject = draggableItem.getData();
|
||
* subject = subject.name + " " + subject.lastName;
|
||
* console.log(subject + " was dropped on grid 1");
|
||
* },
|
||
* onSort: function(container, item, index) {
|
||
* var subject = item.getData();
|
||
* subject = subject.name + " " + subject.lastName;
|
||
* console.log(subject + "'s index has changed to " + index);
|
||
|
||
* }
|
||
* });
|
||
* g = new PMUI.grid.GridPanel({
|
||
* behavior: 'dragdropsort',
|
||
* pageSize:6,
|
||
* columns:[
|
||
* {
|
||
* title: 'Initials',
|
||
* columnData: function(data) {
|
||
* return data.name.substr(0, 1) + " " + data.lastName.substr(0, 1);
|
||
* }
|
||
* },
|
||
* {
|
||
* title:'Name',
|
||
* dataType:'string',
|
||
* columnData: "name"
|
||
* },
|
||
* {
|
||
* title:'LastName',
|
||
* dataType:'number',
|
||
* width : 150,
|
||
* columnData: "lastName",
|
||
* sortable: true
|
||
* },
|
||
* {
|
||
* title:'columna3',
|
||
* dataType:'button',
|
||
* width : "200px",
|
||
* onButtonClick: function(row, grid) {
|
||
* console.log(row, grid);
|
||
* }
|
||
* }
|
||
* ],
|
||
* dataItems: [
|
||
* {
|
||
* name: "Daniel",
|
||
* lastName: "Canedo"
|
||
* }, {
|
||
* name: "John",
|
||
* lastName: "McAllister"
|
||
* }, {
|
||
* name: "Ximena",
|
||
* lastName: "Jimenez"
|
||
* }, {
|
||
* name: "Fernando",
|
||
* lastName: "Fernandez"
|
||
* }, {
|
||
* name: "Rodrigo",
|
||
* lastName: "Rodriguez"
|
||
* }, {
|
||
* name: "Andrea",
|
||
* lastName: "Postigo"
|
||
* }, {
|
||
* name: "Hernando",
|
||
* lastName: "Hernandez"
|
||
* }
|
||
* ],
|
||
* onDrop: function(container, draggableItem) {
|
||
* var subject = draggableItem.getData();
|
||
* subject = subject.name + " " + subject.lastName;
|
||
* console.log(subject + " was dropped on grid 2");
|
||
* },
|
||
* onSort: function(container, item, index) {
|
||
* var subject = item.getData();
|
||
* subject = subject.name + " " + subject.lastName;
|
||
* console.log(subject + "'s index has changed to " + index);
|
||
|
||
* }
|
||
* });
|
||
* document.body.appendChild(g.getHTML());
|
||
* document.body.appendChild(g2.getHTML());
|
||
* g.defineEvents();
|
||
* g2.defineEvents();
|
||
* });
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of GridPanel class.
|
||
* @param {Object} [settings=null] A JSON object with the config options.
|
||
*
|
||
* @cfg {Array} [columns=[]] An Array where each element is an object literal or an instance of
|
||
* {@link PMUI.grid.GridPanelColumn}. In case to be an object literal it must have {@link PMUI.grid.GridPanelColumn
|
||
* the config options for GridPanelColumn creation}.
|
||
* @cfg {Array} [items=[]] An Array where each of its elements can be an instance of PMUI.grid.GridPanelRow or a
|
||
* JSON object with the config options to build a new one.
|
||
* @cfg {Array} [dataItems=[]] An Array where each of its elements can be a JSON object with the data available for
|
||
* the item (row) that will be created.
|
||
* @cfg {Number} [pageSize=0] The size for every page in the table, if it is set to 0 (default) then there will no
|
||
* exists pagination.
|
||
* @cfg {Boolean} [draggable=false] If the grid will apply the row dragging behavior.
|
||
* @cfg {Boolean} [filterable=true] If the grid will have the filtering function enabled or not.
|
||
* @cfg {Number} [initialPage=0] The page number to show initially.
|
||
* @cfg {Function} [customStatusBar=null] The function to generate a custom message in the grid's status bar. This
|
||
* function must return a string with the text to be used as the message to be displayed in thegrid's status bar.
|
||
* When the function is called 5 parameters will be sent:
|
||
*
|
||
* - The current page (Number).
|
||
* - The page size (Number).
|
||
* - The number of items (Number).
|
||
* - If a criteria is being applied to the grid (Boolean).
|
||
* - The filter criteria applied to the grid (String).
|
||
*
|
||
* If you need access more grid's properties you can use 'this' to refer the grid since the function is called in
|
||
* the grid's context.
|
||
* @cfg {Object|PMUI.util.Style|null} [rowStyle=null] The style to be applied to the grid's rows. It can be:
|
||
*
|
||
* - An object literal: in this case the object can have the properties:
|
||
* - cssClasses: an array of strings, each string is a css class that will be applied to each row's html.
|
||
* - cssProperties: an object literal in which each property is a valid css property and its value is a valid
|
||
* css value for the respective css property.
|
||
*
|
||
* - An instance of the {@link PMUI.util.Style Style} class.
|
||
* - null, in this case no custom style will be applied to the html of the grid's rows.
|
||
*
|
||
* @cfg {String} [filterPlaceholder] Sets the placeholder for the filter textbox.
|
||
* @cfg {Boolean} [visibleHeaders=true] Turns on/off the visibility of the column headers.
|
||
* @cfg {String} [sortableItems='> tr'] Specifies which items inside the element should be sortable in case a
|
||
* sort behavior is applied. It must be a jQuery selector.
|
||
* @cfg {Function|null} [onEmpty=null] A callback function to be called everytime the grid's last item is removed.
|
||
* The value for this config option can be a function or the null constant for no callback execution. For more
|
||
* info about the paramerters sent to the function please read the {@link #event-onEmpty onEmpty} event
|
||
* documentation.
|
||
* @cfg {Function|null} [onRowClick=null] The callback function to be executed everytime the
|
||
* {@link #event-onRowClick onRowClick} event is fired. Read about this event to know about the parameters received
|
||
* by the callback function.
|
||
* @cfg {String|Function|null} [emptyMessage=null] The message to show when the grid is showing no items. It
|
||
* can be:
|
||
*
|
||
* - A String, in this case the string will be displayed in both cases, when the grid has no items and when no
|
||
* grid's item meet the filter.
|
||
* - A Function, in this case the function must return a string or an HTML Element to be displayed. The function
|
||
* will receive two parameters: the {@link PMUI.grid.Grid grid}, a boolean If it is true it means the returned
|
||
* value will be used when a filter is applied, otherwise it means that the returned value will be used when
|
||
* there are no items in the grid.
|
||
* - null, in this case a default message will be used for each situation.
|
||
*/
|
||
var GridPanel = function (settings) {
|
||
/**
|
||
* A JSON object that contains the object's DOM components.
|
||
* @type {Object}
|
||
* @private
|
||
*/
|
||
this.dom = {};
|
||
/**
|
||
* The grid's list of {@link PMUI.grid.GridPanelColumn column objects}.
|
||
* @type {PMUI.ui.ArrayList}
|
||
* @private
|
||
*/
|
||
this.columns = new PMUI.util.ArrayList();
|
||
GridPanel.superclass.call(this, jQuery.extend({
|
||
factory: {
|
||
products: {
|
||
"GridPanelRow": PMUI.grid.GridPanelRow
|
||
},
|
||
defaultProduct: "GridPanelRow"
|
||
}
|
||
}, settings, {
|
||
elementTag: "div"
|
||
}));
|
||
this.pages = null;
|
||
this.displayedPages = null;
|
||
this.prevText = null;
|
||
this.nextText = null;
|
||
this.invertPageOrder = null;
|
||
this.labelMap = null;
|
||
this.hrefTextPrefix = null;
|
||
this.hrefTextSuffix = null;
|
||
this.nextAtFront = null;
|
||
this.edges = null;
|
||
this.useStartEdge = null;
|
||
this.ellipseText = null;
|
||
this.selectOnClick = null;
|
||
this.useEndEdge = null;
|
||
/**
|
||
* The number of rows to show in every page, 0 means no limit.
|
||
* @type {Number}
|
||
* @readonly
|
||
*/
|
||
this.pageSize = null;
|
||
/**
|
||
* If the grid has the filtering functiionality enabled or not.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.filterable = null;
|
||
/**
|
||
* The current filter criteria.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.filterCriteria = null;
|
||
/**
|
||
* The current page being displayed.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.currentPage = null;
|
||
/**
|
||
* If the column sorting functionloty is enabled or not.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.sortable = null;
|
||
/**
|
||
* The {@link PMUI.control.TextControl TextControl} object that is playing the filter text input control role.
|
||
* @type {PMUI.control.TextControl}
|
||
* @private
|
||
*/
|
||
this.filterControl = null;
|
||
/**
|
||
* The {@link PMUI.ui.Button Button} to executes the filtering.
|
||
* @type {[type]}
|
||
*/
|
||
this.filterButton = null;
|
||
/**
|
||
* An {@link PMUI.util.ArrayList ArrayList} that contains the rows ordered by the
|
||
* {@link #property-filterCriteria filterCriteria}.
|
||
* @type {PMUI.util.ArrayList}
|
||
* @private
|
||
*/
|
||
this.usableItemsList = null;
|
||
/**
|
||
* An {@link PMUI.util.ArrayList ArrayList} that contains only the rows that meet the filter criteria.
|
||
* @type {PMUI.util.ArrayList}
|
||
* @private
|
||
*/
|
||
this.filteredItems = null;
|
||
/**
|
||
* @property {Function} statusBarHandler The function to generate a custom message in the grid's status bar.
|
||
*/
|
||
this.customStatusBar = null;
|
||
/**
|
||
* The style to be applied to all the rows in the grid.
|
||
* @type {PMUI.util.Style}
|
||
* @private
|
||
*/
|
||
this.rowStyle = null;
|
||
/**
|
||
* The placeholder to be used in the text control for filtering. It is set by the
|
||
* {@link #cfg-filterPlaceholder filterPlaceholder} config option and the
|
||
* {@link #method-setFilterPlaceholer setFilterPlaceholer()} method.
|
||
* @type {String}
|
||
*/
|
||
this.filterPlaceholder = null;
|
||
/**
|
||
* The data about the sorting that is currently applied to the grid.
|
||
* @type {Object}
|
||
*/
|
||
this.sortingData = null;
|
||
/**
|
||
* @event onRowClick
|
||
* Fired everytime a grid's row is clicked.
|
||
* @param {PMUI.grid.GridPanelRow} row The row object the click was performed on.
|
||
* @param {Object} data The row's data
|
||
*/
|
||
this.onRowClick = null;
|
||
/**
|
||
* @event onEmpty
|
||
* Fired everytime the Grid removes its last item.
|
||
* @param {PMUI.grid.GridPanel} grid The GridPanel object.
|
||
*/
|
||
this.onEmpty = null;
|
||
/**
|
||
* If the column headers are visible or not, it is set by the {@link #cfg-visibleHeaders visibleHeaders} config
|
||
* option and the {@link #method-hideHeaders hideHeaders()} and {@link #method-showHeaders showHeaders()}.
|
||
* @type {Boolean}
|
||
*/
|
||
this.visibleHeaders = null;
|
||
/**
|
||
* [selectedRow description]
|
||
* @type {[type]}
|
||
*/
|
||
this.selectedRow = null;
|
||
/**
|
||
* [selectable description]
|
||
* @type {[type]}
|
||
*/
|
||
this.selectable = null;
|
||
/**
|
||
* If the footer is visible or not.
|
||
* @type {Boolean}
|
||
*/
|
||
this.visibleFooter = null;
|
||
/**
|
||
* The message to be displayed in the grid when there are no items to display. Set by the
|
||
* {@link #cfg-emptyMessage emptyMessage config option} and the
|
||
* {@link #method-setEmptyMessage setEmptyMessage()} method.
|
||
* @type {String|Function}
|
||
*/
|
||
this.emptyMessage = null;
|
||
this._dynamicLoad = null;
|
||
this.keys = null;
|
||
this.customDataRest;
|
||
/**
|
||
* Height for the HTML element tableContainer, it can be a number or a string with the following format:
|
||
##px when ## is a number.
|
||
* @type {Number|String}
|
||
* @readonly
|
||
*/
|
||
this.tableContainerHeight = "";
|
||
GridPanel.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom("PMUI.core.Container", GridPanel);
|
||
/**
|
||
* The object type.
|
||
* @type {String}
|
||
*/
|
||
GridPanel.prototype.type = "GridPanel";
|
||
/**
|
||
* The object's family.
|
||
* @type {String}
|
||
*/
|
||
GridPanel.prototype.family = "GridPanel";
|
||
/**
|
||
* Initialize the object.
|
||
* @param {Object} settings A JSON object with the setting options.
|
||
* @private
|
||
*/
|
||
GridPanel.prototype.init = function (settings) {
|
||
var defaults = {
|
||
columns: [],
|
||
items: [],
|
||
dataItems: null,
|
||
pages: 0,
|
||
displayedPages: 3,
|
||
prevText: 'Prev'.translate(),
|
||
nextText: 'Next'.translate(),
|
||
invertPageOrder: false,
|
||
labelMap: [],
|
||
hrefTextPrefix: '#page-',
|
||
hrefTextSuffix: '',
|
||
nextAtFront: false,
|
||
edges: 2,
|
||
useStartEdge: true,
|
||
ellipseText: '…',
|
||
selectOnClick: true,
|
||
useEndEdge: true,
|
||
pageSize: 0,
|
||
filterable: true,
|
||
inititalPage: 0,
|
||
customStatusBar: null,
|
||
rowStyle: null,
|
||
visibleHeaders: true,
|
||
filterPlaceholder: "",
|
||
onRowClick: null,
|
||
sortableItems: '> tr:not(.pmui-nodrag)',
|
||
onEmpty: null,
|
||
emptyMessage: null,
|
||
selectable: false,
|
||
visibleFooter: true,
|
||
dynamicLoad: false,
|
||
keys: {},
|
||
tableContainerHeight: "auto"
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
this.totalRows = 0;
|
||
|
||
this.usableItemsList = new PMUI.util.ArrayList();
|
||
this.sortingData = {
|
||
criteria: null,
|
||
type: null
|
||
};
|
||
this.rowStyle = new PMUI.util.Style();
|
||
this.filterControl = new PMUI.control.TextControl({
|
||
onKeyUp: this.onFilterControlChangeHandler(),
|
||
style: {
|
||
cssClasses: [
|
||
"pmui-gridpanel-search"
|
||
]
|
||
}
|
||
});
|
||
this.filterButton = new PMUI.ui.Button({
|
||
text: 'Search',
|
||
style: {
|
||
cssClasses: [
|
||
"pmui-gridpanel-buttonsearch"
|
||
]
|
||
}
|
||
});
|
||
this.filteredItems = new PMUI.util.ArrayList();
|
||
|
||
this.setPageSize(defaults.pageSize)
|
||
.setCurrentPage(defaults.inititalPage);
|
||
|
||
this.setSortableItems(defaults.sortableItems)
|
||
.setSelectable(defaults.selectable)
|
||
.setEmptyMessage(defaults.emptyMessage)
|
||
.setOnEmptyHandler(defaults.onEmpty)
|
||
.setRowStyle(defaults.rowStyle)
|
||
.setColumns(defaults.columns)
|
||
.setCustomStatusBar(defaults.customStatusBar)
|
||
.setFilterPlaceholder(defaults.filterPlaceholder)
|
||
.setOnRowClick(defaults.onRowClick)
|
||
.setVisibleFooter(defaults.visibleFooter)
|
||
.setDisplayedPages(defaults.displayedPages)
|
||
.setPages(defaults.pages)
|
||
.setPrevText(defaults.prevText)
|
||
.setNextText(defaults.nextText)
|
||
.setInvertPageOrder(defaults.invertPageOrder)
|
||
.setLabelMap(defaults.labelMap)
|
||
.setHrefTextPrefix(defaults.hrefTextPrefix)
|
||
.setHrefTextSuffix(defaults.hrefTextSuffix)
|
||
.setNextAtFront(defaults.nextAtFront)
|
||
.setEdgesPagination(defaults.edges)
|
||
.setUseStartEdge(defaults.useStartEdge)
|
||
.setEllipseText(defaults.ellipseText)
|
||
.setSelectOnClick(defaults.selectOnClick)
|
||
.setUseEndEdge(defaults.useEndEdge)
|
||
.setDynamicLoad(defaults.dynamicLoad)
|
||
.setCustomDataRest(defaults.customDataRest)
|
||
.setTableContainerHeight(defaults.tableContainerHeight);
|
||
|
||
if (jQuery.isArray(defaults.dataItems)) {
|
||
this.setDataItems(defaults.dataItems);
|
||
} else {
|
||
this.setItems(defaults.items);
|
||
}
|
||
|
||
|
||
if (defaults.filterable) {
|
||
this.enableFiltering();
|
||
} else {
|
||
this.disableFiltering();
|
||
}
|
||
if (defaults.visibleHeaders) {
|
||
this.showHeaders();
|
||
} else {
|
||
this.hideHeaders();
|
||
}
|
||
this.updateUsableItemsList();
|
||
};
|
||
/**
|
||
* Set the height for the HTML element tableContainer
|
||
* @param {Number|String} height it can be a number or a string.
|
||
* In case of using a String you only can use 'auto' or 'inherit' or ##px or ##% or ##em when ## is a number.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setTableContainerHeight = function(height){
|
||
if (typeof height === 'number') {
|
||
height = height+"px";
|
||
} else if (/^\d+(\.\d+)?px$/.test(height)) {
|
||
height = height;
|
||
} else if (/^\d+(\.\d+)?%$/.test(height)) {
|
||
height = height;
|
||
} else if (/^\d+(\.\d+)?em$/.test(height)) {
|
||
height = height;
|
||
} else if (height === 'auto' || height === 'inherit') {
|
||
height = height;
|
||
} else {
|
||
throw new Error('setHeight: height param is not a number');
|
||
}
|
||
this.tableContainerHeight = height;
|
||
return this;
|
||
};
|
||
|
||
GridPanel.prototype.setCustomDataRest = function (handlder) {
|
||
if (typeof handlder === "function") {
|
||
this.customDataRest = handlder;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridPanel.prototype.setKeys = function (keys) {
|
||
if (!(keys.server && keys.projectID && keys.workspace && keys.accessToken && keys.endPoint)) {
|
||
throw new Error('setKeys(): The parameter, in case of being an object, must define server, projectId, authBearer, URL, pageParam, totalPages;');
|
||
}
|
||
this.keys = keys || {};
|
||
this.url = keys.server;
|
||
this.url = this.url + "/api/1.0/" + keys.workspace + "/";
|
||
this.url = this.url + keys.endPoint;
|
||
return this;
|
||
};
|
||
GridPanel.prototype.setDynamicLoad = function (dynamicLoad) {
|
||
this._dynamicLoad = !!dynamicLoad ? dynamicLoad : false;
|
||
if (this._dynamicLoad.hasOwnProperty("keys")) {
|
||
this.setKeys(this._dynamicLoad["keys"]);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @inherirdoc
|
||
*/
|
||
GridPanel.prototype.setDataItems = function (dataItems) {
|
||
if (this.usableItemsList) {
|
||
GridPanel.superclass.prototype.setDataItems.call(this, dataItems);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
GridPanel.prototype.setItems = function (items) {
|
||
if (this.usableItemsList) {
|
||
GridPanel.superclass.prototype.setItems.call(this, items);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the message to display when there are no items to display in the grid.
|
||
* @param {String|Function|null} emptyMessage It can be:
|
||
*
|
||
* - A String, in this case the string will be displayed in both cases, when the grid has no items and when no
|
||
* grid's item meet the filter.
|
||
* - A Function, in this case the function must return a string or an HTML Element to be displayed. The function
|
||
* will receive two parameters: the {@link PMUI.grid.Grid grid}, a boolean If it is true it means the returned
|
||
* value will be used when a filter is applied, otherwise it means that the returned value will be used when
|
||
* there are no items in the grid.
|
||
* - null, in this case a default message will be used for each situation.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setEmptyMessage = function (emptyMessage) {
|
||
if (!(emptyMessage === null || typeof emptyMessage === 'string' || typeof emptyMessage === 'function')) {
|
||
throw new Error("setEmptyMessage(): the parameter must be a string, a function or null.");
|
||
}
|
||
this.emptyMessage = emptyMessage;
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables the behaviors and column's buttons.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.disable = function () {
|
||
this.disableColumn();
|
||
return GridPanel.superclass.prototype.disable.call(this);
|
||
};
|
||
/**
|
||
* Enables the behaviors and column's buttons.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.enable = function () {
|
||
this.enableColumn();
|
||
return GridPanel.superclass.prototype.enable.call(this);
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
GridPanel.prototype.getBehavioralItems = function () {
|
||
var items = [],
|
||
initialIndex = this.currentPage * this.pageSize,
|
||
finalIndex = initialIndex + this.pageSize,
|
||
i;
|
||
|
||
for (i = initialIndex; i < finalIndex && this.getItem(i); i += 1) {
|
||
items.push(this.getItem(i));
|
||
}
|
||
return items;
|
||
};
|
||
/**
|
||
* Enables one or all the columns.
|
||
* @param {String|Number|PMUI.grid.GridPanelColumn} [column] A criteria to select the column that will be
|
||
* enabled. It supports the following data types:
|
||
*
|
||
* - String, in this case the parameter is used as the column's id.
|
||
* - Number, in this case the parameter is used as the column's index.
|
||
* - An instance of {@link PMUI.grid.GridPanelColumn GridPanelColumn}, in this case the supplied object must be
|
||
* a child of the grid.
|
||
* - [no value], since this parameter is optional, you can skip it. In this case all the columns in the grid will
|
||
* be enabled.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.enableColumn = function (column) {
|
||
var i,
|
||
targetColumn = this.getColumns(column);
|
||
|
||
for (i = 0; i < targetColumn.length; i += 1) {
|
||
if (targetColumn[i].dataType === 'button') {
|
||
targetColumn[i].enable();
|
||
}
|
||
}
|
||
this.disabled = false;
|
||
this.style.removeClasses(['pmui-disabled']);
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables one or all the columns.
|
||
* @param {String|Number|PMUI.grid.GridPanelColumn} [column] A criteria to select the column that will be
|
||
* disabled. It supports the following data types:
|
||
*
|
||
* - String, in this case the parameter is used as the column's id.
|
||
* - Number, in this case the parameter is used as the column's index.
|
||
* - An instance of {@link PMUI.grid.GridPanelColumn GridPanelColumn}, in this case the supplied object must be
|
||
* a child of the grid.
|
||
* - [no value], since this parameter is optional, you can skip it. In this case all the columns in the grid will
|
||
* be disabled.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.disableColumn = function (column) {
|
||
var i,
|
||
targetColumn = this.getColumns(column);
|
||
|
||
for (i = 0; i < targetColumn.length; i += 1) {
|
||
if (targetColumn[i].dataType === 'button') {
|
||
targetColumn[i].disable();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the width to one or all the columns.
|
||
* @param {Number|String} width The width to be applied to the column(s).
|
||
* @param {String|Number|PMUI.grid.GridPanelColumn} [column] A criteria to select the column the width will be
|
||
* applied. It supports the following data types:
|
||
*
|
||
* - String, in this case the parameter is used as the column's id.
|
||
* - Number, in this case the parameter is used as the column's index.
|
||
* - An instance of {@link PMUI.grid.GridPanelColumn GridPanelColumn}, in this case the supplied object must be
|
||
* a child of the grid.
|
||
* - [no value], since this parameter is optional, you can skip it. In this case the width will be applied to all
|
||
* the columns in the grid.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setColumnWidth = function (width, column) {
|
||
var targetColumn = [],
|
||
aux,
|
||
i;
|
||
|
||
if (typeof column === 'string') {
|
||
aux = this.columns.find("id", column);
|
||
} else if (typeof column === 'number') {
|
||
aux = this.columns.get(column);
|
||
} else if (column instanceof PMUI.grid.GridPanelColumn && this.isDirectParentOf(column)) {
|
||
targetColumn.push(column);
|
||
} else if (column === undefined) {
|
||
targetColumn = this.column.asArray();
|
||
}
|
||
if (aux) {
|
||
targetColumn.push(aux);
|
||
}
|
||
for (i = 0; i < targetColumn.length; i += 1) {
|
||
targetColumn[i].setWidth(width);
|
||
}
|
||
if (i > 0) {
|
||
this.goToPage(this.currentPage);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the function callback to be called everytime the grid's last item is removed.
|
||
* @param {Function|null} handler The callback function or the null constant for no callback execution. For more
|
||
* info about the paramerters sent to the function please read the {@link #event-onEmpty onEmpty} event
|
||
* documentation.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setOnEmptyHandler = function (handler) {
|
||
if (!(typeof handler === 'function' || handler === null)) {
|
||
throw new Error('setOnEmptyHandler(): The parameter must be a function or null.');
|
||
}
|
||
this.onEmpty = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows the column headers.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.showHeaders = function () {
|
||
this.visibleHeaders = true;
|
||
if (this.html) {
|
||
this.dom.thead.style.display = '';
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Hide the column headers.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.hideHeaders = function () {
|
||
this.visibleHeaders = false;
|
||
if (this.html) {
|
||
this.dom.thead.style.display = 'none';
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Updates the usable items list.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
GridPanel.prototype.updateUsableItemsList = function () {
|
||
if (this.usableItemsList) {
|
||
this.usableItemsList.set(this.items.asArray());
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the placeholder for the filter textbox.
|
||
* @param {String} filterPlaceholder
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setFilterPlaceholder = function (filterPlaceholder) {
|
||
if (typeof filterPlaceholder !== 'string') {
|
||
throw new Error('setFilterPlaceholder(): The parameter must be a string.');
|
||
}
|
||
this.filterControl.setPlaceholder(this.filterPlaceholder = filterPlaceholder);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the custom style to be applied to the grid's rows.
|
||
* @param {Object|PMUI.util.Style|null} rowStyle It can be an object literal (with the properties
|
||
* cssProperties and/or cssClasses), an instance of PMUI.util.Style or null (in this case no custom style will be
|
||
* applied to the rows).
|
||
*/
|
||
GridPanel.prototype.setRowStyle = function (rowStyle) {
|
||
var i,
|
||
rows,
|
||
rowsLength;
|
||
|
||
if (rowStyle !== null && typeof rowStyle !== 'object' && !(rowStyle instanceof PMUI.util.Style)) {
|
||
throw new Error("setRowStyle(): The parameter must be null or an object literal or an instance of "
|
||
+ "PMUI.grid.GridPanelRow.");
|
||
}
|
||
this.rowStyle.clear();
|
||
if (rowStyle instanceof PMUI.util.Style) {
|
||
this.rowStyle = rowStyle;
|
||
} else if (rowStyle) {
|
||
this.rowStyle.addProperties(rowStyle.cssProperties || {})
|
||
.addClasses(rowStyle.cssClasses || []);
|
||
}
|
||
rows = this.items.asArray();
|
||
rowsLength = rows.length;
|
||
for (i = 0; i < rowsLength; i += 1) {
|
||
rows[i].setStyle({
|
||
cssProperties: this.rowStyle.cssProperties,
|
||
cssClasses: this.rowStyle.cssClasses
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets a function to generate a custom message in the grid's status bar.
|
||
* @param {Function|NULL} handler The function for generate the message to be shown in the grid's status bar. It
|
||
* also can be NULL, in this case the message shown in the grid's status bar wiil be the default one.
|
||
* For more info about the sent parameters to the function read the {@link #cfg-customStatusBar customStatusBar}
|
||
* config option.
|
||
*/
|
||
GridPanel.prototype.setCustomStatusBar = function (handler) {
|
||
if (!(typeof handler === 'function' || handler === null)) {
|
||
throw new Error('setCustomStatusBar(): this method only accepts as parameter a function or null.');
|
||
}
|
||
this.customStatusBar = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Enables the filter functionality.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.enableFiltering = function () {
|
||
this.filterable = true;
|
||
if (this.dom.toolbar) {
|
||
this.dom.toolbar.style.display = '';
|
||
if (!this._dynamicLoad) {
|
||
this.goToPage(this.currentPage);
|
||
}
|
||
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables the filter functionality.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.disableFiltering = function () {
|
||
this.filterable = false;
|
||
if (this.dom.toolbar) {
|
||
this.dom.toolbar.style.display = 'none';
|
||
this.filterCriteria = "";
|
||
this.filterControl.setValue("");
|
||
if (!this._dynamicLoad) {
|
||
this.goToPage(this.currentPage);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the index in page for the specified row.
|
||
* @param {PMUI.grid.GridPanelRow|Number|String} row It can be:
|
||
*
|
||
* - {@link PMUI.grid.GridPanelRow}.
|
||
* - Number, in this case it is interpreted as the global index for the row.
|
||
* - String, it will be interpreted as the row's id.
|
||
* @return {Number}
|
||
*/
|
||
GridPanel.prototype.indexInPage = function (row) {
|
||
var globalIndex = this.getItemIndex(row);
|
||
|
||
if (this.pageSize !== 0 && globalIndex >= 0) {
|
||
globalIndex = globalIndex % this.pageSize;
|
||
}
|
||
|
||
return globalIndex;
|
||
};
|
||
/**
|
||
* Returns the handler to be executed when the filter changes.
|
||
* @return {Function}
|
||
* @private
|
||
*/
|
||
GridPanel.prototype.onFilterControlChangeHandler = function () {
|
||
var that = this;
|
||
|
||
return function () {
|
||
var nextFilter = this.getHTML().value;
|
||
|
||
if (that.filterCriteria !== nextFilter) {
|
||
that.filter(nextFilter);
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Sets the columns.
|
||
* @param {Array} columns An Array where each element is an object literal with the
|
||
* {@link PMUI.grid.GridPanelColumn the config options for GridPanelColumn creation} or a
|
||
* {@link PMUI.grid.GridPanelColumn GridPanelColumn object}.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setColumns = function (columns) {
|
||
var i;
|
||
|
||
this.clearColumns();
|
||
if (!jQuery.isArray(columns)) {
|
||
throw new Error("setColumns(): The parameter must be an Array");
|
||
}
|
||
|
||
for (i = 0; i < columns.length; i += 1) {
|
||
this.addColumn(columns[i]);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns one or all the grid's columns.
|
||
* @param {String|Number|PMUI.grid.GridPanelColumn} [column] A criteria to select the column that will be
|
||
* returned. It supports the following data types:
|
||
*
|
||
* - String, in this case the parameter is used as the column's id.
|
||
* - Number, in this case the parameter is used as the column's index.
|
||
* - An instance of {@link PMUI.grid.GridPanelColumn GridPanelColumn}, in this case the supplied object must be
|
||
* a child of the grid.
|
||
* - [no value], since this parameter is optional, you can skip it. In this case all the columns in the grid will
|
||
* be returned.
|
||
* @return {Array}
|
||
*/
|
||
GridPanel.prototype.getColumns = function (column) {
|
||
var targetColumn = [],
|
||
aux;
|
||
|
||
if (typeof column === 'string') {
|
||
aux = this.columns.find("id", column);
|
||
} else if (typeof column === 'number') {
|
||
aux = this.columns.get(column);
|
||
} else if (column instanceof PMUI.grid.GridPanelColumn && this.isDirectParentOf(column)) {
|
||
targetColumn.push(column);
|
||
} else if (column === undefined) {
|
||
targetColumn = this.columns.asArray().slice(0);
|
||
}
|
||
if (aux) {
|
||
targetColumn.push(aux);
|
||
}
|
||
return targetColumn;
|
||
};
|
||
/**
|
||
* Paints a column into the grid's head.
|
||
* @param {PMUI.grid.GridPanelColumn} column
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
GridPanel.prototype.paintColumn = function (column) {
|
||
if (this.dom.thead) {
|
||
this.dom.thead.appendChild(column.getHTML());
|
||
}
|
||
return this;
|
||
};
|
||
GridPanel.prototype.paintColumns = function () {
|
||
var i,
|
||
columns = this.columns.asArray();
|
||
|
||
for (i = 0; i < columns.length; i += 1) {
|
||
this.paintColumn(columns[i]);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a column.
|
||
* @param {PMUI.grid.GridPanelColumn|JSON} column A {@link PMUI.grid.GridPanelColumn} or a JSON Object with the
|
||
* {@link PMUI.grid.GridPanelColumn#cfg config options} for the new column.
|
||
*/
|
||
GridPanel.prototype.addColumn = function (column) {
|
||
var that = this,
|
||
columnToAdd,
|
||
rows,
|
||
i,
|
||
defaults = {
|
||
grid: this,
|
||
title: '[untitled]',
|
||
type: 'string',
|
||
sortable: false,
|
||
searchable: true,
|
||
onSort: function (order) {
|
||
var criteria = this.columnData;
|
||
that.sort(criteria, order);
|
||
}
|
||
};
|
||
|
||
if (column instanceof PMUI.grid.GridPanelColumn) {
|
||
columnToAdd = column;
|
||
columnToAdd.clearCells();
|
||
columnToAdd.setGrid(this);
|
||
} else if (typeof column === 'object') {
|
||
jQuery.extend(true, defaults, column);
|
||
columnToAdd = new PMUI.grid.GridPanelColumn(defaults);
|
||
} else {
|
||
throw new Error('addColumn(): The method only accepts an object or an instace of PMUI.grid.GridPanelColumn'
|
||
+ ' as parameter.');
|
||
}
|
||
|
||
//TODO control align and width
|
||
//console.log("\tCOLUMN insert " + columnToAdd.title/*isd*/);
|
||
this.columns.insert(columnToAdd);
|
||
this.paintColumn(columnToAdd);
|
||
rows = this.items.asArray();
|
||
for (i = 0; i < rows.length; i += 1) {
|
||
rows[i].addCell(columnToAdd);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Clears all the columns for the grid.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.clearColumns = function () {
|
||
while (this.columns.getSize()) {
|
||
this.removeColumn(0);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes a column and all its cells from the grid.
|
||
* @param {Number|String|PMUI.grid.GridPanelColumn} column This value is used to determine the row to remove:
|
||
*
|
||
* - String, in this case the string must be the id of a column in the grid.
|
||
* - Number, in this case the number is the index of the column to remove.
|
||
* - a {@link PMUI.grid.GridPanelColumn GridPanelColumn object}, if it's a column that belongs to the grid then
|
||
* this column will be the one to remove.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.removeColumn = function (column) {
|
||
var columnToRemove,
|
||
i,
|
||
row,
|
||
size,
|
||
index;
|
||
|
||
if (column instanceof PMUI.grid.GridPanelColumn) {
|
||
columnToRemove = column;
|
||
} else if (typeof column === 'number') {
|
||
columnToRemove = this.columns.get(column);
|
||
} else if (typeof column === 'string') {
|
||
columnToRemove = this.columns.find('id', column);
|
||
}
|
||
|
||
if (columnToRemove) {
|
||
index = this.columns.indexOf(columnToRemove);
|
||
size = this.items.getSize();
|
||
for (i = 0; i < size; i += 1) {
|
||
row = this.items.get(i);
|
||
row.removeCell(index);
|
||
}
|
||
columnToRemove.grid = null;
|
||
columnToRemove.clearCells();
|
||
this.columns.remove(columnToRemove);
|
||
jQuery(columnToRemove.getHTML()).remove();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a new Item
|
||
* @param {Object|PMUI.grid.GridPanelRow} item An instance of {@link PMUi.grid.GridPanelRow GridPanelRow} or an
|
||
* object with the properties to be used to create a new one.
|
||
* @param {Number} [index] The insertion index position.
|
||
*/
|
||
GridPanel.prototype.addItem = function (item, index) {
|
||
var itemToBeAdded;
|
||
|
||
if (typeof item !== 'object') {
|
||
throw new Error('addItem(): The first parameter must be an object or an instance of PMUI.grid.GridPanel.');
|
||
}
|
||
item.onSelect = this.onRowSelectHandler();
|
||
if (this.factory) {
|
||
itemToBeAdded = this.factory.make(item);
|
||
}
|
||
if (itemToBeAdded && !this.isDirectParentOf(itemToBeAdded)) {
|
||
itemToBeAdded.parent = this;
|
||
itemToBeAdded.style.addClasses(['pmui-' + (this.items.getSize() % 2 ? 'odd' : 'even')]);
|
||
if (itemToBeAdded.html || this.columns.asArray()) {
|
||
itemToBeAdded.setCells();
|
||
}
|
||
|
||
if (typeof index === 'number') {
|
||
this.items.insertAt(itemToBeAdded, index);
|
||
if (this.usableItemsList) {
|
||
this.usableItemsList.insertAt(itemToBeAdded, index);
|
||
}
|
||
if (this.filterCriteria) {
|
||
this.filter(this.filterCriteria);
|
||
} else {
|
||
this.goToPage(this.currentPage);
|
||
}
|
||
} else {
|
||
this.items.insert(itemToBeAdded);
|
||
this.usableItemsList.insert(itemToBeAdded);
|
||
if (this.dom.tbody && !this.massiveAction) {
|
||
this.goToPage(this.currentPage);
|
||
|
||
}
|
||
}
|
||
if (this.eventsDefined) {
|
||
itemToBeAdded.defineEvents();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* [onRowSelectHandler description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
GridPanel.prototype.onRowSelectHandler = function () {
|
||
var that = this;
|
||
return function () {
|
||
if (that.selectedRow) {
|
||
that.selectedRow.deselectRow();
|
||
}
|
||
that.selectedRow = this;
|
||
};
|
||
};
|
||
/**
|
||
* Sets the callback function to be executed everytime the {@link #event-onRowClick onRowClick} event is fired.
|
||
* Read about this event to know about the parameters received by the callback function.
|
||
* @param {Function|null} handler
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setOnRowClick = function (handler) {
|
||
if (typeof handler !== 'function' && handler !== null) {
|
||
throw new Error("sdfsdfgsd");
|
||
}
|
||
this.onRowClick = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows an empty row in grid.
|
||
* @param sizeItems
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
GridPanel.prototype.showEmptyCell = function (sizeItems) {
|
||
var tr,
|
||
td,
|
||
message;
|
||
|
||
if (this.dom.tbody) {
|
||
tr = PMUI.createHTMLElement('tr');
|
||
td = PMUI.createHTMLElement('td');
|
||
tr.className = 'pmui-gridpanel-emptyrow pmui-nodrag';
|
||
td.colSpan = this.columns.getSize();
|
||
tr.appendChild(td);
|
||
$(this.dom.tbody).find('.pmui-gridpanel-emptyrow').remove();
|
||
if (!sizeItems) {
|
||
// the empty row will be added only if there is not items in the container
|
||
$(this.dom.tbody).append(tr);
|
||
if (typeof this.emptyMessage === 'function') {
|
||
message = this.emptyMessage(this, !!this.filterCriteria);
|
||
} else if (typeof this.emptyMessage === 'string') {
|
||
message = this.emptyMessage;
|
||
} else {
|
||
if (this.filterCriteria) {
|
||
message = 'No matches found for \"' + this.filterCriteria + '\"';
|
||
} else {
|
||
message = 'No records found.';
|
||
}
|
||
}
|
||
if (typeof message === 'string') {
|
||
td.appendChild(document.createTextNode(message));
|
||
} else if (PMUI.isHTMLElement(message)) {
|
||
td.appendChild(message);
|
||
}
|
||
if (this.items.getSize() === 0 && typeof this.onEmpty === 'function') {
|
||
this.onEmpty(this);
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes a row from the object.
|
||
* @param {PMUI.core.Element|String|Number} item It can be a string (id of the child to remove),
|
||
a number (index of the child to remove) or a {Element} object
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.removeItem = function (item) {
|
||
var currentPage = this.currentPage;
|
||
if (item.selected) {
|
||
item.deselectRow();
|
||
}
|
||
|
||
GridPanel.superclass.prototype.removeItem.call(this, item);
|
||
|
||
if (!this.massiveAction) {
|
||
this.updateUsableItemsList();
|
||
this.filteredItems.remove(item);
|
||
this.showEmptyCell(this.items.getSize());
|
||
if (currentPage >= this.getTotalPages()) {
|
||
currentPage -= 1;
|
||
this.currentPage = currentPage < 0 ? 0 : currentPage;
|
||
}
|
||
if (this.dom.tbody) {
|
||
this.goToPage(this.currentPage, true);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
GridPanel.prototype.clearItems = function () {
|
||
var currentPage = this.currentPage;
|
||
GridPanel.superclass.prototype.clearItems.call(this);
|
||
this.updateUsableItemsList();
|
||
this.showEmptyCell(this.items.getSize());
|
||
if (currentPage >= this.getTotalPages()) {
|
||
currentPage -= 1;
|
||
this.currentPage = currentPage < 0 ? 0 : currentPage;
|
||
}
|
||
if (this.dom.tbody) {
|
||
this.goToPage(this.currentPage);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Remove all columns´s cells
|
||
* @returns {PMUI.grid.GridPanel}
|
||
*/
|
||
GridPanel.prototype.clearItemsColumns = function () {
|
||
var i,
|
||
max = this.getColumns().length;
|
||
for (i = 0; i < max; i += 1) {
|
||
this.getColumns()[i].clearCells();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Moves a row from its current position to another.
|
||
* @param {PMUI.grid.GridPanelRow|Number|String} item It can be:
|
||
|
||
*
|
||
* - An instance of PMUI.grid.GridPanelRow, in this case this object must be a item of the object.
|
||
* - A Number, in this case the number is interpereted as the index of the item to move.
|
||
* - A String, in this case the string is interpreted as the id of the item to move.
|
||
* @param {Number} index The index in which the item will be moved to.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.moveItem = function (item, index) {
|
||
var items = this.items,
|
||
currentIndex,
|
||
referenceObject;
|
||
|
||
item = this.getItem(item);
|
||
|
||
if (item instanceof PMUI.core.Element && this.isDirectParentOf(item)) {
|
||
currentIndex = items.indexOf(item);
|
||
items = items.asArray();
|
||
referenceObject = this.items.get(index + (currentIndex < index ? 1 : 0));
|
||
item = items.splice(currentIndex, 1)[0];
|
||
if (this.items.indexOf(item) > -1) {
|
||
this.items.remove(item);
|
||
}
|
||
this.items.insertAt(item, index);
|
||
this.updateUsableItemsList();
|
||
if (this.html) {
|
||
if (!referenceObject) {
|
||
this.goToPage(this.currentPage);
|
||
} else if (index === (this.currentPage * this.pageSize + this.pageSize - 1)
|
||
|| (this.getTotalPages() === (this.currentPage + 1)
|
||
&& index === (this.items.getSize() % this.pageSize) - 1)) {
|
||
this.containmentArea.appendChild(item.getHTML());
|
||
} else {
|
||
this.containmentArea.insertBefore(item.getHTML(), referenceObject.getHTML());
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the data for every rowe in the grid.
|
||
* @return {Array}
|
||
*/
|
||
GridPanel.prototype.getData = function () {
|
||
var i,
|
||
items = this.items.asArray(),
|
||
data = [];
|
||
|
||
for (i = 0; i < items.length; i += 1) {
|
||
data.push(items[i].getData());
|
||
}
|
||
|
||
return data;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
GridPanel.prototype.paintItem = function (item, index) {
|
||
var intitalItem = this.currentPage * this.pageSize,
|
||
finalIndex = this.pageSize ? this.currentPage + this.pageSize - 1 : null;
|
||
|
||
if (index === undefined) {
|
||
index = this.items.getSize();
|
||
}
|
||
if (index >= initialIndex || (index <= finalIndex || finalIndex === null)) {
|
||
this.goToPage(this.currentPage);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
GridPanel.prototype.paintItems = function () {
|
||
return this.filterCriteria ? this.filter(this.filterCriteria) : this.goToPage(this.currentPage);
|
||
};
|
||
/**
|
||
* Creates the HTML for the Grid.
|
||
* @return {HTMLElement}
|
||
*/
|
||
GridPanel.prototype.createHTML = function () {
|
||
var table,
|
||
thead,
|
||
tbody,
|
||
toolbarDiv,
|
||
footer,
|
||
pager,
|
||
statusBar,
|
||
tableContainer,
|
||
pager2;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
GridPanel.superclass.superclass.prototype.createHTML.call(this);
|
||
table = PMUI.createHTMLElement("table");
|
||
table.className = 'pmui-gridpanel-table';
|
||
table.cellSpacing = 0;
|
||
table.cellPadding = 0;
|
||
thead = PMUI.createHTMLElement("thead");
|
||
tbody = PMUI.createHTMLElement("tbody");
|
||
tableContainer = PMUI.createHTMLElement("div");
|
||
tableContainer.className = "pmui-gridpanel-tableContainer";
|
||
tbody.className = 'pmui-gridpanel-tbody';
|
||
this.containmentArea = tbody;
|
||
tableContainer.style.overflow = 'auto';
|
||
toolbarDiv = PMUI.createHTMLElement("div");
|
||
toolbarDiv.className = 'pmui-gridpanel-toolbar';
|
||
toolbarDiv.appendChild(this.filterControl.getHTML());
|
||
if (this._dynamicLoad) {
|
||
var searchLoad = PMUI.createHTMLElement("span");
|
||
searchLoad.className = "pmui-gridpanel-searchload";
|
||
toolbarDiv.appendChild(searchLoad);
|
||
}
|
||
this.html.appendChild(toolbarDiv);
|
||
|
||
this.dom.tableContainer = tableContainer;
|
||
this.dom.thead = thead;
|
||
this.dom.tbody = tbody;
|
||
this.dom.table = table;
|
||
this.dom.toolbar = toolbarDiv;
|
||
|
||
|
||
table.appendChild(thead);
|
||
table.appendChild(tbody);
|
||
tableContainer.appendChild(table);
|
||
this.html.appendChild(tableContainer);
|
||
pager = PMUI.createHTMLElement('ul');
|
||
pager.className = 'pmui-gridpanel-pager';
|
||
|
||
statusBar = PMUI.createHTMLElement('div');
|
||
statusBar.className = 'pmui-gridpanel-statusbar';
|
||
|
||
footer = PMUI.createHTMLElement("div");
|
||
footer.className = 'pmui-gridpanel-footer';
|
||
pager2 = PMUI.createHTMLElement("ul");
|
||
pager2.className = 'pmui-gridpanel-pager';
|
||
if (this._dynamicLoad) {
|
||
footer.appendChild(pager);
|
||
} else {
|
||
footer.appendChild(pager2);
|
||
}
|
||
|
||
this.html.appendChild(footer);
|
||
|
||
this.dom.pager2 = pager2;
|
||
|
||
this.dom.pager = pager;
|
||
this.dom.statusBar = statusBar;
|
||
this.dom.footer = footer;
|
||
|
||
this.setVisibleFooter(this.visibleFooter);
|
||
this.paintColumns()
|
||
.setHeight(this.height);
|
||
|
||
tableContainer.style.height = this.tableContainerHeight;
|
||
|
||
this.style.applyStyle();
|
||
|
||
if (this.filterable) {
|
||
this.enableFiltering();
|
||
} else {
|
||
this.disableFiltering();
|
||
}
|
||
if (this.visibleHeaders) {
|
||
this.showHeaders();
|
||
} else {
|
||
this.hideHeaders();
|
||
}
|
||
this.showEmptyCell(this.items.getSize());
|
||
if (this.eventsDefined) {
|
||
this.defineEvents();
|
||
}
|
||
if (this.sortingData.sortingCriteria) {
|
||
this.sort(this.sortingData.criteria, this.sortingData.type);
|
||
}
|
||
|
||
return this.html;
|
||
};
|
||
/**
|
||
* [updateStatusBar description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
GridPanel.prototype.updateStatusBar = function () {
|
||
var itemsLength,
|
||
filterCriteria,
|
||
b,
|
||
currentPage,
|
||
filtered,
|
||
totalPages;
|
||
|
||
filterCriteria = this.filterCriteria;
|
||
currentPage = this.currentPage;
|
||
filtered = !!(filterCriteria && this.filterable);
|
||
itemsLength = filtered ? this.filteredItems.getSize() : this.items.getSize();
|
||
jQuery(this.dom.statusBar).empty();
|
||
totalPages = this.getTotalPages(filtered);
|
||
if (typeof this.customStatusBar === 'function') {
|
||
this.dom.statusBar.textContent =
|
||
this.customStatusBar(currentPage, this.pageSize, itemsLength, filtered, filterCriteria || "");
|
||
} else if (totalPages === 0) {
|
||
b = PMUI.createHTMLElement('b');
|
||
b.appendChild(document.createTextNode(""));
|
||
this.dom.statusBar.appendChild(b);
|
||
} else {
|
||
b = PMUI.createHTMLElement('b');
|
||
b.appendChild(document.createTextNode("PAGE " + (currentPage + 1)));
|
||
this.dom.statusBar.appendChild(b);
|
||
this.dom.statusBar.appendChild(document.createTextNode(" of " + totalPages
|
||
+ (filtered ? " filtered pages" : "")));
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* [param] this-GridPanel
|
||
* @return Object
|
||
*/
|
||
GridPanel.prototype._getInterval = function (that) {
|
||
return {
|
||
start: Math.ceil(that.currentPage > that.halfDisplayed ? Math.max(Math.min(that.currentPage - that.halfDisplayed, (that.pages - that.displayedPages)), 0) : 0),
|
||
end: Math.ceil(that.currentPage > that.halfDisplayed ? Math.min(that.currentPage + that.halfDisplayed, that.pages) : Math.min(that.displayedPages, that.pages))
|
||
};
|
||
};
|
||
|
||
/**
|
||
* [number] pageIndex
|
||
* [object] opts
|
||
*/
|
||
GridPanel.prototype._appendItem = function (pageIndex, opts) {
|
||
var self = this.dom.footer,
|
||
options,
|
||
$link,
|
||
$linkWrapper = $('<li></li>'),
|
||
$ul = $(this.dom.footer).find('ul');
|
||
|
||
pageIndex = pageIndex < 0 ? 0 : (pageIndex < this.pages ? pageIndex : this.pages - 1);
|
||
|
||
options = {
|
||
text: pageIndex + 1,
|
||
classes: ''
|
||
};
|
||
|
||
if (this.labelMap.length && this.labelMap[pageIndex]) {
|
||
options.text = this.labelMap[pageIndex];
|
||
}
|
||
|
||
options = $.extend(options, opts || {});
|
||
|
||
if (pageIndex == this.currentPage || this.disabled) {
|
||
if (this.disabled) {
|
||
$linkWrapper.addClass('disabled');
|
||
} else {
|
||
$linkWrapper.addClass('active');
|
||
}
|
||
$link = (options.text == 'Prev') ? $('<span class="pmui-gridpanel-pager-current"><span style="font-size: 18px; line-height: normal;"> ‹ </span>' + (options.text) + '</span>') : (options.text == 'Next') ? $('<span class="pmui-gridpanel-pager-current">' + (options.text) + '<span style="font-size: 18px; line-height: normal;"> › </span></span>') : $('<span class="pmui-gridpanel-pager-current">' + (options.text) + '</span>');
|
||
|
||
} else {
|
||
$link = (options.text == 'Prev') ? $('<a href="' + this.hrefTextPrefix + (pageIndex + 1) + this.hrefTextSuffix + '" class="page-link"><span style="font-size: 18px; line-height: normal;"> ‹ </span>' + (options.text) + '</a>') : (options.text == 'Next') ? $('<a href="' + this.hrefTextPrefix + (pageIndex + 1) + this.hrefTextSuffix + '" class="page-link">' + (options.text) + '<span style="font-size: 18px; line-height: normal;"> › </span></a>') : $('<a href="' + this.hrefTextPrefix + (pageIndex + 1) + this.hrefTextSuffix + '" class="page-link">' + (options.text) + '</a>');
|
||
var that = this;
|
||
$link.click(function (event) {
|
||
return that._selectPage.call(that, pageIndex, event);
|
||
});
|
||
}
|
||
|
||
if (options.classes) {
|
||
$link.addClass(options.classes);
|
||
}
|
||
|
||
$linkWrapper.append($link);
|
||
|
||
if ($ul.length) {
|
||
$(this.dom.pager2).append($linkWrapper);
|
||
} else {
|
||
$(this.dom.pager2).append($linkWrapper); //... review
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Select number in a page.
|
||
* @param {Number} pageIndex The index of the page to go.
|
||
* @param {event} click event.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype._selectPage = function (pageIndex, event) {
|
||
this.currentPage = pageIndex;
|
||
if (this.selectOnClick) {
|
||
this.goToPage(pageIndex, true);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Change the grid page.
|
||
* @param {Number} index The index of the page to go.
|
||
* @param {Boolean} [force] If its true you go to the specified page even if there's no data in it.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.goToPage = function (index, force) {
|
||
var modal;
|
||
|
||
if (this._dynamicLoad) {
|
||
var i, numDisplayedItems = 0, that = this;
|
||
|
||
if (!((index < 0) && !force)) {
|
||
this.currentPage = index;
|
||
|
||
if (!this.html) {
|
||
return this;
|
||
}
|
||
}
|
||
if (!this.html) {
|
||
return this;
|
||
}
|
||
|
||
this.showEmptyCell(numDisplayedItems);
|
||
if (this.html) {
|
||
$(this.dom.toolbar).find(".pmui-gridpanel-searchload").addClass("load");
|
||
modal = document.createElement("div");
|
||
modal.id = "dynamic-modal-load";
|
||
$(modal).css({
|
||
height: $(this.dom.tableContainer).outerHeight(),
|
||
width: $(this.dom.tableContainer).outerWidth(),
|
||
background: "rgba(204, 197, 197, 0.4)",
|
||
position: "absolute",
|
||
zIndex: "200"
|
||
});
|
||
$(this.dom.tableContainer).prepend(modal);
|
||
}
|
||
$.ajax({
|
||
url: this.url + "?filter=" + (this.filterCriteria ? this.filterCriteria : "") + "&start=" + (this.pageSize * index) + "&limit=" + this.pageSize + "&type=" + (this.typeList ? this.typeList : ""),
|
||
type: "GET",
|
||
async: true,
|
||
contentType: "application/json",
|
||
beforeSend: function (xhr) {
|
||
xhr.setRequestHeader("Authorization", "Bearer " + that.keys.accessToken);
|
||
},
|
||
success: function (data) {
|
||
var i,
|
||
newItem,
|
||
numDisplayedItems = 0,
|
||
dataReceived;
|
||
if (typeof that.customDataRest === "function") {
|
||
dataReceived = that.customDataRest(data["data"]);
|
||
} else {
|
||
dataReceived = data["data"];
|
||
}
|
||
that._dynamicLoad.totalPages = Math.ceil(data["total"] / that.pageSize);
|
||
$(that.dom.tbody).empty();
|
||
if (dataReceived.length) {
|
||
for (i = 0; i < dataReceived.length; i += 1) {
|
||
newItem = that.factory.make({
|
||
data: dataReceived[i]
|
||
});
|
||
newItem.parent = that;
|
||
newItem.style.addClasses(['pmui-' + (i % 2 ? 'odd' : 'even')]);
|
||
if (newItem.html || that.columns.asArray()) {
|
||
newItem.setCells();
|
||
}
|
||
that.dom.tbody.appendChild(newItem.updateCellsWidth().getHTML());
|
||
$(newItem.html).find(".pmui-gridpanelcell-content").each(function () {
|
||
if (this.children.length === 0 && this.textContent.length != 0) {
|
||
this.title = this.textContent;
|
||
}
|
||
});
|
||
numDisplayedItems += 1;
|
||
}
|
||
}
|
||
that.showEmptyCell(numDisplayedItems);
|
||
that.setBehavior(that.behavior);
|
||
if (that.html) {
|
||
$(that.dom.toolbar).find(".pmui-gridpanel-searchload").removeClass("load");
|
||
$(that.dom.tableContainer).find("#dynamic-modal-load").remove();
|
||
}
|
||
return that.updatePager().updateStatusBar();
|
||
that.dom.footer.appendChild(this.dom.pager);
|
||
},
|
||
error: function (xhr, textStatus, errorThrown) {
|
||
|
||
}
|
||
});
|
||
this.setBehavior(this.behavior);
|
||
} else {
|
||
this.halfDisplayed = this.displayedPages / 2;
|
||
this.currentPage = index;
|
||
if (force && this.filterCriteria && this.filterable) {
|
||
this.pages = Math.ceil(this.filteredItems.getSize() / this.pageSize) ? Math.ceil(this.filteredItems.getSize() / this.pageSize) : 1;
|
||
} else {
|
||
this.pages = Math.ceil(this.getItems().length / this.pageSize) ? Math.ceil(this.getItems().length / this.pageSize) : 1;
|
||
}
|
||
var interval = this._getInterval(this);
|
||
//Updates the pager
|
||
if (this.dom.pager2 && this.getItems().length != 0) {
|
||
jQuery(this.dom.pager2).empty();
|
||
|
||
//Generate Prev link
|
||
if (this.prevText) {
|
||
this._appendItem.call(this, !this.invertPageOrder ? this.currentPage - 1 : this.currentPage + 1, {
|
||
text: this.prevText,
|
||
classes: 'prev'
|
||
});
|
||
}
|
||
|
||
|
||
//Generate Next link
|
||
if (this.nextText && this.nextAtFront) {
|
||
this._appendItem.call(this, !this.invertPageOrder ? this.currentPage + 1 : this.currentPage - 1, {
|
||
text: this.nextText,
|
||
classes: 'next'
|
||
});
|
||
}
|
||
|
||
|
||
//Generate start edges
|
||
if (!this.invertPageOrder) {
|
||
if (interval.start > 0 && this.edges > 0) {
|
||
if (this.useStartEdge) {
|
||
var end = Math.min(this.edges, interval.start);
|
||
for (i = 0; i < end; i += 1) {
|
||
this._appendItem.call(this, i);
|
||
}
|
||
}
|
||
if (this.edges < interval.start && (interval.start - this.edges != 1)) {
|
||
$(this.dom.pager2).append('<li class="disabled"><span class="pmui-gridpanel-pager-ellipse">' + this.ellipseText + '</span></li>');
|
||
} else if (interval.start - this.edges == 1) {
|
||
this._appendItem.call(this, this.edges);
|
||
}
|
||
}
|
||
} else {
|
||
if (interval.end < this.pages && this.edges > 0) {
|
||
if (this.useStartEdge) {
|
||
var begin = Math.max(this.pages - this.edges, interval.end);
|
||
for (i = this.pages - 1; i >= begin; i -= 1) {
|
||
this._appendItem.call(this, i);
|
||
}
|
||
}
|
||
if (this.pages - this.edges > interval.end && (this.pages - this.edges - interval.end != 1)) {
|
||
$(this.dom.pager2).append('<li class="disabled"><span class="pmui-gridpanel-pager-ellipse">' + this.ellipseText + '</span></li>');
|
||
} else if (this.pages - this.edges - interval.end == 1) {
|
||
this._appendItem.call(this, interval.end);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//Generate interval links
|
||
if (!this.invertPageOrder) {
|
||
for (i = interval.start; i < interval.end; i += 1) {
|
||
this._appendItem.call(this, i);
|
||
}
|
||
} else {
|
||
for (i = interval.end - 1; i >= interval.start; i -= 1) {
|
||
this._appendItem.call(this, i);
|
||
}
|
||
}
|
||
|
||
//Generate end edges
|
||
if (!this.invertPageOrder) {
|
||
if (interval.end < this.pages && this.edges > 0) {
|
||
if (this.pages - this.edges > interval.end && (this.pages - this.edges - interval.end != 1)) {
|
||
$(this.dom.pager2).append('<li class="disabled"><span class="pmui-gridpanel-pager-ellipse">' + this.ellipseText + '</span></li>');
|
||
} else if (this.pages - this.edges - interval.end == 1) {
|
||
this._appendItem.call(this, interval.end);
|
||
}
|
||
if (this.useEndEdge) {
|
||
var begin = Math.max(this.pages - this.edges, interval.end);
|
||
for (i = begin; i < this.pages; i += 1) {
|
||
this._appendItem.call(this, i);
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
if (interval.start > 0 && this.edges > 0) {
|
||
if (this.edges < interval.start && (interval.start - this.edges != 1)) {
|
||
$(this.dom.pager2).append('<li class="disabled"><span class="pmui-gridpanel-pager-ellipse">' + this.ellipseText + '</span></li>');
|
||
} else if (interval.start - this.edges == 1) {
|
||
this._appendItem.call(this, this.edges);
|
||
}
|
||
|
||
if (this.useEndEdge) {
|
||
var end = Math.min(this.edges, interval.start);
|
||
for (i = end - 1; i >= 0; i -= 1) {
|
||
this._appendItem.call(this, i);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//Generate Next link
|
||
if (this.nextText && !this.nextAtFront) {
|
||
this._appendItem.call(this, !this.invertPageOrder ? this.currentPage + 1 : this.currentPage - 1, {
|
||
text: this.nextText,
|
||
classes: 'next'
|
||
});
|
||
}
|
||
} else {
|
||
if (this.getItems().length == 0) {
|
||
jQuery(this.dom.pager2).empty();
|
||
}
|
||
}
|
||
//Show rows in gridPanel
|
||
var i, initRow, lastRow, listTarget, size, numDisplayedItems = 0, totalPages;
|
||
if (!((index < 0 || index >= this.getTotalPages(this.filterCriteria)) && !force)) {
|
||
if (!this.html) {
|
||
return this;
|
||
}
|
||
if (this.filterCriteria && this.filterable) {
|
||
listTarget = this.filteredItems.asArray();
|
||
} else {
|
||
listTarget = this.usableItemsList.asArray();
|
||
}
|
||
size = listTarget.length;
|
||
|
||
totalPages = this.getTotalPages(!!this.filterCriteria);
|
||
jQuery(this.dom.tbody).find('>tr').detach();
|
||
if (force) {
|
||
initRow = this.currentPage * this.pageSize;
|
||
lastRow = this.pageSize !== 0 ? (initRow + this.pageSize) : size;
|
||
} else {
|
||
initRow = (this.filterCriteria && this.filterable) ? 0 : this.pageSize !== 0 ? ((this.currentPage + 1) * this.pageSize) - this.pageSize : 0;
|
||
lastRow = this.pageSize !== 0 ? (initRow + this.pageSize) : size;
|
||
}
|
||
for (i = initRow; i < lastRow && i < size; i += 1) {
|
||
this.dom.tbody.appendChild(listTarget[i].updateCellsWidth().getHTML());
|
||
numDisplayedItems += 1;
|
||
}
|
||
}
|
||
|
||
if (!this.html) {
|
||
return this;
|
||
}
|
||
|
||
this.showEmptyCell(numDisplayedItems);
|
||
this.setBehavior(this.behavior);
|
||
return this;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Deprecated...
|
||
* Updates the pager.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
GridPanel.prototype.updatePager = function () {
|
||
var totalPages,
|
||
page,
|
||
i,
|
||
inputPage,
|
||
link,
|
||
textContent,
|
||
additionalClass,
|
||
currentPage = this.currentPage,
|
||
dataIndex,
|
||
infoLink;
|
||
|
||
if (this.dom.pager) {
|
||
jQuery(this.dom.pager).empty();
|
||
if (this._dynamicLoad) {
|
||
|
||
totalPages = this._dynamicLoad.totalPages;
|
||
var first, next, first, last, total;
|
||
first = PMUI.createHTMLElement('li');
|
||
first.className = "list-item-ajax";
|
||
link = PMUI.createHTMLElement('a');
|
||
link.className = 'pmui-gridpanel-pagelink pmui-gridpanel-previousbutton';
|
||
textContent = "«";
|
||
link.textContent = textContent;
|
||
link.href = '#';
|
||
first.appendChild(link);
|
||
jQuery(link).css({
|
||
height: "auto"
|
||
}).data({"index": 0});
|
||
this.dom.pager.appendChild(first);
|
||
if (this.currentPage !== 0) {
|
||
jQuery(link).removeClass("disable");
|
||
} else {
|
||
jQuery(link).addClass("disable");
|
||
}
|
||
prev = PMUI.createHTMLElement('li');
|
||
prev.className = "list-item-ajax";
|
||
link = PMUI.createHTMLElement('a');
|
||
link.className = 'pmui-gridpanel-pagelink';
|
||
link.innerHTML = "<";
|
||
jQuery(link).addClass("pmui-gridpanel-previousbutton");
|
||
link.href = '#';
|
||
prev.appendChild(link);
|
||
jQuery(link).css({
|
||
height: "auto"
|
||
}).data({"index": this.currentPage - 1});
|
||
this.dom.pager.appendChild(prev);
|
||
if (this.currentPage !== 0) {
|
||
jQuery(link).removeClass("disable");
|
||
} else {
|
||
jQuery(link).addClass("disable");
|
||
}
|
||
infoLink = PMUI.createHTMLElement('li');
|
||
infoLink.className = "list-item-ajax";
|
||
total = PMUI.createHTMLElement("a");
|
||
total.className = "pmui-gridpanel-total";
|
||
total.textContent = " Page ";
|
||
infoLink.appendChild(total);
|
||
this.dom.pager.appendChild(infoLink);
|
||
|
||
infoLink = PMUI.createHTMLElement('li');
|
||
infoLink.className = "list-item-ajax";
|
||
inputPage = PMUI.createHTMLElement("input");
|
||
jQuery(inputPage).addClass("pmui-gridpanel-gotoPage");
|
||
infoLink.appendChild(inputPage);
|
||
this.dom.pager.appendChild(infoLink);
|
||
jQuery(inputPage).val(this.currentPage + 1);
|
||
jQuery(infoLink).css({
|
||
"vertical-align": "top"
|
||
});
|
||
infoLink = PMUI.createHTMLElement('li');
|
||
infoLink.className = "list-item-ajax";
|
||
total = PMUI.createHTMLElement("a");
|
||
total.className = "pmui-gridpanel-total";
|
||
total.textContent = " of " + (totalPages ? totalPages : 1);
|
||
infoLink.appendChild(total);
|
||
this.dom.pager.appendChild(infoLink);
|
||
|
||
next = PMUI.createHTMLElement('li');
|
||
next.className = "list-item-ajax";
|
||
link = PMUI.createHTMLElement('a');
|
||
link.className = 'pmui-gridpanel-pagelink';
|
||
link.innerHTML = ">";
|
||
jQuery(link).addClass("pmui-gridpanel-nextbutton");
|
||
link.href = '#';
|
||
next.appendChild(link);
|
||
jQuery(link).css({
|
||
height: "auto"
|
||
}).data({"index": this.currentPage + 1});
|
||
this.dom.pager.appendChild(next);
|
||
if (currentPage + 1 < totalPages) {
|
||
jQuery(link).removeClass("disable");
|
||
} else {
|
||
jQuery(link).addClass("disable");
|
||
}
|
||
last = PMUI.createHTMLElement('li');
|
||
last.className = "list-item-ajax";
|
||
link = PMUI.createHTMLElement('a');
|
||
link.className = 'pmui-gridpanel-pagelink pmui-gridpanel-nextbutton';
|
||
textContent = "»";
|
||
link.textContent = textContent;
|
||
link.href = '#';
|
||
last.appendChild(link);
|
||
jQuery(link).css({
|
||
height: "auto"
|
||
}).data({"index": this._dynamicLoad.totalPages - 1});
|
||
this.dom.pager.appendChild(last);
|
||
if (currentPage + 1 < totalPages) {
|
||
jQuery(link).removeClass("disable");
|
||
} else {
|
||
jQuery(link).addClass("disable");
|
||
}
|
||
} else {
|
||
totalPages = this.getTotalPages(!!this.filterCriteria);
|
||
if (!totalPages) {
|
||
return this;
|
||
}
|
||
for (i = -1; i <= totalPages; i += 1) {
|
||
additionalClass = textContent = dataIndex = "";
|
||
if (i < 0) {
|
||
if (currentPage > 0) {
|
||
dataIndex = 'p';
|
||
additionalClass = 'pmui-gridpanel-previousbutton';
|
||
}
|
||
} else if (i === totalPages) {
|
||
if (currentPage < totalPages - 1) {
|
||
additionalClass = 'pmui-gridpanel-nextbutton';
|
||
dataIndex = 'n';
|
||
}
|
||
} else {
|
||
textContent = i + 1;
|
||
if (currentPage === i) {
|
||
additionalClass = 'pmui-active';
|
||
}
|
||
dataIndex = i;
|
||
}
|
||
if (dataIndex !== "") {
|
||
page = PMUI.createHTMLElement('li');
|
||
link = PMUI.createHTMLElement('a');
|
||
if (this._dynamicLoad) {
|
||
$(link).css({
|
||
height: 21
|
||
});
|
||
}
|
||
link.className = 'pmui-gridpanel-pagelink';
|
||
link.setAttribute("data-index", dataIndex);
|
||
if (textContent) {
|
||
link.textContent = textContent;
|
||
} else {
|
||
textContent = PMUI.createHTMLElement('div');
|
||
textContent.className = 'pmui-icon';
|
||
link.appendChild(textContent);
|
||
}
|
||
jQuery(link).addClass(additionalClass);
|
||
link.href = '#';
|
||
page.appendChild(link);
|
||
this.dom.pager.appendChild(page);
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Sets the size for the grid's pages.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setPageSize = function (pageSize) {
|
||
var previousSize = this.pageSize;
|
||
if (typeof pageSize !== 'number') {
|
||
throw new Error("setPageSize(): The method only accepts a number as parameter.");
|
||
}
|
||
if (pageSize < 0) {
|
||
throw new Error("setPageSize(): The method only accepts a number major or equal to zero (0).");
|
||
}
|
||
this.pageSize = pageSize;
|
||
if (this.html && previousSize !== pageSize) {
|
||
if (pageSize === 0) {
|
||
jQuery(this.dom.pager).hide();
|
||
this.currentPage = 0;
|
||
} else {
|
||
jQuery(this.dom.pager).show();
|
||
}
|
||
this.goToPage(this.currentPage);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the size for the grid's displayedPages.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setDisplayedPages = function (displayedPages) {
|
||
this.displayedPages = displayedPages;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the size for the grid's pages.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setPages = function (pages) {
|
||
this.pages = pages;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets Prev text in paginator.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setPrevText = function (prevText) {
|
||
this.prevText = prevText;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets Next text in paginator.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setNextText = function (nextText) {
|
||
this.nextText = nextText
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the size for the grid's pages.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setInvertPageOrder = function (invertPageOrder) {
|
||
this.invertPageOrder = invertPageOrder
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets numbers in a paginator.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setLabelMap = function (labelMap) {
|
||
this.labelMap = labelMap
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the size for the grid's pages.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setHrefTextPrefix = function (hrefTextPrefix) {
|
||
this.hrefTextPrefix = hrefTextPrefix
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* Sets the size for the grid's pages.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setHrefTextSuffix = function (hrefTextSuffix) {
|
||
this.hrefTextSuffix = hrefTextSuffix
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* Sets the size for the grid's pages.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setNextAtFront = function (nextAtFront) {
|
||
this.nextAtFront = nextAtFront
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* Sets the size for the grid's pages.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setEdgesPagination = function (edges) {
|
||
this.edges = edges
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* Sets the size for the grid's pages.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setUseStartEdge = function (useStartEdge) {
|
||
this.useStartEdge = useStartEdge
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* Sets the size for the grid's pages.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setEllipseText = function (ellipseText) {
|
||
this.ellipseText = ellipseText
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* Sets the size for the grid's pages.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setSelectOnClick = function (selectOnClick) {
|
||
this.selectOnClick = selectOnClick
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the size for the grid's pages.
|
||
* @param {Number} pageSize
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setUseEndEdge = function (useEndEdge) {
|
||
this.useEndEdge = useEndEdge
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the total number of pages on the grid.
|
||
* @param {Boolean} [filter=false] If the calculation will be done taking only the filtered results.
|
||
* @return {Number}
|
||
*/
|
||
GridPanel.prototype.getTotalPages = function (filter) {
|
||
var targetListSize = filter ? this.filteredItems.getSize() : this.items.getSize();
|
||
|
||
return !this.items.getSize() ? 0 : (this.pageSize === 0 ? 1 : Math.ceil(targetListSize / this.pageSize));
|
||
};
|
||
|
||
/**
|
||
* It defines the events for the Grid.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.defineEvents = function () {
|
||
var that = this,
|
||
i,
|
||
columnsNum = this.columns.getSize();
|
||
|
||
this.removeEvents().eventsDefined = true;
|
||
if (this.dom.pager) {
|
||
this.filterControl.defineEvents();
|
||
|
||
for (i = 0; i < columnsNum; i += 1) {
|
||
this.columns.get(i).defineEvents();
|
||
}
|
||
|
||
/*for(i = 0; i < this.items.getSize(); i += 1) {
|
||
this.items.get(i).defineEvents();
|
||
}*/
|
||
this.addEvent('click').listenWithDelegation(this.dom.pager, 'a', function (e) {
|
||
var where;
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
where = jQuery(this).data("index");
|
||
if (that._dynamicLoad) {
|
||
if ((where > -1 && where < that._dynamicLoad.totalPages) && (that.currentPage !== where)) {
|
||
that.goToPage(where === 'n' ? that.currentPage + 1 : (where === 'p' ? that.currentPage - 1 : where));
|
||
}
|
||
} else {
|
||
that.goToPage(where === 'n' ? that.currentPage + 1 : (where === 'p' ? that.currentPage - 1 : where));
|
||
}
|
||
});
|
||
this.addEvent('keypress').listenWithDelegation(this.dom.pager, 'input', function (e) {
|
||
if (e.keyCode == 13 || e.keyCode == 32) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
if (/^\d*$/.test(this.value) && (this.value <= that._dynamicLoad.totalPages)) {
|
||
if (this.value > 0) {
|
||
that.goToPage(parseInt(this.value) - 1);
|
||
}
|
||
|
||
}
|
||
}
|
||
});
|
||
this.addEvent('change').listenWithDelegation(this.dom.pager, 'input', function (e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
if (this.value !== that.currentPage) {
|
||
this.value = that.currentPage + 1;
|
||
}
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the current page to be displayed in the grid.
|
||
* @param {Number} currentPage
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setCurrentPage = function (currentPage) {
|
||
this.currentPage = currentPage;
|
||
if (this.html) {
|
||
this.goToPage(this.currentPage);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Clears the filter.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.clearFilter = function () {
|
||
this.filterCriteria = null;
|
||
this.goToPage(this.currentPage);
|
||
return this;
|
||
};
|
||
/**
|
||
* Executes the sorting.
|
||
* @param {String} criteria The sorting criteria.
|
||
* @param {String} [sortType="asc"] The sorting order: "asc" or "desc".
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.sort = function (criteria, sortType) {
|
||
var items,
|
||
theColumn,
|
||
i,
|
||
columns,
|
||
evaluate;
|
||
|
||
this.sortingData.criteria = criteria;
|
||
this.sortingData.type = sortType;
|
||
evaluate = function (a, b) {
|
||
var dataA,
|
||
dataB,
|
||
res;
|
||
|
||
if (typeof criteria === 'function') {
|
||
dataA = criteria.call(a, a.getData()).toString();
|
||
dataB = criteria.call(b, b.getData()).toString();
|
||
} else {
|
||
dataA = a.getData();
|
||
dataB = b.getData();
|
||
dataA = (dataA[criteria] && dataA[criteria].toString()) || "";
|
||
dataB = (dataB[criteria] && dataB[criteria].toString()) || "";
|
||
}
|
||
if (dataA < dataB) {
|
||
res = 1;
|
||
} else if (dataA > dataB) {
|
||
res = -1;
|
||
} else {
|
||
res = 0;
|
||
}
|
||
if (sortType === 'asc') {
|
||
res *= -1;
|
||
}
|
||
return res;
|
||
};
|
||
if (!this.html) {
|
||
return this;
|
||
}
|
||
this.updateUsableItemsList();
|
||
items = this.usableItemsList.asArray();
|
||
items.sort(evaluate);
|
||
this.usableItemsList.set(items);
|
||
columns = this.getColumns();
|
||
for (i = 0; i < columns.length; i += 1) {
|
||
columns[i].style.removeClasses(['pmui-sort-asc', 'pmui-sort-desc']);
|
||
if (columns[i].columnData === criteria) {
|
||
theColumn = columns[i];
|
||
}
|
||
}
|
||
|
||
if (theColumn) {
|
||
theColumn.style.addClasses(['pmui-sort-' + sortType]);
|
||
}
|
||
|
||
if (this.filterCriteria) {
|
||
this.filter(this.filterCriteria);
|
||
} else {
|
||
this.goToPage(this.currentPage);
|
||
}
|
||
this.goToPage(this.currentPage);
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the function to be executed when an accepted draggedgable is dragged over the droppable area.
|
||
* @return {Function}
|
||
*/
|
||
GridPanel.prototype.onDragOver = function () {
|
||
return function () {
|
||
};
|
||
};
|
||
/**
|
||
* Filters the rows using a criteria. The filter will be applied only in the columns in which its property
|
||
* "searchable" is true.
|
||
* @param {String} criteria The criteria.
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.filter = function (criteria) {
|
||
var i,
|
||
columns,
|
||
j,
|
||
cell,
|
||
regExp,
|
||
rowsCopy,
|
||
visibleRows,
|
||
pmuiObject,
|
||
sortingCriteria = this.sortingData.criteria;
|
||
|
||
if (typeof criteria === 'string') {
|
||
if (criteria === "") {
|
||
this.clearFilter();
|
||
return this;
|
||
}
|
||
this.filterCriteria = criteria;
|
||
} else if (typeof criteria === 'number') {
|
||
this.filterCriteria = criteria.toString(10);
|
||
}
|
||
|
||
if (!this.dom.tbody) {
|
||
return this;
|
||
}
|
||
|
||
columns = this.columns.asArray();
|
||
regExp = new RegExp(this.filterCriteria.replace(/([\\\.\[\]\^\$\(\)\?\*\+\|\{\}])/g, "\\\$1"), "i");
|
||
rowsCopy = this.usableItemsList.asArray().slice(0);
|
||
|
||
visibleRows = jQuery(this.dom.tbody).find('tr');
|
||
for (i = 0; i < visibleRows.length; i += 1) {
|
||
pmuiObject = PMUI.getPMUIObject(visibleRows[i]);
|
||
if (pmuiObject) {
|
||
jQuery(pmuiObject.html).detach();
|
||
}
|
||
}
|
||
this.filteredItems.clear();
|
||
//if there is a sorting criteria set at the moment, first when use it to filter the rows
|
||
//this is necessary to keep the current sorting order.
|
||
if (sortingCriteria) {
|
||
for (j = 0; j < rowsCopy.length; j += 1) {
|
||
for (i = 0; i < columns.length; i += 1) {
|
||
if (columns[i].getDataType() !== 'button' && columns[i].isSearchable()) {
|
||
if (!rowsCopy[j].html) {
|
||
rowsCopy[j].getHTML();
|
||
rowsCopy[j].setCells();
|
||
}
|
||
cell = rowsCopy[j].getCells()[i];
|
||
if (regExp.test(cell.getContent()) && cell.visible) {
|
||
this.filteredItems.insert(rowsCopy.splice(j, 1)[0]);
|
||
j -= 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (rowsCopy.length) {
|
||
for (i = 0; i < columns.length; i += 1) {
|
||
if (columns[i].getDataType() !== 'button' && columns[i].isSearchable()) {
|
||
for (j = 0; j < rowsCopy.length; j += 1) {
|
||
if (!rowsCopy[j].html) {
|
||
rowsCopy[j].getHTML();
|
||
rowsCopy[j].setCells();
|
||
}
|
||
cell = rowsCopy[j].getCells()[i];
|
||
if (regExp.test(cell.getContent()) && cell.visible) {
|
||
this.filteredItems.insert(rowsCopy.splice(j, 1)[0]);
|
||
j -= 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
this.goToPage(0, true);
|
||
return this;
|
||
};
|
||
/**
|
||
* [setSelectable description]
|
||
* @param {[type]} value [description]
|
||
*/
|
||
GridPanel.prototype.setSelectable = function (value) {
|
||
if (typeof value !== 'boolean') {
|
||
throw new Error('setSelectable(): the property is not valid, should be a boolean');
|
||
}
|
||
this.selectable = value;
|
||
if (!value && this.selectedRow) {
|
||
this.selectedRow.deselectRow();
|
||
this.selectedRow = null;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* fixed the property visibleFooter, to hide or not the foot of GridPanel
|
||
* @param {Boolean} value the property should be type 'boolean'
|
||
*/
|
||
GridPanel.prototype.setVisibleFooter = function (value) {
|
||
if (typeof value !== 'boolean') {
|
||
throw new Error("setFooterHidden(): the value is no valid, should be a value type 'boolean'");
|
||
|
||
}
|
||
this.visibleFooter = value;
|
||
if (this.html) {
|
||
if (this.visibleFooter) {
|
||
this.showFooter();
|
||
} else {
|
||
this.hiddenFooter();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* hidden the footer of the GridPanel if is visible
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.hiddenFooter = function () {
|
||
this.dom.footer.style.display = 'none';
|
||
return this;
|
||
};
|
||
/**
|
||
* show the footer of the GridPanel if it has been hidden
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.showFooter = function () {
|
||
this.dom.footer.style.display = 'block';
|
||
return this;
|
||
};
|
||
/**
|
||
* Set the height for the HTML element
|
||
* @param {Number|String} height it can be a number or a string.
|
||
* In case of using a String you only can use 'auto' or 'inherit' or ##px or ##% or ##em when ## is a number.
|
||
* also sets the height of the table being rendered, according to the high set in order gridPanel
|
||
* @chainable
|
||
*/
|
||
GridPanel.prototype.setHeight = function (height) {
|
||
GridPanel.superclass.prototype.setHeight.call(this, height);
|
||
|
||
|
||
if (this.dom.tableContainer) {
|
||
if (typeof this.height !== "string") {
|
||
this.dom.tableContainer.style.height = this.height - 74 + 'px';
|
||
} else {
|
||
this.dom.tableContainer.style.height = 'auto';
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace("PMUI.grid.GridPanel", GridPanel);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports === GridPanel;
|
||
}
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.grid.GridPanelColumn
|
||
* Class that represents a column to be used in a {@link PMUI.grid.GridPanel GridPanel}.
|
||
* Usually you don't need to instantiate this class since the {@link PMUI.grid.GridPanel GridPanel} do it on its
|
||
* own, in fact, this class can't be instantiate if a grid parent
|
||
* ({@link PMUI.grid.GridPanel#cfg-grid grid config option}) is not specified.
|
||
* @extends {PMUI.core.Element}
|
||
*
|
||
* We don't include any example for this class 'cause we don't recommend you to do it, let the GridPanelColumn do
|
||
* it. Anyway, if you need add new columns to a GridPanel use its
|
||
* {@link PMUI.grid.GridPanel#method-addColumn addColumn() method}.
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the GridPanelColumn object.
|
||
* @param {Object} settings A JSON object with the config options.
|
||
*
|
||
* @cfg {String} [title='[untitled]'] The text to display in the column header.
|
||
* @cfg {String} [dataType='string'] The column data type. The accepted values are: "string", "number", "index" or
|
||
* "date".
|
||
* @cfg {Boolean} [sortable=false] If the column will have the sorting function enabled.
|
||
* @cfg {Boolean} [searchable=true] If the column must be filter when a filter criteria is set.
|
||
* @cfg {Function} [onButtonClick=null] A callback function to be called when a column's button is clicked. For
|
||
* info about the callback parameters please read the
|
||
* {@link PMUI.grid.GridPanelColumn#event-onButtonClick onButtonClick event doc}.
|
||
* @cfg {String} [buttonLabel='[button]'] The label for the button on a column for buttons.
|
||
* @cfg {Array} [cells=[]] The cells that belongs to the column.
|
||
* @cfg {PMUI.grid.GridPanel} grid The grid the column belongs to.
|
||
* @cfg {String|Function} [columnData=null]
|
||
* - In case of a String: The data key to be used for the cells in this column.
|
||
* - In case of a Function: A function that will return the content for the cells in column, the parameters
|
||
* received by the function are:
|
||
* - data {Object}: a JSON object with the data for the current row.
|
||
* The function will be called in the context of the current {@link PMUI.grid.GridPanelRow row object}.
|
||
* @cfg {Function} [onSort=null] A callback function to be called every time the sorting is executed.
|
||
* @cfg {String} [alignmentCell="center"] A string that specifies the alignmentCell for the content of cells that
|
||
* appertains to this column. The accepted values are: "center", "left", "right".
|
||
* @cfg {Object|PMUI.util.Style|null} [cellStyle=null] The style to be applied to the cells that belongs to the
|
||
* column, if it is set to null (the default value) no custom styles will be applied to the cells.
|
||
* @cfg {Object|PMUI.util.Style|Function|null} [buttonStyle=null] The style for the buttons in the column (only applicable
|
||
* if the column has its {@link #property-dataType dataType property} set to "button"). It can be:
|
||
*
|
||
* - null then the buttons won't apply any custom style.
|
||
* - An object literal in that case it can have the properties: cssClasses (an array in which each element is
|
||
* an string that is a class name) and cssProperties (another object literal that can contain css properties and
|
||
* its respective values).
|
||
* - An instance of {@link PMUI.util.Style}.
|
||
* - A function that must return any of the previous value types. The parameters received by the functions are:
|
||
* - the {@link PMUI.grid.GridPanelCell GridPanelCell} object in which the style is being applied.
|
||
* - data {Object}: a JSON object with the data for the current row.
|
||
* The function will be called in the context of the current {@link PMUI.grid.GridPanelRow row object}.
|
||
* @cfg {Boolean} [disabledButtons=false] If the buttons will be disabled.
|
||
* @cfg {String|Function|null} [buttonTooltip=null] Sets the tooltip message for the buttons (only applicable if
|
||
* the column has its {@link #property-dataType dataType property} set to "button"). It can be a string
|
||
* or null or a function. In the latter case the function must return a string, it will receive two parameters:
|
||
*
|
||
* - The cell, a {@link PMUI.grid.GridPanelCell GridPanelCell} object.
|
||
* - The data that belongs to the current row.
|
||
*
|
||
* The function will be called in the context of the current
|
||
* {@link PMUI.grid.GridPanelCell GridPanelCell cell object}.
|
||
*/
|
||
var GridPanelColumn = function (settings) {
|
||
/**
|
||
* The cells that belongs to the column.
|
||
* @type {PMUI.util.ArrayList}
|
||
*/
|
||
this.cells = new PMUI.util.ArrayList();
|
||
GridPanelColumn.superclass.call(this, jQuery.extend(settings, {elementTag: "th"}));
|
||
/**
|
||
* The text to be shown in the column header.
|
||
* @type {String}
|
||
*/
|
||
this.title = null;
|
||
/**
|
||
* The data type for the cells in this column. It is set by the {@link #cfg-dataType dataType config option} or
|
||
* the {@link #method-setDataType setDataType()} method.
|
||
* @type {String}
|
||
*/
|
||
this.dataType = null;
|
||
/**
|
||
* If the column has the sorting functionality enabled.
|
||
* @type {Boolean}
|
||
*/
|
||
this.sortable = null;
|
||
/**
|
||
* If the column has the searching functionality enabled.
|
||
* @type {Boolean}
|
||
*/
|
||
this.searchable = null;
|
||
/**
|
||
* @event onButtonClick
|
||
* Fired when a button in this column is clicked. The event is called in the column context.
|
||
* @param {PMUI.grid.GridPanelRow} row The row the button belongs to.
|
||
* @param {PMUI.grid.GridPanel} grid The grid the button belongs to.
|
||
*/
|
||
this.onButtonClick = null;
|
||
/**
|
||
* The label for the buttons in the column (only applicable when the datatType is set to "button").
|
||
* @type {String|Function}
|
||
*/
|
||
this.buttonLabel = null;
|
||
/**
|
||
* If the buttons are disabled or not.
|
||
* @type {Boolean}
|
||
*/
|
||
this.disabledButtons = null;
|
||
/**
|
||
* The grid the column belongs to.
|
||
* @type {PMUI.grid.GridPanel}
|
||
*/
|
||
this.grid = null;
|
||
/**
|
||
* The data key to be used for the cells in this column.
|
||
* @type {String}
|
||
*/
|
||
this.columnData = null;
|
||
/**
|
||
* The column sort order ("ASC" or "DESC").
|
||
* @type {String}
|
||
*/
|
||
this.sortOrder = null;
|
||
/**
|
||
* The alignmentCell to be applied to the content of the cells that appertain to this column.
|
||
* @type {String}
|
||
*/
|
||
this.alignmentCell = null;
|
||
/**
|
||
* The style object for the cells that belongs to the column.
|
||
* @type {PMUI.util.Style}
|
||
* @private
|
||
*/
|
||
this.cellStyle = null;
|
||
/**
|
||
* @property {PMUI.util.Style} buttonStyle The style object to be applied in the buttons that belong to the
|
||
* column. Only applicable when the column's type is 'button'.
|
||
*/
|
||
this.buttonStyle = null;
|
||
/**
|
||
* The HTML element in which the cell content will be appended.
|
||
* @type {HTMLElement}
|
||
* @private
|
||
*/
|
||
this.contentTitle = null;
|
||
/**
|
||
* The tooltip to be shown for the buttons in the column. Only applicable when the column's type is 'button'.
|
||
* @type {String|Function}
|
||
*/
|
||
this.buttonTooltip = null;
|
||
/**
|
||
* The DOM element in which the sorting arrow is shown.
|
||
* @type {HTMLElement}
|
||
* @private
|
||
*/
|
||
this.sortIcon = null;
|
||
/**
|
||
* Determines the alignment for the title in the column's header,
|
||
* @type {String}
|
||
*/
|
||
this.alignmentTitle = null;
|
||
GridPanelColumn.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom("PMUI.core.Element", GridPanelColumn);
|
||
|
||
GridPanelColumn.prototype.type = "GridPanelColumn";
|
||
/**
|
||
* Initialize the object
|
||
* @param {Object} [settings=null] A JSON object with the config options.
|
||
* @private
|
||
*/
|
||
GridPanelColumn.prototype.init = function (settings) {
|
||
var defaults = {
|
||
title: '[untitled]',
|
||
dataType: 'string',
|
||
sortable: false,
|
||
searchable: true,
|
||
onButtonClick: function () {
|
||
},
|
||
buttonLabel: '[button]',
|
||
cells: [],
|
||
grid: null,
|
||
columnData: null,
|
||
onSort: null,
|
||
alignmentCell: "center",
|
||
cellStyle: null,
|
||
buttonStyle: null,
|
||
visible: true,
|
||
disabledButtons: false,
|
||
buttonTooltip: null,
|
||
alignmentTitle: 'center',
|
||
positionMode: 'inherit'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.buttonStyle = new PMUI.util.Style();
|
||
this.cellStyle = new PMUI.util.Style();
|
||
this.onSort = defaults.onSort;
|
||
this.setPositionMode(defaults.positionMode);
|
||
this.setTitle(defaults.title)
|
||
.setButtonTooltip(defaults.buttonTooltip)
|
||
.setCellStyle(defaults.cellStyle)
|
||
.setButtonStyle(defaults.buttonStyle)
|
||
.setAlignmentCell(defaults.alignmentCell)
|
||
.setColumnData(defaults.columnData)
|
||
.setDataType(defaults.dataType)
|
||
.setOnButtonClick(defaults.onButtonClick)
|
||
.setButtonLabel(defaults.buttonLabel)
|
||
.setGrid(defaults.grid)
|
||
.setSortable(defaults.sortable)
|
||
.setCells(defaults.cells)
|
||
.setVisible(defaults.visible)
|
||
.setAlignmentTitle(defaults.alignmentTitle);
|
||
|
||
if (defaults.searchable) {
|
||
this.enableSearch();
|
||
} else {
|
||
this.disableSearch();
|
||
}
|
||
|
||
if (defaults.disabled) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
};
|
||
/**
|
||
* Sets the button tooltip. Only applicable
|
||
* @param {String|Function|null} tooltip The tooltip to be used in the buttons in the column. It can be a string
|
||
* or null or a function. In the latter case the function must return a string, it will receive two parameters:
|
||
*
|
||
* - The cell, a {@link PMUI.grid.GridPanelCell GridPanelCell} object.
|
||
* - The data that belongs to the current row.
|
||
*
|
||
* The function will be called in the context of the current
|
||
* {@link PMUI.grid.GridPanelCell GridPanelCell cell object}.
|
||
*/
|
||
GridPanelColumn.prototype.setButtonTooltip = function (tooltip) {
|
||
if (!(typeof tooltip === 'function' || typeof tooltip === 'string' || tooltip === null)) {
|
||
throw new Error('setButtonTooltip(): the parameter must be a function or a string or null.');
|
||
}
|
||
this.buttonTooltip = tooltip;
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables all the buttons in the column, this is applied only if the column's property
|
||
* {@link #property-dataType dataType} is set to "button".
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.disable = function () {
|
||
var i,
|
||
cells,
|
||
cellsLength;
|
||
|
||
this.disabledButtons = true;
|
||
cellsLength = (cells = this.cells.asArray()).length;
|
||
for (i = 0; i < cellsLength; i += 1) {
|
||
cells[i].disable();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Disable one item cell
|
||
* @param index
|
||
* @returns {PMUI.grid.GridPanelColumn.options.GridPanelColumn}
|
||
*/
|
||
GridPanelColumn.prototype.disableCell = function (index) {
|
||
var cells = this.cells.asArray(),
|
||
cellsLength = cells.length;
|
||
if (index < cellsLength && index >= 0) {
|
||
cells[index].disable();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Enable one item cell
|
||
* @param index
|
||
* @returns {PMUI.grid.GridPanelColumn.options.GridPanelColumn}
|
||
*/
|
||
GridPanelColumn.prototype.enableCell = function (index) {
|
||
var cells = this.cells.asArray(),
|
||
cellsLength = cells.length;
|
||
if (index < cellsLength && index >= 0) {
|
||
cells[index].enable();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Enables all the buttons in the column, this is applied only if the column's property
|
||
* {@link #property-dataType dataType} is set to "button".
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.enable = function () {
|
||
var i,
|
||
cells,
|
||
cellsLength;
|
||
|
||
if (this.dataType === 'button') {
|
||
this.disabledButtons = false;
|
||
cellsLength = (cells = this.cells.asArray()).length;
|
||
for (i = 0; i < cellsLength; i += 1) {
|
||
cells[i].enable();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* [setVisible description]
|
||
* @param {[type]} visible [description]
|
||
*/
|
||
GridPanelColumn.prototype.setVisible = function (visible) {
|
||
var cells,
|
||
cellsLength,
|
||
i;
|
||
|
||
GridPanelColumn.superclass.prototype.setVisible.call(this, visible);
|
||
if (this.cells) {
|
||
cells = this.cells.asArray();
|
||
cellsLength = cells.length;
|
||
for (i = 0; i < cellsLength; i += 1) {
|
||
cells[i].setVisible(this.visible);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* [getUsableButtonStyle description]
|
||
* @param {[type]} cell [description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
GridPanelColumn.prototype.getUsableButtonStyle = function (cell) {
|
||
var theStyle,
|
||
buttonStyle = this.buttonStyle,
|
||
theRow;
|
||
|
||
if (typeof buttonStyle !== 'function') {
|
||
return {
|
||
cssClasses: buttonStyle.cssClasses,
|
||
cssProperties: buttonStyle.cssProperties
|
||
};
|
||
} else {
|
||
theRow = cell.row;
|
||
theStyle = buttonStyle.call(theRow, cell, theRow.getData());
|
||
return {
|
||
cssClasses: (theStyle && theStyle.cssClasses) || [],
|
||
cssProperties: (theStyle && theStyle.cssProperties) || {}
|
||
};
|
||
}
|
||
};
|
||
/**
|
||
* Sets the style for the buttons in the column (only applicable if the column has its
|
||
* {@link #property-dataType dataType property} set to "button").
|
||
* @param {PMUI.util.Style|Object|null|Function} cellStyle The style to be applied. It can be:
|
||
*
|
||
* - null then the buttons won't apply any custom style.
|
||
* - An object literal in that case it can have the properties: cssClasses (an array in which each element is
|
||
* an string that is a class name) and cssProperties (another object literal that can contain css properties and
|
||
* its respective values).
|
||
* - An instance of {@link PMUI.util.Style}.
|
||
* - A function that must return any of the previous value types.
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.setButtonStyle = function (buttonStyle) {
|
||
var i,
|
||
cells,
|
||
cellsNum,
|
||
theStyle,
|
||
theRow;
|
||
|
||
if (buttonStyle !== null && typeof buttonStyle !== 'object' && typeof buttonStyle !== 'function' && !(buttonStyle instanceof PMUI.util.Style)) {
|
||
throw new Error("setbuttonStyle(): The parameter only can be an object, an instance of PMUI.util.Style or null.");
|
||
}
|
||
this.buttonStyle = this.buttonStyle.clear();
|
||
if (buttonStyle instanceof PMUI.util.Style) {
|
||
this.buttonStyle = buttonStyle;
|
||
} else if (typeof buttonStyle === 'function') {
|
||
this.buttonStyle = buttonStyle;
|
||
} else if (buttonStyle) {
|
||
this.buttonStyle.addProperties((buttonStyle && buttonStyle.cssProperties) || {})
|
||
.addClasses((buttonStyle && buttonStyle.cssClasses) || []);
|
||
}
|
||
if (this.dataType === 'button') {
|
||
cells = this.cells.asArray();
|
||
cellsNum = cells.length;
|
||
for (i = 0; i < cellsNum; i += 1) {
|
||
cells[i].getContent().setStyle(this.getUsableButtonStyle(cells[i]));
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the style for the buttons that belongs to the column.
|
||
* @return {Object} An object literal with the properties: cssProperties and cssClasses
|
||
*/
|
||
GridPanelColumn.prototype.getButtonStyle = function () {
|
||
return {
|
||
cssClasses: this.buttonStyle.cssClasses,
|
||
cssProperties: this.buttonStyle.cssProperties
|
||
};
|
||
};
|
||
/**
|
||
* Sets the style for the cells in the column.
|
||
* @param {PMUI.util.Style|Object|null} cellStyle The style to be applied. If it is null then the cells won't apply
|
||
* any custom style.
|
||
*/
|
||
GridPanelColumn.prototype.setCellStyle = function (cellStyle) {
|
||
var i,
|
||
cells,
|
||
cellsNum;
|
||
|
||
if (cellStyle !== null && typeof cellStyle !== 'object' && !(cellStyle instanceof PMUI.util.Style)) {
|
||
throw new Error("setCellStyle(): The parameter only can be an object, an instance of PMUI.util.Style or null.");
|
||
}
|
||
this.cellStyle = this.cellStyle.clear();
|
||
if (cellStyle instanceof PMUI.util.Style) {
|
||
this.cellStyle = cellStyle;
|
||
} else if (cellStyle) {
|
||
this.cellStyle.addProperties(cellStyle.cssProperties || {})
|
||
.addClasses(cellStyle.cssClasses || []);
|
||
}
|
||
cells = this.cells.asArray();
|
||
cellsNum = cells.length;
|
||
for (i = 0; i < cellsNum; i += 1) {
|
||
cells[i].setStyle({
|
||
cssClasses: this.cellStyle.cssClasses,
|
||
cssProperties: this.cellStyle.cssProperties
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the style for the cells that belongs to the column.
|
||
* @return {Object} An object literal with the properties: cssProperties and cssClasses
|
||
*/
|
||
GridPanelColumn.prototype.getCellStyle = function () {
|
||
return {
|
||
cssProperties: this.cellStyle.cssProperties,
|
||
cssClasses: this.cellStyle.cssClasses
|
||
};
|
||
};
|
||
/**
|
||
* Sets the alignmentCell for the content in the cells that appertain to the column.
|
||
* @param {String} alignmentCell The accepted values are: "center", "left", "right".
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.setAlignmentCell = function (alignmentCell) {
|
||
var i,
|
||
cells;
|
||
|
||
if (alignmentCell === 'center' || alignmentCell === 'left' || alignmentCell === 'right') {
|
||
this.alignmentCell = alignmentCell;
|
||
cells = this.getCells();
|
||
for (i = 0; i < cells.length; i += 1) {
|
||
cells[i].setAlignment(this.alignmentCell);
|
||
}
|
||
} else {
|
||
throw new Error('setAlignment(): This method only accepts one of the following values: '
|
||
+ '"center", "left", "right"');
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridPanelColumn.prototype.setAlignmentTitle = function (alignmentTitle) {
|
||
if (alignmentTitle === 'center' || alignmentTitle === 'left' || alignmentTitle === 'right') {
|
||
this.alignmentTitle = alignmentTitle;
|
||
if (this.contentTitle) {
|
||
this.contentTitle.style.textAlign = alignmentTitle;
|
||
}
|
||
} else {
|
||
throw new Error('setAlignment(): This method only accepts one of the following values: '
|
||
+ '"center", "left", "right"');
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the alignment for the content in the cells that appertain to the column.
|
||
* @return {String}
|
||
*/
|
||
GridPanelColumn.prototype.getAlignment = function () {
|
||
return this.alignment;
|
||
};
|
||
/**
|
||
* Returns true is the filtering function is enabled, otherwise returns false.
|
||
* @return {Boolean}
|
||
*/
|
||
GridPanelColumn.prototype.isSearchable = function () {
|
||
return this.searchable;
|
||
};
|
||
/**
|
||
* Enables the filtering functionality.
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.enableSearch = function () {
|
||
this.searchable = true;
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables the filtering functionality.
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.disableSearch = function () {
|
||
this.searchable = false;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the data's field name that is used by the row to fill its cell for this column.
|
||
* @return {String}
|
||
*/
|
||
GridPanelColumn.prototype.getColumnData = function () {
|
||
return this.columnData;
|
||
};
|
||
/**
|
||
* Sets a function or a string that will represent the data's field name that is used by the row to fill its cell
|
||
* for this column.
|
||
* @param {String|Function} columnData It can be a String or a Function
|
||
* - In case of a String: The data key to be used for the cells in this column.
|
||
* - In case of a Function: A function that will return the content for the cells in column, the parameters receive
|
||
* by the function are:
|
||
* - data {Object}: a JSON object with the data for the current row.
|
||
* The function will be called in the context of the current {@link PMUI.grid.GridPanelRow row object}.
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.setColumnData = function (columnData) {
|
||
if (columnData === null || typeof columnData === 'string' || typeof columnData === 'function') {
|
||
this.columnData = columnData;
|
||
} else {
|
||
throw new Error('setColumnData(): The method only accepts a string or a function or NULL as parameter.');
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the title to be shown in the column header.
|
||
* @param {String} title
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.setTitle = function (title) {
|
||
this.title = title;
|
||
if (this.html) {
|
||
jQuery(this.contentTitle).empty();
|
||
this.contentTitle.appendChild(document.createTextNode(title));
|
||
this.contentTitle.appendChild(this.sortIcon);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the column's data type.
|
||
* @return {String}
|
||
*/
|
||
GridPanelColumn.prototype.getDataType = function () {
|
||
return this.dataType;
|
||
};
|
||
/**
|
||
* Sets the data type for the column.
|
||
* @param {String} dataType The accepted values are:
|
||
*
|
||
* - "number" for cells with numeric values.
|
||
* - "string" for cells with string values.
|
||
* - "index" for cells with the row index.
|
||
* - "date" for cells with date values.
|
||
* - "button" for cells that contain a button.
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.setDataType = function (dataType) {
|
||
if (dataType === 'string' || dataType === 'number' || dataType === 'index' || dataType === 'date' || dataType === 'button') {
|
||
this.dataType = dataType;
|
||
} else {
|
||
throw new Error('setDataType(): It only accepts "string", "number", "index" or "date".');
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Enables or disables the sorting functionality.
|
||
* @param {Boolean} sortable
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.setSortable = function (sortable) {
|
||
if (!(typeof sortable === 'boolean')) {
|
||
throw new Error("setSortable(): property 'sortable' should be a boolean");
|
||
}
|
||
//TODO enable event to listen the clicks on column for sorting
|
||
this.sortable = sortable;
|
||
if (this.html) {
|
||
if (sortable) {
|
||
this.style.addClasses(['pmui-sortable']);
|
||
} else {
|
||
this.style.removeClasses(['pmui-sortable']);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the callback function to be executed when a column's button is clicked.
|
||
* @return {Function}
|
||
*/
|
||
GridPanelColumn.prototype.getOnButtonClick = function () {
|
||
return this.onButtonClick;
|
||
};
|
||
/**
|
||
* Sets the callback function to be executed when a column's button is clicked.
|
||
* @param {Function} onButtonClick
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.setOnButtonClick = function (onButtonClick) {
|
||
if (!(typeof onButtonClick == 'function')) {
|
||
throw new Error("setOnButtonClick(): property 'onButtonClick' should be a function");
|
||
}
|
||
this.onButtonClick = onButtonClick;
|
||
//TODO update the listeners for all the buttons in the column
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the text for the button labels in the column.
|
||
* @param {String|Function} buttonLabel A string or a function that returns the string for the button. Three
|
||
* parameters function will be sent to the function:
|
||
*
|
||
* - The row the button belongs to ({@link PMUI.grid.GridPanelRow GridPanelRow}).
|
||
* - The data from the row (object literal).
|
||
*
|
||
* It is important to mention that the function is called in the context of the column object.
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.setButtonLabel = function (buttonLabel) {
|
||
if (typeof buttonLabel !== 'string' && typeof buttonLabel !== 'function') {
|
||
throw new Error('setButtonLabel(): the parameter must be a string or a function.');
|
||
}
|
||
this.buttonLabel = buttonLabel;
|
||
//TODO update the label for all the buttons in the column
|
||
return this;
|
||
};
|
||
/**
|
||
* Set the grid the column belongs to.
|
||
* @param {PMUI.grid.Grid} grid
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.setGrid = function (grid) {
|
||
if (!(grid instanceof PMUI.grid.GridPanel)) {
|
||
throw new Error('setGrid(): the grid property should be instance of [PMUI.grid.GridPanel]');
|
||
}
|
||
this.grid = grid;
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a cell to the column.
|
||
* @param {PMUI.grid.GridPanelCell} cell
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.addCell = function (cell) {
|
||
if (!(cell instanceof PMUI.grid.GridPanelCell)) {
|
||
throw new Error("addCell(): this method only accepts instances of PMUI.grid.GridPanelCell.");
|
||
}
|
||
cell.setAlignment(this.alignmentCell);
|
||
cell.setStyle({
|
||
cssProperties: this.cellStyle.getProperties(),
|
||
cssClasses: this.cellStyle.getClasses()
|
||
});
|
||
this.cells.insert(cell);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Set the cells for the column.
|
||
* @param {PMUI.util.ArrayList|Array} cells An array in which every element is an instance of the
|
||
* {@link PMUI.grid.GridPanelCell GridPanelCell class}.
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.setCells = function (cells) {
|
||
var cellsAux = [],
|
||
i;
|
||
|
||
this.clearCells();
|
||
|
||
if (cells instanceof PMUI.util.ArrayList) {
|
||
cellsAux = cells.items.asArray();
|
||
} else if (jQuery.isArray(cells)) {
|
||
cellsAux = cells;
|
||
} else {
|
||
throw new Error('setCells(): the cells property should be instanceof of PMUI.util.ArrayList or an Array');
|
||
}
|
||
for (i = 0; i < cellsAux.length; i += 1) {
|
||
this.addCell(cellsAux[i]);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Return the column's cells.
|
||
* @return {Array} An array in which each element is an instance of the
|
||
* {@link PMUI.grid.GridPanelCell GridPanelCell class}.
|
||
*/
|
||
GridPanelColumn.prototype.getCells = function () {
|
||
return this.cells.asArray().slice(0);
|
||
};
|
||
/**
|
||
* Removes a cell from the column.
|
||
* @param {PMUI.grid.GridPanelCell|Number|String} cell The cell to remove, it can be:
|
||
*
|
||
* - An instance of {@link PMUI.grid.GridPanelCell GridPanelCell}, in this case this cell must belong to the
|
||
* column.
|
||
* - A Number, in this case it is interpreted as the index of the cell to remove.
|
||
* - A String, in this case it is interpreted as the id of the cell to remove.
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.removeCell = function (cell) {
|
||
var cellToRemove;
|
||
|
||
if (cell instanceof PMUI.grid.GridPanelCell) {
|
||
cellToRemove = cell;
|
||
} else if (typeof cell === 'number') {
|
||
cellToRemove = this.cells.get(cell);
|
||
} else if (typeof cell === 'string') {
|
||
cellToRemove = this.cells.find("id", cell);
|
||
}
|
||
|
||
if (cellToRemove) {
|
||
cellToRemove.column = null;
|
||
this.cells.remove(cellToRemove);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Clears all the cells of the column.
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.clearCells = function () {
|
||
this.cells.clear();
|
||
while (this.cells.getSize() > 0) {
|
||
this.removeCell(0);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Defines the event for the object.
|
||
* @chainable
|
||
*/
|
||
GridPanelColumn.prototype.defineEvents = function () {
|
||
var that = this;
|
||
|
||
this.removeEvents().eventsDefined = true;
|
||
if (this.html) {
|
||
this.addEvent('click').listen(this.html, function () {
|
||
if (that.sortable) {
|
||
that.sortOrder = that.sortOrder === 'asc' ? 'desc' : 'asc';
|
||
if (typeof that.onSort === 'function') {
|
||
that.onSort(that.sortOrder);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the html for the object.
|
||
* @return {HTMLElement}
|
||
*/
|
||
GridPanelColumn.prototype.createHTML = function () {
|
||
var contentTitle,
|
||
sortIcon;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
GridPanelColumn.superclass.prototype.createHTML.call(this);
|
||
sortIcon = PMUI.createHTMLElement('span');
|
||
sortIcon.className = 'pmui-grid-sort-icon';
|
||
contentTitle = PMUI.createHTMLElement('span');
|
||
contentTitle.className = 'pmui-gridpanelColumn-title';
|
||
this.contentTitle = contentTitle;
|
||
this.sortIcon = sortIcon;
|
||
this.html.appendChild(contentTitle);
|
||
this.setTitle(this.title)
|
||
.setSortable(this.sortable)
|
||
.setWidth(this.width)
|
||
.setAlignmentTitle(this.alignmentTitle);
|
||
return this.html;
|
||
};
|
||
|
||
GridPanelColumn.prototype.setWidth = function (width) {
|
||
var finalWidth,
|
||
i,
|
||
cellsLength,
|
||
cells;
|
||
|
||
if (typeof width === 'number') {
|
||
this.width = width;
|
||
} else if (/^\d+(\.\d+)?px$/.test(width)) {
|
||
this.width = parseInt(width, 10);
|
||
} else if (/^\d+(\.\d+)?%$/.test(width)) {
|
||
this.width = width;
|
||
} else if (/^\d+(\.\d+)?em$/.test(width)) {
|
||
this.width = width;
|
||
} else if (width === 'auto') {
|
||
this.width = width;
|
||
} else {
|
||
throw new Error('setWidth: width param is not a number');
|
||
}
|
||
|
||
if (typeof this.width === 'string') {
|
||
finalWidth = 'auto';
|
||
} else {
|
||
finalWidth = this.width + 'px';
|
||
}
|
||
|
||
if (this.html) {
|
||
this.contentTitle.style.minWidth = finalWidth;
|
||
}
|
||
cellsLength = (cells = this.cells.asArray()).length;
|
||
for (i = 0; i < cellsLength; i += 1) {
|
||
cells[i].setWidth(finalWidth);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridPanelColumn.prototype.applyStyle = function () {
|
||
if (this.html) {
|
||
this.style.applyStyle();
|
||
|
||
this.style.addProperties({
|
||
display: this.visible ? this.display : "none",
|
||
position: this.positionMode,
|
||
left: this.x,
|
||
top: this.y,
|
||
width: (typeof this.width === 'string') ? this.width : 'auto',
|
||
height: this.height,
|
||
zIndex: this.zOrder
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace("PMUI.grid.GridPanelColumn", GridPanelColumn);
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = GridPanelColumn;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.grid.GridPanelRow
|
||
* Class that defines a row to be used in a {@link PMUI.grid.GridPanel GridPanel}.
|
||
* The single class is not very useful alone, it should be used with a {@link PMUI.grid.GridPanel GridPanel}.
|
||
* @extends {PMUI.core.Element}
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var row = new PMUI.grid.GridPanelRow({
|
||
* data: {
|
||
* name: "John",
|
||
* lastname: "McAllister"
|
||
* }
|
||
* }),
|
||
* grid = new PMUI.grid.GridPanel({
|
||
* pageSize: 6,
|
||
* columns:[
|
||
* {
|
||
* title:'columna1',
|
||
* dataType:'string',
|
||
* columnData: "name"
|
||
* },
|
||
* {
|
||
* title:'columna2',
|
||
* dataType:'number',
|
||
* width : 150,
|
||
* columnData: "lastName",
|
||
* sortable: true
|
||
* }
|
||
* ],
|
||
* items: [
|
||
* row
|
||
* ]
|
||
* });
|
||
*
|
||
* document.body.appendChild(grid.getHTML());
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the GridPanelRow class.
|
||
* @param {Object} settings A JSON object with the config options.
|
||
*
|
||
* @cfg {PMUI.data.DataField|Object} [data={}] A {@link PMUI.data.DataField DataField} or a JSON object with the
|
||
* data for the GridPanelRow.
|
||
* @cfg {PMUI.grid.GridPanel} [parent=null] The {@link PMUI.grid.GridPanel GridPanel} the GridPanelRow belongs to.
|
||
*/
|
||
var GridPanelRow = function (settings) {
|
||
GridPanelRow.superclass.call(this, jQuery.extend(settings, {elementTag: "tr"}));
|
||
/**
|
||
* An ArrayList that contains the row's cells ({@link PMUI.grid.GridPanelCell GridPanelCell}).
|
||
* @type {PMUI.util.ArrayList}
|
||
* @private
|
||
*/
|
||
this.cells = null;
|
||
/**
|
||
* The parent GridPanel of the GridPanelRow.
|
||
* @type {PMUI.grid.GridPanel GridPanel}
|
||
* @readonly
|
||
*/
|
||
this.parent = null;
|
||
/**
|
||
* The data that belongs to the GridPanelRow.
|
||
* @type {PMUI.data.DataField}
|
||
* @private
|
||
*/
|
||
this.data = null;
|
||
|
||
this.onClick = null;
|
||
|
||
this.selected = null;
|
||
this.onSelect = null;
|
||
GridPanelRow.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', GridPanelRow);
|
||
/**
|
||
* The class family.
|
||
* @type {String}
|
||
*/
|
||
GridPanelRow.prototype.family = 'GridPanelRow';
|
||
/**
|
||
* The object's family.
|
||
* @type {String}
|
||
*/
|
||
GridPanelRow.prototype.type = 'GridPanelRow';
|
||
/**
|
||
* Initialize the object.
|
||
* @param {Object} settings A JSON object with the config options.
|
||
* @private
|
||
*/
|
||
GridPanelRow.prototype.init = function (settings) {
|
||
var defaults = {
|
||
data: {},
|
||
parent: null,
|
||
onClick: null,
|
||
onSelect: function () {
|
||
}
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.cells = new PMUI.util.ArrayList();
|
||
this.data = new PMUI.data.DataField();
|
||
|
||
this.setData(defaults.data)
|
||
.setParent(defaults.parent)
|
||
.setOnClick(defaults.onClick)
|
||
.setOnSelectCallback(defaults.onSelect);
|
||
};
|
||
/**
|
||
* Set the data for the object.
|
||
* @param {PMUI.data.DataField|Object} dataç
|
||
* @chainable
|
||
*/
|
||
GridPanelRow.prototype.setData = function (data) {
|
||
var key;
|
||
|
||
if (data instanceof PMUI.data.DataField) {
|
||
this.data = data;
|
||
} else if (typeof data === 'object') {
|
||
this.data.clear();
|
||
for (key in data) {
|
||
this.data.addAttribute(key, data[key]);
|
||
}
|
||
} else {
|
||
throw new Error("setData(): it only accepts a JSON object o an instance of PMUI.data.DataField as parameter.");
|
||
}
|
||
|
||
if (this.html) {
|
||
this.setCells();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Set the parent grid for the object.
|
||
* @param {PMUI.grid.GridPanel} parent
|
||
* @chainable
|
||
*/
|
||
GridPanelRow.prototype.setParent = function (parent) {
|
||
if (parent) {
|
||
if (parent instanceof PMUI.grid.GridPanel) {
|
||
this.parent = parent;
|
||
} else {
|
||
throw new Error("setParent() method only accepts a object [PMUI.panel.GridPanel] as parameter.");
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the object's parent grid.
|
||
* @return {PMUI.grid.GridPanel}
|
||
*/
|
||
GridPanelRow.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
/**
|
||
* Updates the width for each row's cell using the respective column's width.
|
||
* @chainable
|
||
*/
|
||
GridPanelRow.prototype.updateCellsWidth = function () {
|
||
var i,
|
||
cells,
|
||
cellsLength;
|
||
|
||
cellsLength = (cells = this.cells.asArray()).length;
|
||
for (i = 0; i < cellsLength; i += 1) {
|
||
cells[i].setWidth(cells[i].column.width);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Paints a cell in the row.
|
||
* @param {PMUI.grid.GridPanelCell} cell
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
GridPanelRow.prototype.paintCell = function (cell) {
|
||
if (this.html) {
|
||
this.html.appendChild(cell.getHTML());
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Paints all cells in the row.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
GridPanelRow.prototype.paintCells = function () {
|
||
var i,
|
||
cells = this.cells.asArray();
|
||
|
||
for (i = 0; i < cells.length; i += 1) {
|
||
this.paintCell(cells[i]);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Add a single cell into the row.
|
||
* @param {PMUI.grid.GridPanelColumn|null} [column=null] It can be:
|
||
*
|
||
* - null, in this case an empty cell will be added at the end of the row.
|
||
* - A {@link PMUI.grid.GridPanelColumn GridPanelColumn}, in this case the cell will be created using the settings
|
||
* the parameter has for its cells. Also the cell will be associated to the column.
|
||
*/
|
||
GridPanelRow.prototype.addCell = function (column) {
|
||
var data,
|
||
columnData,
|
||
cell,
|
||
cellIndex,
|
||
buttonLabel,
|
||
buttonTooltip,
|
||
content,
|
||
that = this;
|
||
|
||
if (!(column === null || column instanceof PMUI.grid.GridPanelColumn)) {
|
||
throw new Error("addCell(): The parameter must be an instance of PMUI.grid.GridPanel o null.");
|
||
}
|
||
data = this.data.getRecord();
|
||
cellIndex = this.parent.getColumns().length;
|
||
cell = new PMUI.grid.GridPanelCell({
|
||
columnIndex: cellIndex,
|
||
row: this,
|
||
column: column || null,
|
||
visible: (column && column.visible) && true,
|
||
width: (column && column.width) || "auto"
|
||
});
|
||
if (column) {
|
||
columnData = column.getColumnData();
|
||
if (column.dataType === 'button') {
|
||
buttonLabel = column.buttonLabel;
|
||
buttonTooltip = column.buttonTooltip;
|
||
content = new PMUI.ui.Button({
|
||
style: column.getUsableButtonStyle(),
|
||
text: typeof buttonLabel === 'function' ? buttonLabel(this, data) : (buttonLabel || ""),
|
||
messageTooltip: (typeof buttonTooltip === 'function' ? buttonTooltip.call(cell, cell, data)
|
||
: (buttonTooltip || "")),
|
||
handler: (function (handler) {
|
||
return function () {
|
||
handler(that, that.parent);
|
||
};
|
||
}(column.getOnButtonClick()))
|
||
});
|
||
} else if (column.dataType === 'index') {
|
||
content = this.parent.getItemIndex(this) + 1;
|
||
} else if (columnData) {
|
||
if (typeof columnData === 'function') {
|
||
content = columnData.call(this, data);
|
||
} else {
|
||
content = this.data.getAttribute(columnData);
|
||
}
|
||
}
|
||
|
||
cell.style.addClasses(["pmui-gridpanelcell-" + column.dataType]);
|
||
} else {
|
||
content = null;
|
||
}
|
||
cell.setContent(content);
|
||
this.cells.insert(cell);
|
||
column.addCell(cell);
|
||
this.paintCell(cell);
|
||
return this;
|
||
};
|
||
/**
|
||
* @method setCells
|
||
* Build the cells for the row using its parent {@link PMUI.grid.GridPanel#property-columns GridPanel's columns} to
|
||
* retrieve the data from the odject's {@link PMUI.grid.GridPanelRow#property-data data}.
|
||
* @chainable
|
||
*/
|
||
GridPanelRow.prototype.setCells = function () {
|
||
var i,
|
||
columns;
|
||
|
||
this.clearCells();
|
||
if (this.parent) {
|
||
columns = this.parent.getColumns();
|
||
for (i = 0; i < columns.length; i += 1) {
|
||
this.addCell(columns[i]);
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the data that belongs to the object.
|
||
* @return {Object} A JSON object with the data.
|
||
*/
|
||
GridPanelRow.prototype.getData = function () {
|
||
return this.data.getRecord();
|
||
};
|
||
/**
|
||
* Returns the object's cells.
|
||
* @return {Array} An array in which every item is a object's {@link PMUI.grid.GridPanelCell cell}.
|
||
*/
|
||
GridPanelRow.prototype.getCells = function () {
|
||
return this.cells.asArray().slice(0);
|
||
};
|
||
/**
|
||
* Clear the cells from the object.
|
||
* @chainable
|
||
*/
|
||
GridPanelRow.prototype.clearCells = function () {
|
||
var i;
|
||
while (this.cells.getSize()) {
|
||
this.removeCell(0);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Remove a cell from the object.
|
||
* @param {PMUI.grid.GridPanelCell|Number|String} cell It can be:
|
||
*
|
||
* - A instance of {@link PMUI.grid.GridPanelCell GridPanelCell}, in this case it must be a cell that belongs to
|
||
* the object.
|
||
* - A Number, in this case the cell with that index will be removed.
|
||
* - A String, in this case the cell with that id will be removed.
|
||
* @chainable
|
||
*/
|
||
GridPanelRow.prototype.removeCell = function (cell) {
|
||
var cellToRemove,
|
||
column;
|
||
|
||
if (cell instanceof PMUI.grid.GridPanelCell) {
|
||
cellToRemove = cell;
|
||
} else if (typeof cell === 'number') {
|
||
cellToRemove = this.cells.get(cell);
|
||
} else if (typeof cell === 'string') {
|
||
cellToRemove = this.cells.find("id", cell)
|
||
} else {
|
||
throw new Error("removeCell(): This method only accepts a number or a string or a instance of " +
|
||
"PMUI.grid.GridPanelCell as parameter");
|
||
}
|
||
|
||
if (cellToRemove) {
|
||
cellToRemove.setColumnIndex(null);
|
||
cellToRemove.row = null;
|
||
jQuery(cellToRemove.html).remove();
|
||
column = cellToRemove.getColumn();
|
||
if (column) {
|
||
column.removeCell(cellToRemove);
|
||
}
|
||
cellToRemove.column = null;
|
||
this.cells.remove(cellToRemove);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Attach the listeners for the object and every of its children.
|
||
* @chainable
|
||
*/
|
||
GridPanelRow.prototype.defineEvents = function () {
|
||
var that = this;
|
||
|
||
this.removeEvents().eventsDefined = true;
|
||
if (this.html) {
|
||
this.addEvent('click').listen(this.html, function (e) {
|
||
e.preventDefault();
|
||
if (typeof that.onClick === 'function') {
|
||
that.onClick(that, that.getData());
|
||
}
|
||
if (that.parent.selectable) {
|
||
if (!that.selected) {
|
||
that.selectRow();
|
||
}
|
||
}
|
||
if (that.parent && typeof that.parent.onRowClick === 'function') {
|
||
that.parent.onRowClick(that, that.getData());
|
||
}
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the object's HTML.
|
||
* @return {HTMLElement}
|
||
*/
|
||
GridPanelRow.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
GridPanelRow.superclass.prototype.createHTML.call(this);
|
||
this.paintCells()
|
||
.defineEvents();
|
||
return this.html;
|
||
};
|
||
/**
|
||
* [setOnClick description]
|
||
* @param {[type]} onClick [description]
|
||
*/
|
||
GridPanelRow.prototype.setOnClick = function (onClick) {
|
||
if (typeof onClick !== 'function' && onClick !== null) {
|
||
throw new Error('setOnClick(): the parameter is no valid, should be a function');
|
||
}
|
||
this.onClick = onClick;
|
||
return this;
|
||
};
|
||
/**
|
||
* [selectRow description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
GridPanelRow.prototype.selectRow = function () {
|
||
this.selected = true;
|
||
this.style.addClasses(['pmui-active-row']);
|
||
if (typeof this.onSelect === 'function') {
|
||
this.onSelect();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* [isSelectedRow description]
|
||
* @return {Boolean} [description]
|
||
*/
|
||
GridPanelRow.prototype.isSelectedRow = function () {
|
||
return this.selected;
|
||
};
|
||
/**
|
||
* [deselectRow description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
GridPanelRow.prototype.deselectRow = function () {
|
||
if (this.onSelect) {
|
||
this.selected = false;
|
||
this.style.removeClasses(['pmui-active-row']);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* [setOnSelectRowCallback description]
|
||
* @param {Function} callback [description]
|
||
*/
|
||
GridPanelRow.prototype.setOnSelectCallback = function (callback) {
|
||
if (typeof callback === 'function' || callback == null) {
|
||
this.onSelect = callback;
|
||
} else {
|
||
throw new Error("setOnSelectCallback(): The parameter is not a function.");
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.grid.GridPanelRow', GridPanelRow);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = GridPanelRow;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.grid.GridPanelCell
|
||
* Class that represent a cell to be used in instances of {@link PMUI.grid.GridPanelRow GridPanelRow}.
|
||
* It's not very useful to instantiate this class to use it alone. Most of cases you won't need to instantiate it,
|
||
* the {@link PMUI.grid.GridPanelRow GridPanelRow} creates its own cells objects automatically.
|
||
* {@link PMUI.grid.GridPanelRow GridPanelRow}.
|
||
* @extends {PMUI.core.Element}
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var cell = new PMUI.grid.GridPanelCell({
|
||
* content: "This is the cell content"
|
||
* });
|
||
*
|
||
* document.body.appendChild(cell.getHTML());
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the GridPanelCell class.
|
||
* @param {Object} settings A JSON object with the config options.
|
||
*
|
||
* @cfg {String|Number|PMUI.core.Element|null} [content=null] The content to be displayed in the cell, in case to
|
||
* be null the cells has no content.
|
||
* @cfg {Number} [columnIndex=null] The column index the cell belongs to.
|
||
* @cfg {PMUI.grid.GridPanelRow} [row=null] The row the cell belongs to.
|
||
* @cfg {PMUI.grid.GridPanelColumn} [column=null] The column the cell belongs to.
|
||
* @cfg {String} [alignment="center"] A string that specifies the alignment for the cell content. The accepted
|
||
* values are: "center", "left", "right".
|
||
* @cfg {Boolean} [disabled=false] If the cell will be disabled or not.
|
||
*/
|
||
var GridPanelCell = function (settings) {
|
||
GridPanelCell.superclass.call(this, jQuery.extend(settings, {elementTag: "td"}));
|
||
/**
|
||
* The content for the cell.
|
||
* @type {PMUI.core.Element|String|Number}
|
||
*/
|
||
this.content = null;
|
||
/**
|
||
* The position index for the cell, relative to its parent row.
|
||
* @type {Number}
|
||
*/
|
||
this.columnIndex = null;
|
||
/**
|
||
* The row the cell belongs to.
|
||
* @type {PMUI.grid.GridPanelRow}
|
||
*/
|
||
this.row = null;
|
||
/**
|
||
* The column the cell appertains to.
|
||
* @type {PMUI.grid.GridPanelColumn}
|
||
*/
|
||
this.column = null;
|
||
/**
|
||
* The alignment to be applied to the cell content.
|
||
* @type {String}
|
||
*/
|
||
this.alignment = null;
|
||
this.contentSpan = null;
|
||
/**
|
||
* If the cell content is disabled or not.
|
||
* @type {Boolean}
|
||
*/
|
||
this.disabled = null;
|
||
GridPanelCell.prototype.init.call(this, settings);
|
||
};
|
||
PMUI.inheritFrom("PMUI.core.Element", GridPanelCell);
|
||
/**
|
||
* The object's type.
|
||
* @type {String}
|
||
*/
|
||
GridPanelCell.prototype.type = "GridPanelCell";
|
||
/**
|
||
* The class family.
|
||
* @type {String}
|
||
*/
|
||
GridPanelCell.prototype.family = "grid";
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} settings A JSON object with the config options.
|
||
* @private
|
||
*/
|
||
GridPanelCell.prototype.init = function (settings) {
|
||
var defaults = {
|
||
content: null,
|
||
columnIndex: null,
|
||
row: null,
|
||
column: null,
|
||
alignment: "center",
|
||
disabled: false
|
||
};
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.row = defaults.row;
|
||
this.column = defaults.column;
|
||
this.eventsDefined = false;
|
||
|
||
if (defaults.disabled) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
|
||
this.setAlignment(defaults.alignment)
|
||
.setContent(defaults.content)
|
||
.setColumnIndex(defaults.columnIndex);
|
||
};
|
||
/**
|
||
* Sets the alignment for the content in the cell.
|
||
* @param {String} alignment The accepted values are: "center", "left", "right".
|
||
* @chainable
|
||
*/
|
||
GridPanelCell.prototype.setAlignment = function (alignment) {
|
||
if (alignment === 'center' || alignment === 'left' || alignment === 'right') {
|
||
this.alignment = alignment;
|
||
if (this.html && this.contentSpan) {
|
||
this.contentSpan.style.textAlign = this.alignment;
|
||
this.style.addProperties({'text-align': this.alignment});
|
||
}
|
||
} else {
|
||
throw new Error('setAlignment(): This method only accepts one of the following values: '
|
||
+ '"canter", "left", "right"');
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the cell's content alignment.
|
||
* @return {String}
|
||
*/
|
||
GridPanelCell.prototype.getAlignment = function () {
|
||
return this.alignment;
|
||
};
|
||
/**
|
||
* Sets the content for the cell.
|
||
* @param {String|Number|PMUI.core.Element|null} content The content to be displayed in the cell, in case to
|
||
* be null the cells has no content.
|
||
* @chainable
|
||
*/
|
||
GridPanelCell.prototype.setContent = function (content) {
|
||
var type,
|
||
visibleContent;
|
||
|
||
this.content = content;
|
||
|
||
if (content instanceof PMUI.core.Element) {
|
||
visibleContent = content.getHTML();
|
||
} else if (typeof content === 'number' || typeof content === 'string') {
|
||
visibleContent = document.createTextNode(content);
|
||
} else if (content === null || content === undefined) {
|
||
visibleContent = undefined;
|
||
} else {
|
||
throw new Error("setContent(): invalid parameter, it should be a Number, String or an instance of PMUI.core.Element.");
|
||
}
|
||
|
||
if (this.html) {
|
||
jQuery(this.contentSpan).empty();
|
||
if (visibleContent) {
|
||
this.contentSpan.appendChild(visibleContent);
|
||
} else {
|
||
this.contentSpan.innerHTML = ' ';
|
||
}
|
||
if (this.disabled) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the column the cell belongs to.
|
||
* @return {PMUI.grid.GridPanelColumn}
|
||
*/
|
||
GridPanelCell.prototype.getColumn = function () {
|
||
return this.column;
|
||
};
|
||
/**
|
||
* Returns the row the cell belongs to.
|
||
* @return {PMUI.grid.GridPanelRow}
|
||
*/
|
||
GridPanelCell.prototype.getRow = function () {
|
||
return this.row;
|
||
};
|
||
/**
|
||
* Returns the cell's content.
|
||
* @return {String|Number|PMUI.core.Element|null}
|
||
*/
|
||
GridPanelCell.prototype.getContent = function () {
|
||
return this.content;
|
||
};
|
||
/**
|
||
* Sets the index of the column the cell belongs to.
|
||
* @param {Number} columnIndex
|
||
*/
|
||
GridPanelCell.prototype.setColumnIndex = function (columnIndex) {
|
||
this.columnIndex = columnIndex
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the index of the column the cell belongs to.
|
||
* @return {Number}
|
||
*/
|
||
GridPanelCell.prototype.getColumnIndex = function () {
|
||
return this.columnIndex;
|
||
};
|
||
/**
|
||
* Defines the events for the object.
|
||
* @chainable
|
||
*/
|
||
GridPanelCell.prototype.defineEvents = function () {
|
||
this.eventsDefined = true;
|
||
if (this.content instanceof PMUI.core.Element) {
|
||
this.content.defineEvents();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the object's html.
|
||
* @return {HTMLElement}
|
||
*/
|
||
GridPanelCell.prototype.createHTML = function () {
|
||
var type,
|
||
contentSpan;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
GridPanelCell.superclass.prototype.createHTML.call(this);
|
||
contentSpan = PMUI.createHTMLElement('span');
|
||
contentSpan.className = 'pmui-gridpanelcell-content';
|
||
this.contentSpan = contentSpan;
|
||
this.html.appendChild(this.contentSpan);
|
||
this.setAlignment(this.alignment)
|
||
.setContent(this.content)
|
||
.setWidth(this.width)
|
||
.defineEvents();
|
||
return this.html;
|
||
};
|
||
|
||
GridPanelCell.prototype.setWidth = function (width) {
|
||
if (typeof width === 'number') {
|
||
this.width = width;
|
||
} else if (/^\d+(\.\d+)?px$/.test(width)) {
|
||
this.width = parseInt(width, 10);
|
||
} else if (/^\d+(\.\d+)?%$/.test(width)) {
|
||
this.width = width;
|
||
} else if (/^\d+(\.\d+)?em$/.test(width)) {
|
||
this.width = width;
|
||
} else if (width === 'auto') {
|
||
this.width = width;
|
||
} else {
|
||
throw new Error('setWidth: width param is not a number');
|
||
}
|
||
|
||
if (this.html) {
|
||
if (typeof this.width === 'string') {
|
||
this.contentSpan.style.width = 'auto';
|
||
} else {
|
||
this.contentSpan.style.width = this.width + 'px';
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridPanelCell.prototype.applyStyle = function () {
|
||
if (this.html) {
|
||
this.style.applyStyle();
|
||
|
||
this.style.addProperties({
|
||
display: this.visible ? this.display : "none",
|
||
position: this.positionMode,
|
||
left: this.x,
|
||
top: this.y,
|
||
width: (typeof this.width === 'string') ? this.width : 'auto',
|
||
height: this.height,
|
||
zIndex: this.zOrder
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Enables the cell's content.
|
||
* @chainable
|
||
*/
|
||
GridPanelCell.prototype.enable = function () {
|
||
this.disabled = false;
|
||
if (this.content && this.content.enable) {
|
||
this.content.enable();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables the cell's content.
|
||
* @chainable
|
||
*/
|
||
GridPanelCell.prototype.disable = function () {
|
||
this.disabled = true;
|
||
if (this.content && this.content.disable) {
|
||
this.content.disable();
|
||
}
|
||
return this;
|
||
};
|
||
PMUI.extendNamespace("PMUI.grid.GridPanelCell", GridPanelCell);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = GridPanelCell;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
var ControlGrid = function (settings) {
|
||
ControlGrid.superclass.call(this, jQuery.extend(true, settings, {
|
||
factory: {
|
||
products: {
|
||
"GridControlRow": PMUI.grid.GridControlRow
|
||
},
|
||
defaultProduct: "GridControlRow"
|
||
}
|
||
}));
|
||
this.columnsFactory = new PMUI.util.Factory();
|
||
this.dependencies = {};
|
||
ControlGrid.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.grid.GridPanel', ControlGrid);
|
||
|
||
ControlGrid.prototype.init = function (settings) {
|
||
var defaults = {
|
||
allowedCells: {
|
||
'text': PMUI.grid.TextControlColumn,
|
||
'dropdownlist': PMUI.grid.DropDownListControlColumn,
|
||
'checkboxgroup': PMUI.grid.CheckBoxGroupColumn,
|
||
'number': PMUI.grid.NumberColumn
|
||
}
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setAllowedCells(defaults.allowedCells)
|
||
.setColumns(defaults.columns);
|
||
};
|
||
|
||
ControlGrid.prototype.setAllowedCells = function (allowedCells) {
|
||
this.columnsFactory.clearProducts()
|
||
.setProducts(allowedCells);
|
||
return this;
|
||
};
|
||
|
||
ControlGrid.prototype.getColumn = function (column) {
|
||
var the_column = null;
|
||
if (typeof column === 'string') {
|
||
the_column = this.columns.find('name', column);
|
||
} else if (typeof column === 'number') {
|
||
the_column = this.columns.get(column);
|
||
}
|
||
return the_column;
|
||
};
|
||
|
||
ControlGrid.prototype.setColumns = function (columns) {
|
||
if (this.columnsFactory) {
|
||
ControlGrid.superclass.prototype.setColumns.call(this, columns);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ControlGrid.prototype.removeColumn = function (column) {
|
||
ControlGrid.superclass.prototype.removeColumn.call(this, column);
|
||
return this.updateDependencies();
|
||
};
|
||
|
||
ControlGrid.prototype.updateDependencies = function () {
|
||
var dependencies = {},
|
||
i,
|
||
j,
|
||
columns = this.columns.asArray(),
|
||
dependent,
|
||
dependents;
|
||
|
||
for (i = 0; i < columns.length; i += 1) {
|
||
dependents = columns[i].dependentCols;
|
||
for (j = 0; j < dependents.length; j += 1) {
|
||
if (this.getColumn(dependents[j])) {
|
||
if (!dependencies[dependents[j]]) {
|
||
dependencies[dependents[j]] = [];
|
||
}
|
||
dependencies[dependents[j]].push(columns[i]);
|
||
}
|
||
}
|
||
}
|
||
this.dependencies = dependencies;
|
||
return this;
|
||
};
|
||
|
||
ControlGrid.prototype.addColumn = function (column) {
|
||
var newColumn;
|
||
|
||
if (typeof column === 'object') {
|
||
column.grid = this;
|
||
newColumn = this.columnsFactory.make(column);
|
||
} else {
|
||
throw new Error('addColumn(): invalid column to add');
|
||
}
|
||
|
||
if (newColumn) {
|
||
this.columns.insert(newColumn);
|
||
if (this.dom.thead) {
|
||
this.dom.thead.appendChild(newColumn.getHTML());
|
||
}
|
||
}
|
||
this.updateDependencies();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Disables one or all the columns.
|
||
* @param {String|Number|PMUI.grid.GridPanelColumn} [column] A criteria to select the column that will be
|
||
* disabled. It supports the following data types:
|
||
*
|
||
* - String, in this case the parameter is used as the column's id.
|
||
* - Number, in this case the parameter is used as the column's index.
|
||
* - An instance of {@link PMUI.grid.GridPanelColumn GridPanelColumn}, in this case the supplied object must be
|
||
* a child of the grid.
|
||
* - [no value], since this parameter is optional, you can skip it. In this case all the columns in the grid will
|
||
* be disabled.
|
||
* @chainable
|
||
*/
|
||
ControlGrid.prototype.disableColumn = function (column) {
|
||
var i,
|
||
targetColumn = this.getColumns(column);
|
||
|
||
for (i = 0; i < targetColumn.length; i += 1) {
|
||
targetColumn[i].disable();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* [disableColumn description]
|
||
* @param {[type]} column [description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
ControlGrid.prototype.enableColumn = function (column) {
|
||
var i,
|
||
targetColumn = this.getColumns(column);
|
||
|
||
for (i = 0; i < targetColumn.length; i += 1) {
|
||
targetColumn[i].enable();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ControlGrid.prototype.isValid = function () {
|
||
var i,
|
||
rows,
|
||
valid = true;
|
||
|
||
rows = this.getItems();
|
||
for (i = 0; i < rows.length; i += 1) {
|
||
valid = valid && rows[i].isValid();
|
||
if (!valid) {
|
||
return valid;
|
||
}
|
||
}
|
||
return valid;
|
||
};
|
||
|
||
ControlGrid.prototype.fireDependency = function () {
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.grid.ControlGrid', ControlGrid);
|
||
}());
|
||
(function () {
|
||
var GridControlCell = function (settings) {
|
||
this.controls = [];
|
||
GridControlCell.superclass.call(this, settings);
|
||
/**
|
||
* @property {Boolean} [validAtChange=true]
|
||
* If the validation must be executed every time the field's value changes.
|
||
*/
|
||
this.validAtChange = null;
|
||
this.value = null;
|
||
this.onChange = null;
|
||
this.validAtChange = null;
|
||
this.disable = null;
|
||
GridControlCell.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.grid.GridPanelCell', GridControlCell);
|
||
|
||
GridControlCell.prototype.init = function (settings) {
|
||
var defaults = {
|
||
onChange: null,
|
||
validAtChange: true,
|
||
disabled: false,
|
||
value: ""
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
this.initControls();
|
||
|
||
this.setOnChangeHandler(defaults.onChange)
|
||
.setValidAtChange(defaults.validAtChange)
|
||
.setValue(defaults.value);
|
||
|
||
if (defaults.disabled) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
};
|
||
/**
|
||
* [setValueToControls description]
|
||
* @param {[type]} value [description]
|
||
*/
|
||
GridControlCell.prototype.setValueToControls = function (value) {
|
||
var i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
this.controls[i].setValue(value);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* [setValue description]
|
||
* @param {[type]} value [description]
|
||
*/
|
||
GridControlCell.prototype.setValue = function (value) {
|
||
if (typeof value === 'number') {
|
||
value = value.toString();
|
||
}
|
||
if (typeof value === 'string') {
|
||
this.value = value;
|
||
} else {
|
||
throw new Error("The setValue() method only accepts string values!");
|
||
}
|
||
this.setValueToControls(value);
|
||
return this;
|
||
};
|
||
/**
|
||
* Turns on/off the validation when the field's value changes.
|
||
* @param {Boolean} validAtChange
|
||
* @chainable
|
||
*/
|
||
GridControlCell.prototype.setValidAtChange = function (validAtChange) {
|
||
this.validAtChange = !!validAtChange;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback function to be called when the field's value changes.
|
||
* @param {Function} handler
|
||
* @chainable
|
||
*/
|
||
GridControlCell.prototype.setOnChangeHandler = function (handler) {
|
||
if (typeof handler === 'function' || handler === null) {
|
||
this.onChange = handler;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
GridControlCell.prototype.initControls = function () {
|
||
return this;
|
||
};
|
||
|
||
GridControlCell.prototype.setValuesToControls = function (values) {
|
||
return this;
|
||
};
|
||
|
||
GridControlCell.prototype.setContent = function (content) {
|
||
return this.setValuesToControls(content);
|
||
};
|
||
|
||
/**
|
||
* Update the field's value property from the controls
|
||
* @protected
|
||
* @chainable
|
||
*/
|
||
GridControlCell.prototype.updateContentFromControls = function () {
|
||
var value = '',
|
||
i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
value += ' ' + this.controls[i].getValue();
|
||
}
|
||
|
||
this.value = this.content = value.substr(1);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* The onChange event handler constructor.
|
||
* @private
|
||
* @return {Function} The handler.
|
||
*/
|
||
GridControlCell.prototype.onChangeHandler = function () {
|
||
var that = this;
|
||
|
||
return function () {
|
||
var previousValue = that.content;
|
||
that.updateContentFromControls();
|
||
if (that.validAtChange) {
|
||
that.isValid();
|
||
}
|
||
|
||
if (typeof that.onChange === 'function') {
|
||
that.onChange(that.getContent(), previousValue);
|
||
}
|
||
|
||
if (that.column) {
|
||
that.column.onChangeHandler(that, that.content, previousValue);
|
||
}
|
||
};
|
||
};
|
||
GridControlCell.prototype.hideMessage = function () {
|
||
this.style.removeClasses(['pmui-error']);
|
||
this.html.removeAttribute("title");
|
||
try {
|
||
jQuery(this.html).tooltip("destroy");
|
||
} catch (e) {
|
||
}
|
||
return this;
|
||
};
|
||
GridControlCell.prototype.showMessage = function (message) {
|
||
this.style.addClasses(['pmui-error']);
|
||
this.html.setAttribute("title", "error");
|
||
jQuery(this.html).tooltip({
|
||
content: message,
|
||
tooltipClass: 'pmui-cell-tooltip-error',
|
||
position: {
|
||
my: "left",
|
||
at: "left bottom"
|
||
}
|
||
});
|
||
jQuery(this.html).tooltip('open');
|
||
return this;
|
||
};
|
||
/**
|
||
* [evalRequired description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
GridControlCell.prototype.evalRequired = function () {
|
||
var valid = true, column = this.column;
|
||
if (column) {
|
||
if (column.required && this.value === "") {
|
||
valid = false;
|
||
}
|
||
}
|
||
if (valid) {
|
||
this.hideMessage();
|
||
} else {
|
||
this.showMessage(column.requiredMessage);
|
||
}
|
||
return valid;
|
||
};
|
||
/**
|
||
* [isValid description]
|
||
* @return {Boolean} [description]
|
||
*/
|
||
GridControlCell.prototype.isValid = function () {
|
||
var valid = true,
|
||
validator,
|
||
validators;
|
||
|
||
valid = valid && this.evalRequired();
|
||
if (!valid) {
|
||
return valid;
|
||
}
|
||
if (this.column) {
|
||
validators = this.column.validators;
|
||
for (validator in validators) {
|
||
if (validators.hasOwnProperty(validator)) {
|
||
validators[validator].setParent(this);
|
||
valid = validators[validator].isValid();
|
||
if (!valid) {
|
||
return valid;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return valid;
|
||
};
|
||
/**
|
||
* Attach the event listeners to the HTML element
|
||
* @private
|
||
* @chainable
|
||
*/
|
||
GridControlCell.prototype.defineEvents = function () {
|
||
var i;
|
||
|
||
if (this.eventsDefined) {
|
||
return this;
|
||
}
|
||
;
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
this.controls[i].setOnChangeHandler(this.onChangeHandler())
|
||
.defineEvents();
|
||
}
|
||
this.eventsDefined = true;
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
GridControlCell.prototype.enable = function () {
|
||
var i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
this.controls[i].disable(false);
|
||
}
|
||
this.disabled = false;
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
GridControlCell.prototype.disable = function () {
|
||
var i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
this.controls[i].disable(true);
|
||
}
|
||
this.disabled = true;
|
||
return this;
|
||
};
|
||
/**
|
||
* [createHTML description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
GridControlCell.prototype.createHTML = function () {
|
||
var i;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
GridControlCell.superclass.prototype.createHTML.call(this);
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
this.contentSpan.appendChild(this.controls[i].getHTML());
|
||
}
|
||
|
||
this.defineEvents();
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.grid.GridControlCell', GridControlCell);
|
||
}());
|
||
(function () {
|
||
var NumberCell = function (settings) {
|
||
NumberCell.superclass.call(this, settings);
|
||
|
||
NumberCell.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.grid.GridControlCell', NumberCell);
|
||
|
||
NumberCell.prototype.init = function (settings) {
|
||
var defaults = {
|
||
placeholder: "",
|
||
maxLength: 524288,
|
||
mask: ["###,###.###"],
|
||
onKeyUp: null,
|
||
content: ''
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
this.setPlaceholder(defaults.placeholder)
|
||
.setMaxLength(defaults.maxLength)
|
||
.setOnKeyUpHandler(defaults.onKeyUp)
|
||
.setContent(defaults.content)
|
||
.setMask(defaults.mask);
|
||
};
|
||
|
||
NumberCell.prototype.setOnKeyUpHandler = function (handler) {
|
||
this.controls[0].setOnKeyUpHandler(handler);
|
||
return this;
|
||
};
|
||
|
||
NumberCell.prototype.setPlaceholder = function (placeholder) {
|
||
this.controls[0].setPlaceholder(placeholder);
|
||
return this;
|
||
};
|
||
|
||
NumberCell.prototype.setMask = function (mask) {
|
||
this.controls[0].setMask(mask);
|
||
return this;
|
||
};
|
||
|
||
NumberCell.prototype.setMaxLength = function (maxLength) {
|
||
this.controls[0].setMaxLength(maxLength);
|
||
return this;
|
||
};
|
||
|
||
NumberCell.prototype.setReadOnly = function (value) {
|
||
this.controls[0].setReadOnly(value);
|
||
return this;
|
||
};
|
||
|
||
NumberCell.prototype.initControls = function () {
|
||
this.controls[0] = new PMUI.control.NumberControl();
|
||
return this;
|
||
};
|
||
|
||
NumberCell.prototype.setContent = function (content) {
|
||
return this.setValuesToControls(content);
|
||
};
|
||
|
||
NumberCell.prototype.setValuesToControls = function (values) {
|
||
if (this.controls.length) {
|
||
this.controls[0].setValue(values);
|
||
this.content = this.controls[0].getValue();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
NumberCell.prototype.getPlaceholder = function () {
|
||
return this.controls[0].getPlaceholder();
|
||
};
|
||
/**
|
||
* [isReadOnly description]
|
||
* @return {Boolean} [description]
|
||
*/
|
||
NumberCell.prototype.isReadOnly = function () {
|
||
return this.controls[0].isReadOnly();
|
||
};
|
||
/**
|
||
* Switches on/off the value trimming for the field's value when it loses focus.
|
||
* @param {Boolean} trimOnBlur Send true for switch on or false to switch off.
|
||
* @chainable
|
||
*/
|
||
PMUI.extendNamespace('PMUI.grid.NumberCell', NumberCell);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = NumberCell;
|
||
}
|
||
}());
|
||
(function () {
|
||
var GridTextControlCell = function (settings) {
|
||
GridTextControlCell.superclass.call(this, settings);
|
||
GridTextControlCell.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.grid.GridControlCell', GridTextControlCell);
|
||
|
||
GridTextControlCell.prototype.init = function (settings) {
|
||
var defaults = {
|
||
placeholder: "",
|
||
maxLength: 0,
|
||
trimOnBlur: true,
|
||
readOnly: false
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setPlaceholder(defaults.placeholder)
|
||
.setMaxLength(defaults.maxLength)
|
||
.setTrimOnBlur(defaults.trimOnBlur)
|
||
.setReadOnly(defaults.readOnly);
|
||
};
|
||
|
||
GridTextControlCell.prototype.initControls = function () {
|
||
this.controls[0] = new PMUI.control.TextControl();
|
||
return this;
|
||
};
|
||
|
||
GridTextControlCell.prototype.setValuesToControls = function (values) {
|
||
return this;
|
||
};
|
||
|
||
GridTextControlCell.prototype.setContent = function (content) {
|
||
return this.setValuesToControls(content);
|
||
};
|
||
/**
|
||
* Sets the placeholder for the control. Note that this feature is only supported
|
||
* by browsers which support the "placeholder" for input elements.
|
||
* @param {String} placeholder
|
||
* @chainable
|
||
*/
|
||
GridTextControlCell.prototype.setReadOnly = function (readonly) {
|
||
this.controls[0].setReadOnly(readonly);
|
||
return this;
|
||
};
|
||
/**
|
||
* [setPlaceholder description]
|
||
* @param {[type]} placeholder [description]
|
||
*/
|
||
GridTextControlCell.prototype.setPlaceholder = function (placeholder) {
|
||
this.controls[0].setPlaceholder(placeholder);
|
||
return this;
|
||
};
|
||
/**
|
||
* [getPlaceholder description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
GridTextControlCell.prototype.getPlaceholder = function () {
|
||
return this.controls[0].getPlaceholder();
|
||
};
|
||
/**
|
||
* [setMaxLength description]
|
||
* @param {[type]} maxLength [description]
|
||
*/
|
||
GridTextControlCell.prototype.setMaxLength = function (maxLength) {
|
||
this.controls[0].setMaxLength(maxLength);
|
||
return this;
|
||
};
|
||
/**
|
||
* [getMaxLength description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
GridTextControlCell.prototype.getMaxLength = function () {
|
||
return this.controls[0].getMaxLength();
|
||
};
|
||
/**
|
||
* [isReadOnly description]
|
||
* @return {Boolean} [description]
|
||
*/
|
||
GridTextControlCell.prototype.isReadOnly = function () {
|
||
return this.controls[0].isReadOnly();
|
||
};
|
||
/**
|
||
* Switches on/off the value trimming for the field's value when it loses focus.
|
||
* @param {Boolean} trimOnBlur Send true for switch on or false to switch off.
|
||
* @chainable
|
||
*/
|
||
GridTextControlCell.prototype.setTrimOnBlur = function (trimOnBlur) {
|
||
this.trimOnBlur = !!trimOnBlur;
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.grid.GridTextControlCell', GridTextControlCell);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = GridTextControlCell;
|
||
}
|
||
}());
|
||
(function () {
|
||
var DropDownListControlCell = function (settings) {
|
||
DropDownListControlCell.superclass.call(this, settings);
|
||
DropDownListControlCell.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.grid.GridControlCell', DropDownListControlCell);
|
||
|
||
DropDownListControlCell.prototype.init = function (settings) {
|
||
var defaults = {
|
||
options: [],
|
||
value: null
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setOptions(defaults.options);
|
||
|
||
if (defaults.value !== null) {
|
||
this.setValue(defaults.value);
|
||
}
|
||
};
|
||
|
||
DropDownListControlCell.prototype.initControls = function () {
|
||
this.controls[0] = new PMUI.control.DropDownListControl();
|
||
return this;
|
||
};
|
||
|
||
DropDownListControlCell.prototype.clearOptions = function () {
|
||
this.controls[0].clearOptions();
|
||
this.content = this.controls[0].getValue();
|
||
return this;
|
||
};
|
||
|
||
DropDownListControlCell.prototype.enableDisableOption = function (disabled, option, group) {
|
||
this.controls[0].enableDisableOption(disabled, option, group);
|
||
return this;
|
||
};
|
||
|
||
DropDownListControlCell.prototype.disableOption = function (option, group) {
|
||
return this.controls[0].enableDisableOption(true, option, group);
|
||
};
|
||
|
||
DropDownListControlCell.prototype.enableOption = function (option, group) {
|
||
return this.controls[0].enableDisableOption(false, option, group);
|
||
};
|
||
|
||
DropDownListControlCell.prototype.removeOption = function (option, group) {
|
||
this.controls[0].removeOption(option, group);
|
||
return this;
|
||
};
|
||
|
||
DropDownListControlCell.prototype.addOptionGroup = function (optionGroup) {
|
||
this.controls[0].addOptionGroup(optiongroup);
|
||
return this;
|
||
};
|
||
|
||
DropDownListControlCell.prototype.addOption = function (option, group) {
|
||
this.controls[0].addOption(option, group);
|
||
return this;
|
||
};
|
||
|
||
DropDownListControlCell.prototype.getSelectedLabel = function () {
|
||
return this.controls[0].getSelectedLabel();
|
||
};
|
||
|
||
DropDownListControlCell.prototype.valueExistsInOptions = function (value) {
|
||
return this.controls[0].valueExistsInOptions(value);
|
||
};
|
||
|
||
DropDownListControlCell.prototype.getFirstAvailableOption = function () {
|
||
return this.controls[0].getFirstAvailableOption();
|
||
}
|
||
|
||
DropDownListControlCell.prototype.setOptions = function (options) {
|
||
this.controls[0].setOptions(options);
|
||
return this;
|
||
};
|
||
|
||
DropDownListControlCell.prototype.getOptions = function (includeGroups) {
|
||
return this.controls[0].getOptions(includeGroups);
|
||
};
|
||
|
||
DropDownListControlCell.prototype.setValuesToControls = function (values) {
|
||
if (this.controls.length) {
|
||
this.controls[0].setValue(values);
|
||
this.content = this.controls[0].getValue();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
DropDownListControlCell.prototype.getContent = function () {
|
||
return this.controls[0].getValue();
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.grid.DropDownListControlCell', DropDownListControlCell);
|
||
}());
|
||
(function () {
|
||
var CheckBoxGroupControlCell = function (settings) {
|
||
CheckBoxGroupControlCell.superclass.call(this, settings);
|
||
/**
|
||
* @property {String} controlPositioning The direction for the options to be added in the field.
|
||
* @readonly
|
||
*/
|
||
this.controlPositioning = null;
|
||
/**
|
||
* @property {Number} maxDirectionOptions The max number of options that can be in the current options
|
||
* direction.
|
||
* @readonly
|
||
*/
|
||
this.maxDirectionOptions = null;
|
||
/**
|
||
* The status if the controls to be saved when the field is switch between enabled/disabled.
|
||
* @type {Object}
|
||
* @private
|
||
*/
|
||
this.auxControlStates = {};
|
||
CheckBoxGroupControlCell.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.grid.GridControlCell', CheckBoxGroupControlCell);
|
||
|
||
CheckBoxGroupControlCell.prototype.init = function (settings) {
|
||
var defaults = {
|
||
options: [],
|
||
controlPositioning: "vertical",
|
||
maxDirectionOptions: 1,
|
||
value: '[]'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
this.setOptions(defaults.options);
|
||
this.setMaxDirectionOptions(defaults.maxDirectionOptions);
|
||
this.setControlPositioning(defaults.controlPositioning);
|
||
};
|
||
|
||
|
||
CheckBoxGroupControlCell.prototype.enable = function () {
|
||
var key,
|
||
i,
|
||
controlsLength = this.controls.length,
|
||
controls = this.controls;
|
||
|
||
CheckBoxGroupControlCell.superclass.prototype.enable.call(this);
|
||
this.disabled = false;
|
||
for (i = 0; i < controlsLength; i += 1) {
|
||
controls[i].disable(this.auxControlStates[controls[i].id]);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupControlCell.prototype.setMaxDirectionOptions = function (max) {
|
||
if (typeof max === 'number') {
|
||
this.maxDirectionOptions = Math.floor(max);
|
||
if (this.html) {
|
||
this.setControlPositioning(this.controlPositioning);
|
||
}
|
||
} else {
|
||
throw new Error("setMaxDirectionOptions(): it only accepts number values.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupControlCell.prototype.setControlPositioning = function (positioning) {
|
||
var errorMessage = "The setControlPositioning() method only accepts \"horizontal\" or \"vertical\" as value.",
|
||
table,
|
||
tbody,
|
||
cell,
|
||
row,
|
||
i,
|
||
column,
|
||
rowIndex;
|
||
|
||
if (typeof positioning === 'string') {
|
||
if (!(positioning === 'horizontal' || positioning === 'vertical')) {
|
||
return this;
|
||
}
|
||
this.controlPositioning = positioning;
|
||
if (this.html && this.controls) {
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
jQuery(this.controls[i].getHTML()).detach();
|
||
}
|
||
$(this.contentSpan).empty();
|
||
table = PMUI.createHTMLElement("table");
|
||
table.className = 'pmui-field-control-table';
|
||
tbody = PMUI.createHTMLElement("tbody");
|
||
if (positioning === 'horizontal') {
|
||
row = PMUI.createHTMLElement("tr");
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
cell = PMUI.createHTMLElement('td');
|
||
this.controls[i].getHTML();
|
||
this.controls[i].control.tabIndex = i;
|
||
cell.appendChild(this.controls[i].getHTML());
|
||
row.appendChild(cell);
|
||
if (this.maxDirectionOptions > 0 && (i + 1) % this.maxDirectionOptions === 0) {
|
||
tbody.appendChild(row);
|
||
row = PMUI.createHTMLElement("tr");
|
||
}
|
||
}
|
||
cell.style.textAlign = "start";
|
||
tbody.appendChild(row);
|
||
} else {
|
||
column = 0;
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
cell = PMUI.createHTMLElement('td');
|
||
this.controls[i].getHTML();
|
||
this.controls[i].control.tabIndex = i;
|
||
cell.appendChild(this.controls[i].getHTML());
|
||
rowIndex = this.maxDirectionOptions === 0 ? i : i % this.maxDirectionOptions;
|
||
|
||
row = jQuery(tbody).find('tr').eq(rowIndex).get(0);
|
||
if (!row) {
|
||
row = PMUI.createHTMLElement('tr');
|
||
tbody.appendChild(row);
|
||
}
|
||
cell.style.textAlign = "start";
|
||
row.appendChild(cell);
|
||
}
|
||
}
|
||
table.appendChild(tbody);
|
||
this.contentSpan.appendChild(table);
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupControlCell.prototype.setOptions = function (options) {
|
||
var i = 0;
|
||
|
||
this.content = [];
|
||
this.content = JSON.stringify(this.content);
|
||
|
||
if (jQuery.isArray(options)) {
|
||
for (i = 0; i < options.length; i += 1) {
|
||
this.addOption(options[i]);
|
||
}
|
||
} else {
|
||
throw new Error("setOptions(): the supplied argument must be an array.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupControlCell.prototype.addOption = function (option) {
|
||
var newOption;
|
||
|
||
newOption = new PMUI.control.SelectableControl(jQuery.extend(true, option, {
|
||
mode: 'checkbox',
|
||
name: this.controls.length + 1,
|
||
selected: option.selected
|
||
}));
|
||
|
||
if (newOption.isSelected()) {
|
||
this.content = JSON.parse(this.content);
|
||
this.content.push(newOption.getValue());
|
||
this.content = JSON.stringify(this.content);
|
||
}
|
||
if (this.eventsDefined) {
|
||
newOption.setOnChangeHandler(this.onChangeHandler()).getHTML();
|
||
newOption.defineEvents();
|
||
}
|
||
this.auxControlStates[newOption.id] = newOption.disabled;
|
||
this.controls.push(newOption);
|
||
this.setControlPositioning(this.controlPositioning);
|
||
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupControlCell.prototype.removeOption = function (item) {
|
||
var itemToRemove,
|
||
i;
|
||
|
||
if (item instanceof PMUI.control.SelectableControl) {
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i] === item) {
|
||
itemToRemove = i;
|
||
break;
|
||
}
|
||
}
|
||
} else if (typeof item === 'string') {
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].id === item) {
|
||
itemToRemove = this.controls[i];
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
itemToRemove = item;
|
||
}
|
||
if (typeof itemToRemove === 'number') {
|
||
itemToRemove = this.controls[itemToRemove];
|
||
delete this.auxControlStates[itemToRemove.id];
|
||
jQuery(itemToRemove.html).detach();
|
||
this.controls.splice(itemToRemove, 1);
|
||
this.setControlPositioning(this.controlPositioning);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupControlCell.prototype.clearOptions = function () {
|
||
while (this.controls.length) {
|
||
this.removeOption(0);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupControlCell.prototype.updateContentFromControls = function () {
|
||
var value = [],
|
||
i;
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].isSelected()) {
|
||
value.push(this.controls[i].getValue());
|
||
}
|
||
}
|
||
|
||
this.content = JSON.stringify(value);
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupControlCell.prototype.evalRequired = function () {
|
||
var valid = true,
|
||
value;
|
||
|
||
value = JSON.parse(this.getContent());
|
||
if (this.required && value.length === 0) {
|
||
this.showMessage(this.requiredMessage, "error");
|
||
valid = false;
|
||
} else {
|
||
this.hideMessage();
|
||
}
|
||
|
||
return valid;
|
||
};
|
||
|
||
|
||
CheckBoxGroupControlCell.prototype.disableOption = function (value) {
|
||
|
||
var index = -1,
|
||
i;
|
||
|
||
if (this.html) {
|
||
if (typeof value === 'string') {
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].label === value) {
|
||
index = i;
|
||
}
|
||
}
|
||
} else {
|
||
index = value;
|
||
}
|
||
if (index === -1) {
|
||
throw new Error('the value send is not part of group CheckBox');
|
||
} else {
|
||
this.controls[index].disable(true);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupControlCell.prototype.enableOption = function (value) {
|
||
var index = -1,
|
||
i;
|
||
|
||
if (this.html) {
|
||
if (typeof value === 'string') {
|
||
|
||
for (i = 0; i < this.controls.length; i += 1) {
|
||
if (this.controls[i].label === value) {
|
||
index = i;
|
||
}
|
||
}
|
||
} else {
|
||
index = value;
|
||
}
|
||
if (index === -1) {
|
||
throw new Error('the value send is not part from group CheckBox');
|
||
} else {
|
||
|
||
this.controls[index].disable(false);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupControlCell.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
CheckBoxGroupControlCell.superclass.prototype.createHTML.call(this)
|
||
|
||
this.setControlPositioning(this.controlPositioning);
|
||
|
||
return this.html;
|
||
};
|
||
|
||
CheckBoxGroupControlCell.prototype.setValuesToControls = function (value) {
|
||
var i,
|
||
j,
|
||
values,
|
||
controls,
|
||
controlsLength;
|
||
|
||
if (value) {
|
||
try {
|
||
values = JSON.parse(value);
|
||
} catch (e) {
|
||
values = '[]';
|
||
}
|
||
|
||
controlsLength = (controls = this.controls.slice(0)).length;
|
||
for (i = 0; i < controlsLength; i += 1) {
|
||
controls[i].deselect();
|
||
}
|
||
for (i = 0; i < values.length; i += 1) {
|
||
for (j = 0; j < controlsLength; j += 1) {
|
||
if (controls[j].getValue() === values[i]) {
|
||
controls[j].select();
|
||
controls.splice(j, 1);
|
||
controlsLength -= 1;
|
||
j -= 1;
|
||
}
|
||
}
|
||
}
|
||
this.updateContentFromControls();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.grid.CheckBoxGroupControlCell', CheckBoxGroupControlCell);
|
||
}());
|
||
(function () {
|
||
var GridControlColumn = function (settings) {
|
||
this.cells = new PMUI.util.ArrayList();
|
||
GridControlColumn.superclass.call(this, jQuery.extend(settings, {elementTag: "th"}));
|
||
/**
|
||
* The name for the column.
|
||
* @type {String}
|
||
*/
|
||
this.name = null;
|
||
/**
|
||
* The text to be shown in the column header.
|
||
* @type {String}
|
||
*/
|
||
this.title = null;
|
||
/**
|
||
* The grid the column belongs to.
|
||
* @type {PMUI.grid.GridPanel}
|
||
*/
|
||
this.grid = null;
|
||
/**
|
||
* The HTML element in which the cell content will be appended.
|
||
* @type {HTMLElement}
|
||
* @private
|
||
*/
|
||
this.contentTitle = null;
|
||
/**
|
||
* [dependentCols description]
|
||
* @type {Array}
|
||
*/
|
||
this.dependentCols = [];
|
||
/**
|
||
* [onChange description]
|
||
* @type {[type]}
|
||
*/
|
||
this.onChange = null;
|
||
/**
|
||
* [dependencyHandler description]
|
||
* @type {[type]}
|
||
*/
|
||
this.dependencyHandler = null;
|
||
/**
|
||
* [disabled description]
|
||
* @type {[type]}
|
||
*/
|
||
this.disabled = null;
|
||
/**
|
||
* [validatorFactory description]
|
||
* @type {[type]}
|
||
*/
|
||
this.validatorFactory = null;
|
||
/**
|
||
* [validators description]
|
||
* @type {Object}
|
||
*/
|
||
this.validators = {};
|
||
/**
|
||
* [required description]
|
||
* @type {[type]}
|
||
*/
|
||
this.required = null;
|
||
/**
|
||
* [requiredMessage description]
|
||
* @type {[type]}
|
||
*/
|
||
this.requiredMessage = null;
|
||
GridControlColumn.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', GridControlColumn);
|
||
|
||
GridControlColumn.prototype.CELL = null;
|
||
|
||
GridControlColumn.prototype.init = function (settings) {
|
||
var defaults = {
|
||
name: this.id,
|
||
title: '[untitled]',
|
||
grid: null,
|
||
cells: [],
|
||
dependentCols: [],
|
||
onChange: null,
|
||
dependencyHandler: null,
|
||
disabled: false,
|
||
validators: [],
|
||
required: false,
|
||
requiredMessage: 'This cell is required.',
|
||
validatorFactory: new PMUI.form.ValidatorFactory()
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setName(defaults.name)
|
||
.setTitle(defaults.title)
|
||
.setGrid(defaults.grid)
|
||
.setRequired(defaults.required)
|
||
.setDependentCols(defaults.dependentCols)
|
||
.setOnChangeHandler(defaults.onChange)
|
||
.setDependencyHandler(defaults.dependencyHandler)
|
||
.setValidatorFactory(defaults.validatorFactory)
|
||
.setValidators(defaults.validators)
|
||
.setRequiredMessage(defaults.requiredMessage);
|
||
|
||
if (defaults.disabled) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
};
|
||
|
||
GridControlColumn.prototype.setRequiredMessage = function (requiredMessage) {
|
||
if (typeof requiredMessage !== 'string') {
|
||
throw new Error('setRequiredMessage(): The parameter must be a strng.');
|
||
}
|
||
this.requiredMessage = requiredMessage;
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.setRequired = function (required) {
|
||
this.required = !!required;
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.setValidatorFactory = function (factory) {
|
||
if (factory instanceof PMUI.util.Factory) {
|
||
this.validatorFactory = factory;
|
||
} else {
|
||
this.validatorFactory = new PMUI.form.ValidatorFactory(factory);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.addValidator = function (validator) {
|
||
var newValidator;
|
||
if (this.validatorFactory) {
|
||
if (this.validatorFactory.isValidClass(validator) || this.validatorFactory.isValidName(validator.pmType)) {
|
||
newValidator = this.validatorFactory.make(validator);
|
||
} else {
|
||
throw new Error('Invalid validator to add.');
|
||
}
|
||
}
|
||
|
||
if (newValidator && newValidator instanceof PMUI.form.Validator) {
|
||
this.validators[newValidator.type] = newValidator;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.clearValidators = function () {
|
||
var key;
|
||
|
||
for (key in this.validators) {
|
||
if (this.validators.hasOwnProperty(key)) {
|
||
this.validators[key] = null;
|
||
delete this.validators[key];
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.setValidators = function (validators) {
|
||
var i = 0;
|
||
|
||
if (jQuery.isArray(validators)) {
|
||
this.clearValidators();
|
||
for (i = 0; i < validators.length; i += 1) {
|
||
this.addValidator(validators[i]);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.getCells = function () {
|
||
return this.cells.asArray().slice(0);
|
||
};
|
||
|
||
GridControlColumn.prototype.setName = function (name) {
|
||
if (typeof name !== 'string') {
|
||
throw new Error("setName(): The parameter must be a string.");
|
||
}
|
||
this.name = name;
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.setDependencyHandler = function (handler) {
|
||
if (!(typeof handler === 'function' || handler === null)) {
|
||
throw new Error("setDependencyHandler(): The parameter must be a function or null.");
|
||
}
|
||
this.dependencyHandler = handler;
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.onChangeHandler = function (cell, newValue, oldValue) {
|
||
var i,
|
||
dependentCols = this.dependentCols,
|
||
grid = this.grid,
|
||
dependentCell,
|
||
col,
|
||
row;
|
||
|
||
cell.row.updateData(cell);
|
||
if (typeof this.onChange === 'function') {
|
||
this.onChange(cell, newValue, oldValue);
|
||
}
|
||
if (grid) {
|
||
for (i = 0; i < dependentCols.length; i += 1) {
|
||
col = grid.getColumn(dependentCols[i]);
|
||
if (!col) {
|
||
this.removeDependentCol(dependentCols[i]);
|
||
continue;
|
||
}
|
||
dependentCell = cell.row.getCell(col);
|
||
col.fireDependencyHandler(dependentCell);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.fireDependencyHandler = function (cell) {
|
||
var grid = this.grid,
|
||
dependsOf,
|
||
obj = {},
|
||
i,
|
||
targetRow,
|
||
targetCells,
|
||
j;
|
||
|
||
if (grid) {
|
||
targetCells = cell ? [cell] : this.cells.asArray();
|
||
for (j = 0; j < targetCells.length; j += 1) {
|
||
cell = targetCells[j];
|
||
targetRow = cell.row;
|
||
dependsOf = grid.dependencies[this.name];
|
||
for (i = 0; i < dependsOf.length; i += 1) {
|
||
obj[dependsOf[i].name] = targetRow.getCell(dependsOf[i]);
|
||
}
|
||
if (typeof this.dependencyHandler === 'function') {
|
||
this.dependencyHandler.call(cell, cell, obj);
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.enable = function () {
|
||
var i,
|
||
cells = this.getCells();
|
||
|
||
for (i = 0; i < cells.length; i += 1) {
|
||
cells[i].enable();
|
||
}
|
||
this.disabled = false;
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.disable = function () {
|
||
var i,
|
||
cells = this.getCells();
|
||
|
||
for (i = 0; i < cells.length; i += 1) {
|
||
cells[i].disable();
|
||
}
|
||
this.disabled = true;
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.setOnChangeHandler = function (handler) {
|
||
if (!(typeof handler === 'function' || handler === null)) {
|
||
throw new Error("setOnChangeHandler(): the parameter must be a function or null.");
|
||
}
|
||
this.onChange = handler;
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.setDependentCols = function (dependentCols) {
|
||
if (!jQuery.isArray(dependentCols)) {
|
||
throw new Error("setDependentCols(): The parameter must be an array.");
|
||
}
|
||
this.dependentCols = dependentCols;
|
||
if (this.grid) {
|
||
this.grid.updateDependencies();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.removeDependentCol = function (columnName) {
|
||
var i;
|
||
|
||
for (i = 0; this.dependentCols.length; i += 1) {
|
||
if (this.dependentCols[i] === columnName) {
|
||
this.dependentCols.splice(i, 1);
|
||
i--;
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.removeCell = function (cell) {
|
||
var cellToRemove;
|
||
|
||
if (cell instanceof PMUI.grid.GridControlCell) {
|
||
cellToRemove = cell;
|
||
} else if (typeof cell === 'number') {
|
||
cellToRemove = this.cells.get(cell);
|
||
} else if (typeof cell === 'string') {
|
||
cellToRemove = this.cells.find("id", cell);
|
||
}
|
||
|
||
if (cellToRemove) {
|
||
cellToRemove.column = null;
|
||
this.cells.remove(cellToRemove);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.clearCells = function () {
|
||
this.cells.clear();
|
||
while (this.cells.getSize() > 0) {
|
||
this.removeCell(0);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.addCell = function (cell) {
|
||
if (!(cell instanceof PMUI.grid.GridControlCell)) {
|
||
throw new Error("addCell(): The parameter must be an instance of PMUI.grid.GridControlCell.");
|
||
}
|
||
this.cells.insert(cell);
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.setTitle = function (title) {
|
||
this.title = title;
|
||
if (this.html) {
|
||
jQuery(this.contentTitle).empty();
|
||
this.contentTitle.appendChild(document.createTextNode(title));
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.setGrid = function (grid) {
|
||
if (!(grid instanceof PMUI.grid.ControlGrid)) {
|
||
throw new Error('setGrid(): the grid property should be instance of [PMUI.grid.GridControl]');
|
||
}
|
||
this.grid = grid;
|
||
this.grid.updateDependencies();
|
||
return this;
|
||
};
|
||
|
||
GridControlColumn.prototype.getCellDefaultCfg = function () {
|
||
return {
|
||
disabled: this.disabled
|
||
};
|
||
};
|
||
|
||
GridControlColumn.prototype.createCell = function () {
|
||
var cell;
|
||
|
||
if (!this.CELL instanceof PMUI.grid.GridControlCell) {
|
||
throw new Error("The cell associated to the " + this.type + " is not valid!");
|
||
}
|
||
cell = new this.CELL(this.getCellDefaultCfg());
|
||
this.addCell(cell);
|
||
|
||
return cell;
|
||
};
|
||
|
||
GridControlColumn.prototype.createHTML = function () {
|
||
var contentTitle,
|
||
sortIcon;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
GridControlColumn.superclass.prototype.createHTML.call(this);
|
||
contentTitle = PMUI.createHTMLElement('span');
|
||
contentTitle.className = 'pmui-gridpanelColumn-title';
|
||
this.contentTitle = contentTitle;
|
||
this.html.appendChild(contentTitle);
|
||
this.setTitle(this.title);
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.grid.GridControlColumn', GridControlColumn);
|
||
}());
|
||
(function () {
|
||
var NumberColumn = function (settings) {
|
||
NumberColumn.superclass.call(this, settings);
|
||
this.placeholder = null;
|
||
this.maxLength = null;
|
||
this.mask = null;
|
||
NumberColumn.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.grid.GridControlColumn', NumberColumn);
|
||
|
||
NumberColumn.prototype.CELL = PMUI.grid.NumberCell;
|
||
|
||
NumberColumn.prototype.init = function (settings) {
|
||
var defaults = {
|
||
placeholder: "",
|
||
maxLength: 524288,
|
||
mask: "##############.###############",
|
||
content: '',
|
||
readOnly: false
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setMaxLength(defaults.maxLength)
|
||
.setPlaceHolder(defaults.placeholder)
|
||
.setReadOnly(defaults.readOnly)
|
||
.setMask(defaults.mask);
|
||
};
|
||
|
||
NumberColumn.prototype.setMaxLength = function (input) {
|
||
this.maxLength = input
|
||
return this;
|
||
};
|
||
|
||
NumberColumn.prototype.setPlaceHolder = function (input) {
|
||
this.placeholder = input;
|
||
return this;
|
||
};
|
||
|
||
NumberColumn.prototype.setReadOnly = function (input) {
|
||
this.readOnly = input;
|
||
return this;
|
||
};
|
||
|
||
NumberColumn.prototype.setMask = function (mask) {
|
||
this.mask = mask;
|
||
return this;
|
||
};
|
||
|
||
NumberColumn.prototype.getCellDefaultCfg = function () {
|
||
return jQuery.extend(true, NumberColumn.superclass.prototype.getCellDefaultCfg.call(this), {
|
||
maxLength: this.maxLength,
|
||
mask: this.mask,
|
||
placeholder: this.placeholder,
|
||
readOnly: this.readOnly
|
||
});
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.grid.NumberColumn', NumberColumn);
|
||
}());
|
||
(function () {
|
||
var TextControlColumn = function (settings) {
|
||
TextControlColumn.superclass.call(this, settings);
|
||
this.maxLength = null;
|
||
this.placeholder = null;
|
||
this.trimOnBlur = null;
|
||
this.readOnly = null;
|
||
TextControlColumn.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.grid.GridControlColumn', TextControlColumn);
|
||
|
||
TextControlColumn.prototype.CELL = PMUI.grid.GridTextControlCell;
|
||
|
||
TextControlColumn.prototype.init = function (settings) {
|
||
var defaults = {
|
||
maxLength: null,
|
||
placeholder: null,
|
||
trimOnBlur: false,
|
||
readOnly: false
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setMaxLength(defaults.maxLength)
|
||
.setPlaceHolder(defaults.placeholder)
|
||
.setTrimOnBlur(defaults.trimOnBlur)
|
||
.setReadOnly(defaults.readOnly);
|
||
};
|
||
|
||
TextControlColumn.prototype.setMaxLength = function (input) {
|
||
var i,
|
||
cells,
|
||
cellsLength;
|
||
|
||
if (typeof input !== 'number') {
|
||
throw new Error("setMaxLength(): the parameter must be a number.");
|
||
}
|
||
this.maxLength = input;
|
||
cells = this.cells.asArray();
|
||
cellsLength = cells.length;
|
||
for (i = 0; i < cellsLength; i += 1) {
|
||
cells[i].setMaxLength(this.maxLength);
|
||
}
|
||
return this;
|
||
};
|
||
TextControlColumn.prototype.setPlaceHolder = function (input) {
|
||
var i,
|
||
cells,
|
||
cellsLength;
|
||
|
||
if (typeof input !== 'string') {
|
||
throw new Error("setPlaceHolder(): the parameter must be a string.");
|
||
}
|
||
this.placeholder = input;
|
||
cells = this.cells.asArray();
|
||
cellsLength = cells.length;
|
||
for (i = 0; i < cellsLength; i += 1) {
|
||
cells[i].setPlaceHolder(this.placeholder);
|
||
}
|
||
return this;
|
||
};
|
||
TextControlColumn.prototype.setTrimOnBlur = function (input) {
|
||
var i,
|
||
cells,
|
||
cellsLength;
|
||
|
||
this.trimOnBlur = !!input;
|
||
cells = this.cells.asArray();
|
||
cellsLength = cells.length;
|
||
for (i = 0; i < cellsLength; i += 1) {
|
||
cells[i].setTrimOnBlur(this.trimOnBlur);
|
||
}
|
||
return this;
|
||
};
|
||
TextControlColumn.prototype.setReadOnly = function (input) {
|
||
var i,
|
||
cells,
|
||
cellsLength;
|
||
|
||
this.readOnly = !!input;
|
||
cells = this.cells.asArray();
|
||
cellsLength = cells.length;
|
||
for (i = 0; i < cellsLength; i += 1) {
|
||
cells[i].setReadOnly(this.readOnly);
|
||
}
|
||
return this;
|
||
};
|
||
TextControlColumn.prototype.getCellDefaultCfg = function () {
|
||
return jQuery.extend(true, TextControlColumn.superclass.prototype.getCellDefaultCfg.call(this), {
|
||
maxLength: this.maxLength,
|
||
trimOnBlur: this.trimOnBlur,
|
||
placeholder: this.placeholder,
|
||
readOnly: this.readOnly
|
||
});
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.grid.TextControlColumn', TextControlColumn);
|
||
}());
|
||
(function () {
|
||
var DropDownListControlColumn = function (settings) {
|
||
DropDownListControlColumn.superclass.call(this, settings);
|
||
this.options = [];
|
||
DropDownListControlColumn.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.grid.GridControlColumn', DropDownListControlColumn);
|
||
|
||
DropDownListControlColumn.prototype.CELL = PMUI.grid.DropDownListControlCell;
|
||
|
||
DropDownListControlColumn.prototype.init = function (settings) {
|
||
var defaults = {
|
||
options: []
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setOptions(defaults.options);
|
||
};
|
||
|
||
DropDownListControlColumn.prototype.setOptions = function (options) {
|
||
var i,
|
||
cells;
|
||
|
||
if (!jQuery.isArray(options)) {
|
||
throw new Error("setOptions(): the parameter must be an array.");
|
||
}
|
||
this.options = options;
|
||
cells = this.cells.asArray();
|
||
for (i = 0; i < cells.length; i += 1) {
|
||
cells[i].setOptions(this.options);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
DropDownListControlColumn.prototype.getCellDefaultCfg = function () {
|
||
return jQuery.extend(true, DropDownListControlColumn.superclass.prototype.getCellDefaultCfg.call(this), {
|
||
options: this.options
|
||
});
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.grid.DropDownListControlColumn', DropDownListControlColumn);
|
||
}());
|
||
(function () {
|
||
var CheckBoxGroupColumn = function (settings) {
|
||
CheckBoxGroupColumn.superclass.call(this, settings);
|
||
this.controlPositioning = null;
|
||
this.maxDirectionOptions = null;
|
||
this.options = [];
|
||
CheckBoxGroupColumn.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.grid.GridControlColumn', CheckBoxGroupColumn);
|
||
|
||
CheckBoxGroupColumn.prototype.CELL = PMUI.grid.CheckBoxGroupControlCell;
|
||
|
||
CheckBoxGroupColumn.prototype.init = function (settings) {
|
||
var defaults = {
|
||
options: [],
|
||
controlPositioning: "vertical",
|
||
maxDirectionOptions: 1
|
||
};
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setOptions(defaults.options);
|
||
this.setMaxDirectionOptions(defaults.maxDirectionOptions);
|
||
this.setControlPositioning(defaults.controlPositioning);
|
||
};
|
||
|
||
CheckBoxGroupColumn.prototype.setOptions = function (options) {
|
||
var i,
|
||
cells;
|
||
|
||
if (!jQuery.isArray(options)) {
|
||
throw new Error("setOptions(): the parameter must be an array.");
|
||
}
|
||
this.options = options;
|
||
cells = this.cells.asArray();
|
||
for (i = 0; i < cells.length; i += 1) {
|
||
cells[i].setOptions(this.options);
|
||
}
|
||
return this;
|
||
};
|
||
CheckBoxGroupColumn.prototype.setControlPositioning = function (positioning) {
|
||
this.controlPositioning = positioning;
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupColumn.prototype.setMaxDirectionOptions = function (maxDirectionOptions) {
|
||
this.maxDirectionOptions = maxDirectionOptions;
|
||
return this;
|
||
};
|
||
|
||
CheckBoxGroupColumn.prototype.getCellDefaultCfg = function () {
|
||
return jQuery.extend(true, CheckBoxGroupColumn.superclass.prototype.getCellDefaultCfg.call(this), {
|
||
controlPositioning: this.controlPositioning,
|
||
maxDirectionOptions: this.maxDirectionOptions,
|
||
options: this.options
|
||
});
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.grid.CheckBoxGroupColumn', CheckBoxGroupColumn);
|
||
}());
|
||
(function () {
|
||
var GridControlRow = function (settings) {
|
||
GridControlRow.superclass.call(this, settings);
|
||
this.removeButton = null;
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.grid.GridPanelRow', GridControlRow);
|
||
|
||
GridControlRow.prototype.getCell = function (column) {
|
||
var cell = null;
|
||
if (column instanceof PMUI.grid.GridControlColumn) {
|
||
cell = this.cells.find("column", column);
|
||
} else if (typeof column === 'number') {
|
||
cell = this.cells.get(column);
|
||
}
|
||
return cell;
|
||
};
|
||
|
||
GridControlRow.prototype.setCells = function () {
|
||
var i,
|
||
columns,
|
||
cellsFactory,
|
||
cell;
|
||
|
||
this.clearCells();
|
||
if (this.parent) {
|
||
columns = this.parent.columns.asArray();
|
||
cellsFactory = this.parent.cellsFactory;
|
||
for (i = 0; i < columns.length; i += 1) {
|
||
cell = columns[i].createCell();
|
||
cell.column = columns[i];
|
||
cell.row = this;
|
||
this.cells.insert(cell);
|
||
if (this.html) {
|
||
this.html.appendChild(cell.getHTML());
|
||
}
|
||
this.data.addAttribute(cell.column.name, cell.getContent());
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridControlRow.prototype.updateData = function (cell) {
|
||
if (this.cells.contains(cell)) {
|
||
this.data.addAttribute(cell.column.name, cell.getContent());
|
||
}
|
||
return this;
|
||
};
|
||
|
||
GridControlRow.prototype.defineEvents = function () {
|
||
var that = this;
|
||
|
||
if (!this.removeButton) {
|
||
return this;
|
||
}
|
||
|
||
jQuery(this.html).on('mouseenter', function () {
|
||
var cell = that.getCell(that.cells.getSize() - 1);
|
||
cell.html.appendChild(that.removeButton);
|
||
}).on('mouseleave', function () {
|
||
jQuery(that.removeButton).detach();
|
||
});
|
||
jQuery(this.removeButton).on('click', '.pmui-gridpanelrow-deleteButton-link', function () {
|
||
if (that.parent) {
|
||
that.parent.removeItem(that);
|
||
}
|
||
});
|
||
return this;
|
||
};
|
||
|
||
GridControlRow.prototype.createHTML = function () {
|
||
var deleteButton,
|
||
deleteAnchor;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
GridControlRow.superclass.prototype.createHTML.call(this);
|
||
deleteButton = PMUI.createHTMLElement('div');
|
||
deleteAnchor = PMUI.createHTMLElement('a');
|
||
deleteButton.className = 'pmui-gridpanelrow-deleteButton';
|
||
deleteAnchor.className = 'pmui-gridpanelrow-deleteButton-link';
|
||
deleteAnchor.href = '#';
|
||
deleteButton.appendChild(deleteAnchor);
|
||
this.removeButton = deleteButton;
|
||
this.defineEvents();
|
||
return this.html;
|
||
};
|
||
|
||
GridControlRow.prototype.isValid = function () {
|
||
var i,
|
||
cells = this.cells.asArray(),
|
||
valid = true;
|
||
|
||
for (i = 0; i < cells.length; i += 1) {
|
||
valid = valid && cells[i].isValid();
|
||
if (!valid) {
|
||
return valid;
|
||
}
|
||
}
|
||
return valid;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.grid.GridControlRow', GridControlRow);
|
||
}());
|
||
(function () {
|
||
var ContainableItem = function (settings) {
|
||
ContainableItem.superclass.call(this, settings);
|
||
/**
|
||
* The parent container for the object.
|
||
* @type {PMUI.core.Container}
|
||
* @internal
|
||
*/
|
||
this.parent = null;
|
||
/**
|
||
* The data abstraction for the object.
|
||
* @type {PMUI.data.DataField}
|
||
*/
|
||
this.data = null;
|
||
ContainableItem.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', ContainableItem);
|
||
|
||
ContainableItem.prototype.init = function (settings) {
|
||
var defaults = {
|
||
parent: null,
|
||
data: new PMUI.data.DataField()
|
||
};
|
||
|
||
$.extend(true, defaults, settings);
|
||
|
||
this.setParent(defaults.parent)
|
||
.setData(defaults.data);
|
||
};
|
||
|
||
ContainableItem.prototype.setData = function (data) {
|
||
if (data instanceof PMUI.data.DataField) {
|
||
this.data = data;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
ContainableItem.prototype.getData = function () {
|
||
return this.data;
|
||
};
|
||
|
||
ContainableItem.prototype.setParent = function (parent) {
|
||
if (parent !== undefined) {
|
||
if (parent instanceof PMUI.core.Container || parent === null) {
|
||
this.parent = parent;
|
||
} else {
|
||
throw new Error("setParent(): The parameter must be instance of PMUI.core.Container or null.");
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.item.ContainableItem', ContainableItem);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports == ContainableItem;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.item.TabItem
|
||
* Creates an TabItem class, this is a basic element
|
||
* @extends {PMUI.core.Element}
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var ti,p;
|
||
* p = new PMUI.form.FormPanel({
|
||
* width: 604,
|
||
* height: 130,
|
||
* fieldset: true,
|
||
* legend: "my fieldset panel",
|
||
* items: [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "Name",
|
||
* id: "123",
|
||
* value: "",
|
||
* placeholder: "insert your name",
|
||
* name: "name"
|
||
* },{
|
||
* pmType: "text",
|
||
* label: "Last name",
|
||
* value: "",
|
||
* placeholder: "your lastname here asshole!",
|
||
* name: "lastname"
|
||
* }, {
|
||
* pmType: "panel",
|
||
* layout: 'hbox',
|
||
* items: [
|
||
* {
|
||
* pmType: "text",
|
||
* label: "E-mail",
|
||
* value: "",
|
||
* name: "email"
|
||
* },{
|
||
* pmType: "text",
|
||
* label: "Phone",
|
||
* value: "555",
|
||
* name: "phone"
|
||
* }
|
||
* ]
|
||
* }
|
||
* ],
|
||
* layout: "vbox"
|
||
* });
|
||
* ti = new PMUI.item.TabItem({
|
||
* title : 'titulo1',
|
||
* panel : p,
|
||
* icon : 'pmui-gridpanel-engranaje'
|
||
* });
|
||
* jQuery('body').append(ti.getHTML());
|
||
* ti.defineEvents();
|
||
*
|
||
* create a new instance of the TabItem, according to the example we set the following properties
|
||
* @cfg {String} [title='[untitled]'], Title The title for the Window
|
||
* @cfg {PMUI.core.Panel|Object} panel, this property is to set TabItems that are sent from the JSON
|
||
* @cfg {String} [icon = ""], this property serves to define one TabItem icon with css with putting a className for this icon
|
||
* parameter to family {panel}
|
||
* @cfg {Function} [onSelect= function() {}], this property is a function handler to from execute the
|
||
* function when is callback define events
|
||
*/
|
||
var TabItem = function (settings) {
|
||
TabItem.superclass.call(this, settings);
|
||
/**
|
||
* Defines the Title of the TabItem
|
||
* @type {String}
|
||
*/
|
||
this.title = null;
|
||
/**
|
||
* Element defines the panel that concentrates tab
|
||
* @type {PMUI.core.Panel}
|
||
*/
|
||
this.panel = null;
|
||
/**
|
||
* Defines the property is a function handler to from execute the
|
||
* function when is callback define events
|
||
* @type {function}
|
||
*/
|
||
this.onSelect = null;
|
||
/**
|
||
* The property define the TabItem is selected for triggering the
|
||
* @type {boolean}
|
||
*/
|
||
this.selected = null;
|
||
/**
|
||
* The property define the TabItem is selected for triggering
|
||
* @type {boolean}
|
||
*/
|
||
this.onClose = null;
|
||
/**
|
||
* property is defined when a TabItem is selected or event triggers a reference
|
||
* @type {HTMLElement}
|
||
*/
|
||
this.link = null;
|
||
/**
|
||
* Defines the fatory for childrend [PMUI.core.Panel]
|
||
* @type {PMUI.util.factory}
|
||
*/
|
||
this.factory = null;
|
||
/**
|
||
* property defined Tag for icon
|
||
* @type {HTMLElement}
|
||
*/
|
||
this.classNameIcon = null;
|
||
/**
|
||
* property defined Tag for spanTitle
|
||
* @type {HTMLElement}
|
||
*/
|
||
this.spanTitle = null;
|
||
/**
|
||
* TabItem title can be hidden or viewed by the user if you only want an icon mostart
|
||
* @type {Boolean}
|
||
*/
|
||
this.titleVisible = null;
|
||
/**
|
||
* [onClick description]
|
||
* @type {[type]}
|
||
* @private
|
||
*/
|
||
this.onClick = null;
|
||
this.icon = null;
|
||
TabItem.prototype.init.call(this, settings);
|
||
};
|
||
PMUI.inheritFrom('PMUI.core.Element', TabItem);
|
||
|
||
TabItem.prototype.family = 'TabItem';
|
||
TabItem.prototype.type = 'TabItem';
|
||
|
||
TabItem.prototype.init = function (settings) {
|
||
var defaults = {
|
||
title: '[untitled]',
|
||
panel: null,
|
||
onSelect: function () {
|
||
},
|
||
elementTag: 'li',
|
||
onClick: null
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.factory = new PMUI.util.Factory({
|
||
products: {
|
||
'treepanel': PMUI.panel.TreePanel,
|
||
'panel': PMUI.core.Panel,
|
||
'grid': PMUI.grid.GridPanel
|
||
},
|
||
defaultProduct: 'panel'
|
||
});
|
||
this.setElementTag(defaults.elementTag)
|
||
.setTitle(defaults.title)
|
||
.setPanel(defaults.panel)
|
||
.setOnSelectCallback(defaults.onSelect)
|
||
.setOnClick(defaults.onClick);
|
||
};
|
||
|
||
TabItem.prototype.setOnClick = function (onClick) {
|
||
if (typeof onClick !== 'function' && onClick !== null) {
|
||
throw new Error('setOnClick(): the parameter is no valid, should be a function');
|
||
}
|
||
this.onClick = onClick;
|
||
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* Add an item to the panel.
|
||
* @param {PMUI.item.TabItem} item
|
||
* It can be a valid JSON object or an object that inherits from {@link PMUI.item.TabItem}.
|
||
* @chainable
|
||
*/
|
||
TabItem.prototype.setOnSelectCallback = function (callback) {
|
||
if (typeof callback === 'function') {
|
||
this.onSelect = callback;
|
||
} else {
|
||
throw new Error("setOnSelectCallback(): The parameter is not a function.");
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @event
|
||
* Define the event listeners for the TabPanel.
|
||
* @chainable
|
||
*/
|
||
TabItem.prototype.defineEvents = function () {
|
||
var that = this;
|
||
|
||
this.removeEvents().eventsDefined = true;
|
||
if (this.link) {
|
||
this.addEvent('click').listen(this.link, function (e) {
|
||
if (typeof that.onSelect === 'function') {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
if (!that.selected) {
|
||
that.select();
|
||
}
|
||
}
|
||
if (typeof that.onClick === 'function') {
|
||
that.onClick(that);
|
||
}
|
||
});
|
||
that.panel.defineEvents();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the tabItem title
|
||
* Set the proportion of the html element
|
||
* @param {string} title
|
||
* @chainable
|
||
*/
|
||
TabItem.prototype.setTitle = function (title) {
|
||
this.title = title;
|
||
if (this.html) {
|
||
this.spanTitle.textContent = this.title;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns title the tabItem.
|
||
* @return {string}
|
||
*/
|
||
TabItem.prototype.getTitle = function () {
|
||
return this.title;
|
||
};
|
||
/**
|
||
* Sets the tabPanel [PMUI.core.panel] and full children except Window
|
||
* @chainable
|
||
*/
|
||
TabItem.prototype.setPanel = function (panel) {
|
||
var newPanel, errorMessage = "setPanel(): the object supplied as a parameter is not a valid type.";
|
||
if (!panel) {
|
||
throw new Error("setPanel(): you must specified a valid panel.");
|
||
}
|
||
if (panel instanceof PMUI.ui.Window) {
|
||
throw new Error(errorMessage);
|
||
}
|
||
if (this.factory) {
|
||
if (this.factory.isValidClass(panel) || this.factory.isValidName(panel.pmType) || (panel instanceof PMUI.grid.GridPanel)) {
|
||
newPanel = this.factory.make(panel);
|
||
} else {
|
||
throw new Error(errorMessage);
|
||
}
|
||
}
|
||
if (newPanel) {
|
||
this.panel = newPanel;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns panel the tabItem.
|
||
* @return {PMUI.core.Panel}
|
||
*/
|
||
TabItem.prototype.getPanel = function () {
|
||
return this.panel;
|
||
};
|
||
/**
|
||
* if the tab item is selected, the selected property changes
|
||
* @return {boolean}
|
||
*/
|
||
TabItem.prototype.isSelected = function () {
|
||
return this.selected;
|
||
};
|
||
/**
|
||
* if the tab item is selected, the selected property changes to true and calls
|
||
* your function onSelect
|
||
* @chainable
|
||
*/
|
||
TabItem.prototype.select = function () {
|
||
this.selected = true;
|
||
this.style.addClasses(['pmui-active']);
|
||
if (this.html) {
|
||
this.onSelect();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* if the tab item is selected, the selected property changes to false
|
||
* @chainable
|
||
*/
|
||
TabItem.prototype.deselect = function () {
|
||
this.selected = false;
|
||
this.style.removeClasses(['pmui-active']);
|
||
return this;
|
||
};
|
||
/**
|
||
* @method hideTitle
|
||
* hide the title of TabItem
|
||
* @chainable
|
||
*/
|
||
TabItem.prototype.hideTitle = function () {
|
||
this.titleVisible = false;
|
||
if (this.html) {
|
||
this.spanTitle.style.display = "none";
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @method hideTitle
|
||
* shows the title of the TabItem
|
||
* @chainable
|
||
*/
|
||
TabItem.prototype.showTitle = function () {
|
||
this.titleVisible = true;
|
||
if (this.html) {
|
||
this.spanTitle.style.display = "inline-block";
|
||
}
|
||
return this;
|
||
};
|
||
|
||
TabItem.prototype.createHTML = function () {
|
||
var tab,
|
||
ref,
|
||
spanTitle,
|
||
title,
|
||
icon;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
TabItem.superclass.prototype.createHTML.call(this);
|
||
ref = PMUI.createHTMLElement('a');
|
||
spanTitle = PMUI.createHTMLElement('span');
|
||
icon = PMUI.createHTMLElement('i');
|
||
icon.className = 'pmui-tab-icon';
|
||
ref.className = 'pmui-tab-ref';
|
||
ref.href = '#';
|
||
spanTitle.className = 'pmui-tab_title';
|
||
spanTitle.textContent = this.title;
|
||
ref.appendChild(icon);
|
||
ref.appendChild(spanTitle);
|
||
this.icon = icon;
|
||
this.html.appendChild(ref);
|
||
this.spanTitle = spanTitle;
|
||
this.link = ref;
|
||
this.setWidth(this.width);
|
||
|
||
if (this.eventsDefined) {
|
||
this.defineEvents();
|
||
}
|
||
return this.html;
|
||
};
|
||
|
||
TabItem.prototype.setWidth = function (width) {
|
||
TabItem.superclass.prototype.setWidth.call(this, width);
|
||
if (this.html) {
|
||
if (width == "auto") {
|
||
this.link.setAttribute("title", "");
|
||
this.spanTitle.style.width = "auto";
|
||
} else {
|
||
this.link.setAttribute("title", this.title);
|
||
if (this.width >= 65) {
|
||
this.spanTitle.style.width = this.width - 46 + 'px';
|
||
} else {
|
||
this.spanTitle.style.width = '0px';
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.item.TabItem', TabItem);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = TabItem;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.item.AccordionItem
|
||
* @extends PMUI.core.Item
|
||
*
|
||
* Class to handle Accordion items, this is the basic element for make an {@link PMUI.panel.AccordionPanel Accordion}
|
||
*
|
||
* @constructor
|
||
* For creates a new component the JSON config can have the following sentences
|
||
* @param {Object} settings The configuration options contain:
|
||
*
|
||
* {
|
||
* title: "The title",
|
||
* body: panel // This item can be any element that inherit from {@link PMUI.core.Panel Panel}
|
||
* iconClass: "the-class",
|
||
* style: {
|
||
* cssProperties: {
|
||
* "background-color": "#f2eaea"
|
||
* }
|
||
* }
|
||
* } ...
|
||
* @cfg {String} [title=""] Shows the title for the container
|
||
* @cfg {Object} [body=null] Defines the element that will be inside the element
|
||
* @cfg {String} [iconClass='pmui-accordion-item-icon'] Defines the class name for the header of the item
|
||
*
|
||
*/
|
||
AccordionItem = function (settings) {
|
||
AccordionItem.superclass.call(this, settings);
|
||
/**
|
||
* @property {String} [iconClass='pmui-accordion-item-icon']
|
||
* Defines the class name for the header of the item
|
||
*/
|
||
this.iconClass = null;
|
||
/**
|
||
* @property {String} [headerClass='pmui-accordion-item-header']
|
||
* Defines the class name for the header
|
||
* @private
|
||
*/
|
||
this.headerClass = null,
|
||
/**
|
||
* @property {String} [bodyClass='pmui-accordion-item-body']
|
||
* Defines the class name for the body
|
||
* @private
|
||
*/
|
||
this.bodyClass = null,
|
||
/**
|
||
* @property {String} [footerClass='pmui-accordion-item-footer']
|
||
* Defines the class name for the footer
|
||
* @private
|
||
*/
|
||
this.footerClass = null;
|
||
/**
|
||
* @property {String} [containerClass='pmui-accordion-item-container']
|
||
* Defines the class name for the global container
|
||
* @private
|
||
*/
|
||
this.containerClass = null;
|
||
/**
|
||
* @property {String} [iconExpanded='pmui-accordion-item-closed']
|
||
* Defines the class name that represents the icon expanded for the AccordionItem
|
||
* @private
|
||
*/
|
||
this.iconExpanded = null;
|
||
/**
|
||
* @property {String} [iconClosed='pmui-accordion-item-expanded']
|
||
* Defines the class name that represents the icon closed for the AccordionItem
|
||
* @private
|
||
*/
|
||
this.iconClosed = null;
|
||
|
||
/**
|
||
* @property {Boolean} [collapsed=true]
|
||
* Defines whether the object is collapsed or not
|
||
* @private
|
||
*/
|
||
this.collapsed = null;
|
||
/**
|
||
* @property {Object} [container=null]
|
||
* container Defines the container object for the class xxxxxxx
|
||
* @private
|
||
*/
|
||
this.container = null;
|
||
/**
|
||
* @property {Object} [header=null]
|
||
* Defines the header object for the class
|
||
* @private
|
||
*/
|
||
this.header = null;
|
||
/**
|
||
* @property {Object} [body={}]
|
||
* Defines the body object for the item
|
||
* @private
|
||
*/
|
||
this.body = {};
|
||
/**
|
||
* @property {Object} [footer=null]
|
||
* Defines the footer object for the class
|
||
* @private
|
||
*/
|
||
this.footer = null;
|
||
/**
|
||
* @property {Boolean} [selected=false]
|
||
* Defines whether the item is selected by default when the component is ready to render
|
||
* on the browser
|
||
*/
|
||
this.selected = null;
|
||
/**
|
||
* @property {Boolean} [propName]
|
||
* Represents a flag for control the rendered of the item.
|
||
* If the property is True the item was rendered the otherwise if it
|
||
* False the item still was not rendered
|
||
* @private
|
||
*/
|
||
this.hiddenBody = null;
|
||
/**
|
||
* @property {Object} [iconNode=null]
|
||
* Defines the iconNode object for the class
|
||
* @private
|
||
*/
|
||
this.iconNode = null;
|
||
AccordionItem.prototype.init.call(this, settings);
|
||
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Item', AccordionItem);
|
||
AccordionItem.prototype.type = 'Accordion';
|
||
AccordionItem.prototype.family = 'Item';
|
||
AccordionItem.prototype.init = function (settings) {
|
||
var defaults = {
|
||
title: '',
|
||
body: '',
|
||
collapsed: true,
|
||
iconClass: 'pmui-accordion-item-icon',
|
||
headerClass: 'pmui-accordion-item-header',
|
||
bodyClass: 'pmui-accordion-item-body',
|
||
footerClass: 'pmui-accordion-item-footer',
|
||
containerClass: 'pmui-accordion-item-container',
|
||
iconClosed: "pmui-accordion-item-closed",
|
||
iconExpanded: "pmui-accordion-item-expanded",
|
||
selected: false,
|
||
factory: {
|
||
products: {
|
||
'panel': PMUI.core.Item
|
||
}
|
||
}
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setFactory(defaults.products)
|
||
.setTitle(defaults.title)
|
||
.setBody(defaults.body)
|
||
.setIconClass(defaults.iconClass)
|
||
.setHeaderClass(defaults.headerClass)
|
||
.setBodyClass(defaults.bodyClass)
|
||
.setFooterClass(defaults.footerClass)
|
||
.setContainerClass(defaults.containerClass)
|
||
.setIconExpanded(defaults.iconExpanded)
|
||
.setIconClosed(defaults.iconClosed)
|
||
.setCollapsed(defaults.collapsed)
|
||
.setSelected(defaults.selected);
|
||
};
|
||
|
||
/**
|
||
* Sets the string that represent the title. It could be an simple string
|
||
* or an string that contains html tags. If the string contains html code
|
||
* it will be rendered
|
||
* @param {String} title
|
||
*/
|
||
AccordionItem.prototype.setTitle = function (title) {
|
||
if (typeof title === "string") {
|
||
this.title = title;
|
||
if (this.header) {
|
||
this.header.items[2].title.html.innerHTML = title;
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name for the AccordionItem's title
|
||
* @param {String} class name
|
||
*/
|
||
AccordionItem.prototype.setIconClass = function (className) {
|
||
this.iconClass = (typeof className === 'string') ? className : '';
|
||
if (this.header) {
|
||
this.header.items[1].iconTitle.html.className = 'pmui-accordion-item-iconbase ' + className;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name for the AccordionItem's header
|
||
* @param {String} class name
|
||
* @private
|
||
*/
|
||
AccordionItem.prototype.setHeaderClass = function (className) {
|
||
this.headerClass = (typeof className === 'string') ? className : '';
|
||
if (this.header) {
|
||
this.header.html.className = className;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name for the AccordionItem's body
|
||
* @param {String} class name
|
||
* @private
|
||
*/
|
||
AccordionItem.prototype.setBodyClass = function (className) {
|
||
this.bodyClass = (typeof className === 'string') ? className : '';
|
||
if (this.html) {
|
||
this.container[1].className = className;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name for the AccordionItem's footer
|
||
* @param {String} class name
|
||
* @private
|
||
*/
|
||
AccordionItem.prototype.setFooterClass = function (className) {
|
||
this.footerClass = (typeof className === 'string') ? className : '';
|
||
if (this.html) {
|
||
this.container[2].className = className;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name for the AccordionItem's container
|
||
* @param {String} class name
|
||
* @private
|
||
*/
|
||
AccordionItem.prototype.setContainerClass = function (className) {
|
||
this.containerClass = (typeof className === 'string') ? className : '';
|
||
if (this.html) {
|
||
this.html.className = className;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name that represents the icon in its expanded status
|
||
* @param {String} class name
|
||
* @private
|
||
*/
|
||
AccordionItem.prototype.setIconExpanded = function (className) {
|
||
this.iconExpanded = (typeof className === 'string') ? className : '';
|
||
if (this.header) {
|
||
this.header.items[0].iconNode.html.className = 'pmui-accordion-item-iconbase ' + className;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name that represents the icon in its closed status
|
||
* @param {String} class name
|
||
* @private
|
||
*/
|
||
AccordionItem.prototype.setIconClosed = function (className) {
|
||
this.iconClosed = (typeof className === 'string') ? className : '';
|
||
if (this.header) {
|
||
this.header.items[0].iconNode.html.className = 'pmui-accordion-item-iconbase ' + className;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the status for the item, whether it collapsed or not
|
||
* @param {Boolean} option
|
||
* @private
|
||
*/
|
||
AccordionItem.prototype.setCollapsed = function (option) {
|
||
this.collapsed = option;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the status collapsed. If it true the container will be opened
|
||
* and if it false will be closed
|
||
* @param {Boolean} status
|
||
*/
|
||
AccordionItem.prototype.setSelected = function (status) {
|
||
if (typeof status === 'boolean') {
|
||
this.selected = status;
|
||
this.setCollapsed(!status);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the body for the item as a new child for the container.
|
||
* The parameter can be:
|
||
*
|
||
* - {@link PMUI.core.Panel panel}: In this case the item can be any class that inherit from
|
||
* {@link PMUI.core.Panel Panel}. For example {@link PMUI.form.Form Form}, {@link PMUI.panel.TreePanel TreePanel}, etc.
|
||
* - String: In this case the string must have contain html code o can be a simple string like to exaple below:
|
||
*
|
||
* "<a href=\"http://www.colosa.com\">Colosa</a>"
|
||
*
|
||
* @param {PMUI.core.Panel|String} body
|
||
*/
|
||
AccordionItem.prototype.setBody = function (body) {
|
||
var currentPanel = this.body.html;
|
||
if (body instanceof PMUI.core.Container) {
|
||
body.getHTML();
|
||
this.body.items = [
|
||
{
|
||
panel: {
|
||
html: body.html
|
||
}
|
||
}
|
||
];
|
||
} else if (typeof body === 'string') {
|
||
this.body.items = [
|
||
{
|
||
panel: {
|
||
html: body
|
||
}
|
||
}
|
||
];
|
||
}
|
||
try {
|
||
this.body.html.removeChild(this.body.items[0].panel.html);
|
||
} catch (e) {
|
||
}
|
||
|
||
this.addItem(body);
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds an child item to the object.
|
||
* @param {PMUI.core.Element|Object} item It can be one of the following data types:
|
||
* - {PMUI.core.Element} the object to add.
|
||
* - {Object} a JSON object with the settings for the Container to be added.
|
||
* @param {Number} [index] An index in which the item will be added.
|
||
* @chainable
|
||
*/
|
||
AccordionItem.prototype.addItem = function (item, index) {
|
||
var itemToBeAdded;
|
||
if (this.factory) {
|
||
itemToBeAdded = this.factory.make(item);
|
||
}
|
||
if (itemToBeAdded) {
|
||
itemToBeAdded.parent = this;
|
||
this.clearItems();
|
||
this.items.insert(itemToBeAdded);
|
||
if (this.body.html) {
|
||
this.body.html.appendChild(itemToBeAdded.getHTML());
|
||
|
||
if (this.eventsDefined) {
|
||
itemToBeAdded.defineEvents();
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Handler the collapse funtionality
|
||
* @return {PMUI.item.AccordionItem}
|
||
*/
|
||
AccordionItem.prototype.toggleCollapse = function () {
|
||
if (this.collapsed) {
|
||
this.expand();
|
||
} else {
|
||
this.collapse();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Collapses the item and sets the collapsed property in false
|
||
*/
|
||
AccordionItem.prototype.collapse = function () {
|
||
var items;
|
||
|
||
items = this.container;
|
||
jQuery(items[1]).slideUp(300);
|
||
jQuery(items[2]).slideUp(300);
|
||
this.header.items[0].iconNode.html.className = 'pmui-accordion-item-iconbase ' + this.iconClosed;
|
||
this.collapsed = true;
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Expands the item selected. If the multipleSelection is enabled, It is posible select
|
||
* one or more items the otherwise is only possible select one item.
|
||
* @return {PMUI.item.AccordionItem}
|
||
*/
|
||
AccordionItem.prototype.expand = function () {
|
||
var i,
|
||
items,
|
||
otherElements;
|
||
|
||
items = this.container;
|
||
jQuery(items[1]).slideDown(300);
|
||
jQuery(items[2]).slideDown(300);
|
||
this.header.items[0].iconNode.html.className = 'pmui-accordion-item-iconbase ' + this.iconExpanded;
|
||
this.collapsed = false;
|
||
|
||
//For other items
|
||
if (this.parent.multipleSelection === false) {
|
||
otherElements = this.parent.getItems();
|
||
for (i = 0; i < otherElements.length; i += 1) {
|
||
if (this.id != otherElements[i].id) {
|
||
otherElements[i].collapsed = false;
|
||
otherElements[i].toggleCollapse();
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
AccordionItem.prototype.createHTML = function () {
|
||
var container,
|
||
header,
|
||
iconNode,
|
||
iconTitle,
|
||
title,
|
||
body,
|
||
footer,
|
||
containerIcon;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
container = AccordionItem.superclass.prototype.createHTML.call(this);
|
||
container.setAttribute('class', this.containerClass);
|
||
/*=============================================
|
||
Header accordion
|
||
=============================================*/
|
||
header = PMUI.createHTMLElement("div");
|
||
header.setAttribute('class', this.headerClass);
|
||
iconNode = PMUI.createHTMLElement('span');
|
||
containerIcon = PMUI.createHTMLElement('span');
|
||
containerIcon.className = "pmui-accordion-item-iconContainer";
|
||
if (this.collapsed) {
|
||
iconNode.setAttribute("class", 'pmui-accordion-item-iconbase ' + this.iconClosed);
|
||
} else if (!this.collapsed) {
|
||
iconNode.setAttribute("class", 'pmui-accordion-item-iconbase ' + this.iconExpanded);
|
||
}
|
||
iconTitle = PMUI.createHTMLElement('span');
|
||
iconTitle.setAttribute('class', 'pmui-accordion-item-iconbase ' + this.iconClass);
|
||
title = PMUI.createHTMLElement('span');
|
||
title.className = 'pmui-accordion-item-title';
|
||
title.innerHTML = this.title;
|
||
containerIcon.appendChild(iconNode);
|
||
header.appendChild(containerIcon);
|
||
|
||
this.iconNode = containerIcon;
|
||
header.appendChild(iconTitle);
|
||
header.appendChild(title);
|
||
this.header = {
|
||
html: header,
|
||
items: [
|
||
{
|
||
iconNode: {
|
||
html: iconNode
|
||
}
|
||
},
|
||
{
|
||
iconTitle: {
|
||
html: iconTitle
|
||
}
|
||
},
|
||
{
|
||
title: {
|
||
html: title
|
||
}
|
||
}
|
||
]
|
||
};
|
||
/*=============================================
|
||
body accordion
|
||
=============================================*/
|
||
body = PMUI.createHTMLElement("div");
|
||
body.setAttribute('class', this.bodyClass);
|
||
|
||
if (typeof this.parent.heightItem === "string") {
|
||
body.style.height = this.parent.heightItem;
|
||
} else {
|
||
body.style.height = this.parent.heightItem + 'px';
|
||
}
|
||
if (this.collapsed) {
|
||
body.style.display = 'none';
|
||
}
|
||
|
||
this.body.html = body;
|
||
jQuery(body).html(this.body.items[0].panel.html);
|
||
|
||
/*=============================================
|
||
footer accordion
|
||
=============================================*/
|
||
footer = PMUI.createHTMLElement("div");
|
||
footer.setAttribute('class', this.footerClass);
|
||
this.container = new Array();
|
||
this.container.push(header, body, footer);
|
||
/*=============================================
|
||
Container accordion
|
||
=============================================*/
|
||
container.appendChild(header);
|
||
container.appendChild(body);
|
||
container.appendChild(footer);
|
||
this.html = container;
|
||
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Defines events related to the current panel and the calls to DefineEvents from
|
||
* every {@link PMUI.core.Item item}
|
||
* return {this}
|
||
*/
|
||
AccordionItem.prototype.defineEvents = function () {
|
||
var j,
|
||
fnSelect,
|
||
children,
|
||
that = this;
|
||
|
||
this.removeEvents().eventsDefined = true;
|
||
if (that.container[0]) {
|
||
that.addEvent('click').listen(this.iconNode, function (e) {
|
||
e.preventDefault();
|
||
|
||
that.toggleCollapse();
|
||
fnSelect = that.parent.listeners.select;
|
||
fnSelect(that, e);
|
||
|
||
e.stopPropagation();
|
||
});
|
||
}
|
||
|
||
if (that.items.getSize() > 0) {
|
||
children = that.getItems();
|
||
for (j = 0; j < children.length; j += 1) {
|
||
children[j].defineEvents();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.item.AccordionItem', AccordionItem);
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = AccordionItem;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.item.TreeNode
|
||
* Each node in a TreePanel. It is able to apply data binding, that means that it can use its
|
||
* {@link PMUI.item.TreeNode#property-data data property} for set another object's property.
|
||
* @extends PMUI.core.Item
|
||
*
|
||
* The following example shows a TreeNode object whose child nodes are created using the
|
||
* {@link PMUI.item.TreeNode#cfg-items items config option}:
|
||
*
|
||
* @example
|
||
* var t;
|
||
* $(function() {
|
||
* t = new PMUI.item.TreeNode({
|
||
* label: 'America',
|
||
* childrenDefaultSettings: {
|
||
* label: '[untitled node]'
|
||
* },
|
||
* items: [
|
||
* {
|
||
* label: "North America",
|
||
* items: [
|
||
* {
|
||
* label: 'Canada',
|
||
* data: {
|
||
* label: 'Canada',
|
||
* value: 'cnd'
|
||
* }
|
||
* },
|
||
* {
|
||
* label: 'Mexico'
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* label: "Central America and Caribbean",
|
||
* items: [
|
||
* {
|
||
* label: 'Cuba'
|
||
* },
|
||
* {
|
||
* label: 'Guatemala'
|
||
* }
|
||
* ]
|
||
* },
|
||
* {
|
||
* label: "South America",
|
||
* items: [
|
||
* {
|
||
* label: 'Argentina'
|
||
* },
|
||
* {
|
||
* label: 'Bolivia'
|
||
* }
|
||
* ]
|
||
* }
|
||
* ]
|
||
* });
|
||
* document.body.appendChild(t.getHTML());
|
||
* t.defineEvents();
|
||
* });
|
||
*
|
||
* The following example shows a TreeNode object whose child nodes are created using the
|
||
* {@link PMUI.item.TreeNode#cfg-dataItems dataItems config option}:
|
||
*
|
||
* @example
|
||
* var t2;
|
||
* $(function() {
|
||
* t2 = new PMUI.item.TreeNode({
|
||
* data: {
|
||
* name: 'America'
|
||
* },
|
||
* labelDataBind: 'name',
|
||
* autoBind: true,
|
||
* childrenDefaultSettings: {
|
||
* labelDataBind: 'name',
|
||
* autoBind: true
|
||
* },
|
||
* dataItems: [
|
||
* {
|
||
* name: "Argentina"
|
||
* },
|
||
* {
|
||
* name: "Bolivia"
|
||
* },
|
||
* {
|
||
* name: "Brasil"
|
||
* }
|
||
* ]
|
||
* });
|
||
* document.body.appendChild(t2.getHTML());
|
||
* t2.defineEvents();
|
||
* });
|
||
*
|
||
* @cfg {Boolean} [sterile=false] If the node will be able to have children nodes.
|
||
* @cfg {String} [itemsDataBind=null] The key from the object's data to be used as the array for create the child
|
||
* nodes of the current node when the data binding be applied. If the data binding is applied then the
|
||
* {@link PMUI.item.TreeNode#cfg-items items config option} will be ignored.
|
||
* @cfg {String} [labelDataBind=null] The key from the object's data to be used as the label for the current node
|
||
* when the data binding be applied. If the data binding is applied then the
|
||
* {@link PMUI.item.TreeNode#cfg-label label config option} will be ignored.
|
||
* @cfg {String} [nodeClassDataBind=null] The key from the object's data to be used as the class for the node's
|
||
* html when the data binding be applied. If the data binding is applied then the
|
||
* {@link PMUI.item.TreeNode#cfg-nodeClass nodeClass config option} will be ignored.
|
||
* @cfg {Object} [data={}] The data for the node.
|
||
* @cfg {Boolean} [collapsed=true] If the node will be collapsed or not from the beginning.
|
||
* @cfg {String} [label='[item]'] The label text for the node.
|
||
* @cfg {String} [nodeClass=''] The css class for the node's html.
|
||
* @cfg {Function} [onCollapse=null] The callback function to be executed everytime the current node is collpased.
|
||
* Please read the {@link PMUI.item.TreeNode#event-onCollapse onCollapse event documentation}.
|
||
* @cfg {Function} [onExpand=null] The callback function yto be executed everytime the current node is expanded.
|
||
* Please read the {@link PMUI.item.TreeNode#event-onExpanded onExpanded event documentation}.
|
||
* @cfg {Object} [childrenDefaultSettings={}] The default config options to be applied to the new child nodes for
|
||
* the current node. This only will be applied when the appended item is an object literal.
|
||
* @cfg {Boolean} [autobind] If the data binding will be applied automatically on instantiation and everytime the
|
||
* data is set. This will cause that some others config options be ignored (like
|
||
* {@link PMUI.item.TreeNode#cfg-label label}, {@link PMUI.item.TreeNode#cfg-nodeClass nodeClass} and/or
|
||
* {@link PMUI.item.TreeNode#cfg-items items}).
|
||
* @cfg {Boolean} [recursiveChildrenDefaultSettings=false] If the current
|
||
* {@link PMUI.item.TreeNode#cfg-childrenDefaultSettings childrenDefaultSettings config option} will be inherited
|
||
* to the same config option of its child nodes.
|
||
* @cfg {Function|null} [onBeforeAppend=null] A callback function to be called everytime the
|
||
* {@link #event-onBeforeAppend onBeforeAppend} event is fired. For info about the parameters used for this
|
||
* callback please read the documentation for this event.
|
||
* @cfg {Function|null} [onAppend=null] A callback function to be called everytime the
|
||
* {@link #event-onAppend onAppend} event is fired. For info about the parameters used for this callback please
|
||
* read the documentation for this event.
|
||
*/
|
||
var TreeNode = function (settings) {
|
||
TreeNode.superclass.call(this, settings);
|
||
/**
|
||
* If the node can have child nodes.
|
||
* @type {Boolean}
|
||
*/
|
||
this.sterile = null;
|
||
/**
|
||
* If the node is collapsed.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.collapsed = null;
|
||
/**
|
||
* The current label being used by the node.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.label = null;
|
||
/**
|
||
* A literal object that will contain all the dom elements that compose the node's html structure.
|
||
* @type {Object}
|
||
* @readonly
|
||
*/
|
||
this.dom = {};
|
||
/**
|
||
* The css class for the node's html.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.nodeClass = null;
|
||
/**
|
||
* @event onClick
|
||
* Fired when the current node is clicked
|
||
*/
|
||
this.onClick = null;
|
||
/**
|
||
* @event onCollapse
|
||
* Fired when the current node is collapsed.
|
||
*/
|
||
this.onCollapse = null;
|
||
/**
|
||
* @event onExpand
|
||
* Fired when the current node is expanded.
|
||
*/
|
||
this.onExpand = null;
|
||
/**
|
||
* The key of the object's data that will be used as the array to build the child nodes for the current one
|
||
* when the data binding is applied.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.itemsDataBind = null;
|
||
/**
|
||
* The key of the object's data that will be used as the label for the current node when the data binding is
|
||
* applied.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.labelDataBind = null;
|
||
/**
|
||
* The key of the object's data that will be used as the css class for the current node's html when the data
|
||
* binding is applied.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.nodeClassDataBind = null;
|
||
/**
|
||
* If the data binding will be applied on initialization and everytime the data is set.
|
||
* @type {Boolean}
|
||
*/
|
||
this.autoBind = null;
|
||
/**
|
||
* The default config options to be applied to the child nodes to be add to the current node, but only when an
|
||
* object literal is used.
|
||
* @type {Object}
|
||
*/
|
||
this.childrenDefaultSettings = {};
|
||
/**
|
||
* The data for the current node. This data can be used to modify another node's properties through data
|
||
* binding.
|
||
* @type {PMUI.data.DataField}
|
||
* @private
|
||
*/
|
||
this.data = null;
|
||
/**
|
||
* If the settings defined in the {@link #property-childrenDefaultSettings childrenDefaultSettings} property will
|
||
* be inherited to all the child nodes of the current one.
|
||
* @type {Boolean}
|
||
*/
|
||
this.recursiveChildrenDefaultSettings = null;
|
||
/**
|
||
* @event onBeforeAppend
|
||
* Fired before a child node is appended to the current node or to any of its children nodes.
|
||
* @param {PMUI.item.TreeNode} node The node in which the event is being fired.
|
||
* @param {PMUI.item.TreeNode} newNode The new node to be appended.
|
||
*/
|
||
this.onBeforeAppend = null;
|
||
/**
|
||
* @event onAppend
|
||
* Fired everytime a child node is appended to the current node or to any of its children nodes.
|
||
* @param {PMUI.item.TreeNode} node The node in which the event is being fired.
|
||
* @param {PMUI.item.TreeNode} newNode The appended node.
|
||
*/
|
||
this.onAppend = null;
|
||
TreeNode.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Item', TreeNode);
|
||
/**
|
||
* @property {String} type=TreeNode The type of the class.
|
||
* @readonly
|
||
*/
|
||
TreeNode.prototype.type = 'TreeNode';
|
||
/**
|
||
* @property {String} family=Tree The class family.
|
||
* @readonly
|
||
*/
|
||
TreeNode.prototype.family = 'Tree';
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} settings The object literal with the config options.
|
||
* @private
|
||
*/
|
||
TreeNode.prototype.init = function (settings) {
|
||
var defaults = {
|
||
itemsDataBind: null,
|
||
labelDataBind: null,
|
||
nodeClassDataBind: null,
|
||
data: {},
|
||
sterile: false,
|
||
collapsed: true,
|
||
label: '[item]',
|
||
nodeClass: "",
|
||
onCollapse: null,
|
||
onExpand: null,
|
||
onClick: null,
|
||
childrenDefaultSettings: {},
|
||
autoBind: false,
|
||
recursiveChildrenDefaultSettings: false,
|
||
onAppend: null,
|
||
onBeforeAppend: null
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.data = new PMUI.data.DataField();
|
||
|
||
this.setNodeClass(defaults.nodeClass)
|
||
if (defaults.autoBind) {
|
||
this.enableAutoBind();
|
||
} else {
|
||
this.disableAutoBind();
|
||
}
|
||
this.setRecursiveChildrenDefaultSettings(defaults.recursiveChildrenDefaultSettings)
|
||
.setChildrenDefaultSettings(defaults.childrenDefaultSettings)
|
||
.setSterility(defaults.sterile)
|
||
.setLabel(defaults.label)
|
||
.setParent(defaults.parent)
|
||
.setOnCollapseHandler(defaults.onCollapse)
|
||
.setOnExpandHandler(defaults.onExpand)
|
||
.setOnClickHandler(defaults.onClick)
|
||
.setItemsDataBind(defaults.itemsDataBind)
|
||
.setLabelDataBind(defaults.labelDataBind)
|
||
.setNodeClassDataBind(defaults.nodeClassDataBind)
|
||
.setOnAppendHandler(defaults.onAppend)
|
||
.setOnBeforeAppendHandler(defaults.onBeforeAppend);
|
||
|
||
if (defaults.dataItems && jQuery.isArray(defaults.dataItems)) {
|
||
this.setDataItems(defaults.dataItems);
|
||
} else {
|
||
this.setItems(defaults.items);
|
||
}
|
||
this.setData(defaults.data);
|
||
|
||
if (defaults.collapsed) {
|
||
this.collapse();
|
||
} else {
|
||
this.expand();
|
||
}
|
||
this.elementTag = 'li';
|
||
};
|
||
/**
|
||
* Sets the callback function to be called everytime the {@link #event-onBeforeAppend onBeforeAppend} event is
|
||
* fired. For info about the parameters used for this callback please read the documentation for this event.
|
||
* @param {Function|null} handler
|
||
*/
|
||
TreeNode.prototype.setOnBeforeAppendHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnBeforeAppendHandler(): The parameter must be a function or null.");
|
||
}
|
||
this.onBeforeAppend = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback function to be called everytime the
|
||
* {@link #event-onAppend onAppend} event is fired. For info about the parameters used for this callback please
|
||
* read the documentation for this event.
|
||
* @param {Function|null} handler
|
||
*/
|
||
TreeNode.prototype.setOnAppendHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnAppendHandler(): The parameter must be a function or null.");
|
||
}
|
||
this.onAppend = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the level of the node relative to its root node.
|
||
* @return {Number}
|
||
*/
|
||
TreeNode.prototype.getDepth = function () {
|
||
if (!this.parent || !(this.parent instanceof PMUI.item.TreeNode)) {
|
||
return 0;
|
||
} else {
|
||
return this.parent.getDepth() + 1;
|
||
}
|
||
};
|
||
/**
|
||
* Returns the root node of the current one.
|
||
* @return {PMUI.item.TreeNode}
|
||
*/
|
||
TreeNode.prototype.getRoot = function () {
|
||
if (this.getDepth() === 0) {
|
||
return this;
|
||
} else {
|
||
return this.parent.getRoot();
|
||
}
|
||
};
|
||
/**
|
||
* Turns on the auto binding functionality.
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.enableAutoBind = function () {
|
||
this.autoBind = true;
|
||
return this;
|
||
};
|
||
/**
|
||
* Turns off the auto binding functionality.
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.disableAutoBind = function () {
|
||
this.autoBind = false;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns true if the current {@link PMUI.item.TreeNode#property-childrenDfaultSettings childrenDfaultSettings}
|
||
* will be inherited to the next child nodes that will be added.
|
||
* @return {Boolean} [description]
|
||
*/
|
||
TreeNode.prototype.isRecursiveChildrenDefaultSettings = function () {
|
||
return this.recursiveChildrenDefaultSettings;
|
||
};
|
||
/**
|
||
* Establish if the current object's childrenDefaultSettings property values will be set it to the same property
|
||
* of its future child nodes.
|
||
* @param {Boolean} recursive
|
||
*/
|
||
TreeNode.prototype.setRecursiveChildrenDefaultSettings = function (recursive) {
|
||
this.recursiveChildrenDefaultSettings = !!recursive;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the default config options for the node's child nodes.
|
||
* @return {Object}
|
||
*/
|
||
TreeNode.prototype.getChildrenDefaultSettings = function () {
|
||
return this.childrenDefaultSettings;
|
||
};
|
||
/**
|
||
* Sets the default config options for the child nodes to be added. Note that if you set this, the effect will
|
||
* take effect only in new nodes added from the moment of the new set. The default settings will have effect only
|
||
* when you add an item using anything but an instance of {@link PMUI.core.Element} (or ant subclass of it).
|
||
* @param {Object} settings A object literal with some or all of the config options for a TreeNode instance.
|
||
*/
|
||
TreeNode.prototype.setChildrenDefaultSettings = function (settings) {
|
||
if (typeof settings !== 'object') {
|
||
throw new Error('setChildrenDefaultSettings(): The parameter must be an object.');
|
||
}
|
||
this.childrenDefaultSettings = settings;
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the key of the current node's data to be used as the css class for the node's html.
|
||
* @param {String} nodeClassDataBind
|
||
*/
|
||
TreeNode.prototype.setNodeClassDataBind = function (nodeClassDataBind) {
|
||
if (nodeClassDataBind !== null && typeof nodeClassDataBind !== 'string') {
|
||
throw new Error("setNodeClassDataBind(): the parameter must be a string or null.");
|
||
}
|
||
this.nodeClassDataBind = nodeClassDataBind;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the key of the current node's data to be used as the array of items to be add to the current node.
|
||
* Note that every item in the array will be added as a data item
|
||
* (see the {@link PMUI.core.Container#method-addDataItem addDataItem()} method).
|
||
* @param {String} itemsDataBind
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.setItemsDataBind = function (itemsDataBind) {
|
||
if (itemsDataBind !== null && typeof itemsDataBind !== 'string') {
|
||
throw new Error("setItemsDataBind(): the parameter must be a string or null.");
|
||
}
|
||
this.itemsDataBind = itemsDataBind;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the key of the current node's data to be used as the label for the current node.
|
||
* @param {String} labelDataBind
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.setLabelDataBind = function (labelDataBind) {
|
||
if (labelDataBind !== null && typeof labelDataBind !== 'string') {
|
||
throw new Error("setLabelDataBind(): the parameter must be a string or null.");
|
||
}
|
||
this.labelDataBind = labelDataBind;
|
||
return this;
|
||
};
|
||
/**
|
||
* Bind the node's data to its properties using:
|
||
*
|
||
* - The {@link PMUI.item.TreeNode#property-labelDataBind labelDataBind property} to set the
|
||
* {@link PMUI.item.TreeNode#property-label label property}.
|
||
* - The {@link PMUI.item.TreeNode#property-itemsDataBind labelDataBind property} for set the node's child items.
|
||
* - The {@link PMUI.item.TreeNode#property-nodeClassDataBind nodeClassDataBind property} for set the css class for
|
||
* the node's html.
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.bindData = function () {
|
||
var data = this.data.getRecord();
|
||
|
||
this.setLabel(data[this.labelDataBind] || this.label);
|
||
if (this.itemsDataBind && jQuery.isArray(data[this.itemsDataBind])) {
|
||
this.setDataItems(data[this.itemsDataBind]);
|
||
}
|
||
this.setNodeClass(data[this.nodeClassDataBind] || this.nodeClass);
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the data for the node.
|
||
* @param {Object|PMUI.data.DataField} data
|
||
*/
|
||
TreeNode.prototype.setData = function (data) {
|
||
var key;
|
||
|
||
if (data instanceof PMUI.data.DataField) {
|
||
this.data = data;
|
||
} else if (typeof data === 'object') {
|
||
this.data.clear();
|
||
for (key in data) {
|
||
this.data.addAttribute(key, data[key]);
|
||
}
|
||
} else {
|
||
throw new Error("setData(): it only accepts a JSON object o an instance of PMUI.data.DataField as parameter.");
|
||
}
|
||
|
||
if (this.autoBind) {
|
||
this.bindData();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Return the node's data.
|
||
* @return {Object} A object literal containing the node's data.
|
||
*/
|
||
TreeNode.prototype.getData = function () {
|
||
return this.data.getRecord();
|
||
};
|
||
/**
|
||
* Sets the callback function for the {@link PMUI.item.TreeNode#event-onClickHandler onClickHandler event}.
|
||
* @param {Function} handler
|
||
*/
|
||
TreeNode.prototype.setOnClickHandler = function (handler) {
|
||
if (handler === null || typeof handler === 'function') {
|
||
this.onClick = handler;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback function for the {@link PMUI.item.TreeNode#event-onCollapse onCollapse event}.
|
||
* @param {Function} handler
|
||
*/
|
||
TreeNode.prototype.setOnCollapseHandler = function (handler) {
|
||
if (handler === null || typeof handler === 'function') {
|
||
this.onCollapse = handler;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the callback function for the {@link PMUI.item.TreeNode#event-onExpand onExpand event}.
|
||
* @param {Function} handler
|
||
*/
|
||
TreeNode.prototype.setOnExpandHandler = function (handler) {
|
||
if (handler === null || typeof handler === 'function') {
|
||
this.onExpand = handler;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the factory for the curren node.
|
||
* @private
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.setFactory = function () {
|
||
this.factory = new PMUI.util.Factory({
|
||
products: {
|
||
'treeNode': PMUI.item.TreeNode
|
||
},
|
||
defaultProduct: 'treeNode'
|
||
});
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the parent node for the current one.
|
||
* @param {null|PMUI.item.TreeNode|PMUI.panel.TreePanel} parent.
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.setParent = function (parent) {
|
||
if (parent === null || parent instanceof PMUI.item.TreeNode || parent instanceof PMUI.panel.TreePanel) {
|
||
TreeNode.superclass.prototype.setParent.call(this, parent);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns true if the node is sterile (it can have more child nodes).
|
||
* @return {Boolean}
|
||
*/
|
||
TreeNode.prototype.isSterile = function () {
|
||
return this.sterile;
|
||
};
|
||
/**
|
||
* Sets a custom css class for the node's html.
|
||
* @param {String} nodeClass
|
||
*/
|
||
TreeNode.prototype.setNodeClass = function (nodeClass) {
|
||
if (typeof nodeClass !== 'string') {
|
||
throw new Error('setNodeClass(): the parameter must be a string.');
|
||
}
|
||
nodeClass = jQuery.trim(nodeClass);
|
||
if (this.html) {
|
||
jQuery(this.dom.nodeElement).removeClass(this.nodeClass).addClass('pmui-treepanel-node').addClass(nodeClass);
|
||
}
|
||
this.nodeClass = nodeClass;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the custom css class of the node's html.
|
||
* @return {String}
|
||
*/
|
||
TreeNode.prototype.getNodeClass = function () {
|
||
return this.nodeClass;
|
||
};
|
||
/**
|
||
* Sets if the node is sterile or not (if can have more child nodes).
|
||
* @param {Boolean} sterile
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.setSterility = function (sterile) {
|
||
this.sterile = !!sterile;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the label for the node.
|
||
* @param {String} label
|
||
*/
|
||
TreeNode.prototype.setLabel = function (label) {
|
||
if (typeof label !== 'string') {
|
||
throw new Error('setLabel(): This method only accepts parameter of type String.');
|
||
}
|
||
this.label = label;
|
||
if (this.html) {
|
||
this.dom.label.textContent = label;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Applies the collapsing to its child nodes list.
|
||
* @param {Boolean} applyToChildren If the child nodes will apply the collapsing too.
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.collapse = function (applyToChildren) {
|
||
var i, childNodes;
|
||
this.collapsed = true;
|
||
if (applyToChildren) {
|
||
childNodes = this.items.asArray();
|
||
for (i = 0; i < childNodes.length; i += 1) {
|
||
childNodes[i].collapse(true);
|
||
}
|
||
}
|
||
if (this.html) {
|
||
jQuery(this.containmentArea).hide();
|
||
jQuery(this.dom.nodeElement).addClass('pmui-treepanel-node-collapsed');
|
||
if (typeof this.onCollapse === 'function') {
|
||
this.onCollapse();
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Applies the expanding to its child nodes list.
|
||
* @param {Boolean} applyToChildren If the child nodes will apply the expanding too.
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.expand = function (applyToChildren) {
|
||
var i,
|
||
childNodes;
|
||
|
||
this.collapsed = false;
|
||
if (applyToChildren) {
|
||
childNodes = this.items.asArray();
|
||
for (i = 0; i < childNodes.length; i += 1) {
|
||
childNodes[i].expand(true);
|
||
}
|
||
}
|
||
if (this.html) {
|
||
jQuery(this.containmentArea).show();
|
||
jQuery(this.dom.nodeElement).removeClass('pmui-treepanel-node-collapsed');
|
||
if (typeof this.onExpand === 'function') {
|
||
this.onExpand();
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns true if the node's child list is collapsed, otherwise it returns false.
|
||
* @return {Boolean}
|
||
*/
|
||
TreeNode.prototype.isCollapsed = function () {
|
||
return this.collapsed;
|
||
};
|
||
/**
|
||
* Returns true if the node has no child nodes, otherwise it returns false.
|
||
* @return {Boolean}
|
||
*/
|
||
TreeNode.prototype.isLeaf = function () {
|
||
return !this.items.getSize();
|
||
};
|
||
/**
|
||
* Returns true id the node is root, otherwise it returns false.
|
||
* @return {Boolean}
|
||
*/
|
||
TreeNode.prototype.isRoot = function () {
|
||
return this.parent instanceof PMUI.panel.TreePanel || !this.parent;
|
||
};
|
||
/**
|
||
* Updates the node's css class that sepcifies if the node is leaf or not.
|
||
* @private
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.updateNodeTypeClass = function () {
|
||
if (this.items.getSize() === 0) {
|
||
jQuery(this.dom.nodeElement).removeClass('pmui-treepanel-node-father').addClass('pmui-treepanel-node-leaf');
|
||
} else {
|
||
jQuery(this.dom.nodeElement).removeClass('pmui-treepanel-node-leaf').addClass('pmui-treepanel-node-father');
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* The private handler fot the {@link #event-onBeforeAppend onBeforeAppend} event.
|
||
* @private
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.onBeforeAppendHandler = function (treeNode) {
|
||
if (typeof this.onBeforeAppend === 'function') {
|
||
this.onBeforeAppend(this, treeNode);
|
||
}
|
||
this.parent && this.parent.onBeforeAppendHandler(treeNode);
|
||
return this;
|
||
};
|
||
/**
|
||
* The private handler for the {@link #event-onAppend} event.
|
||
* @private
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.onAppendHandler = function (treeNode) {
|
||
if (typeof this.onAppend === 'function') {
|
||
this.onAppend(this, treeNode);
|
||
}
|
||
this.parent && this.parent.onAppendHandler(treeNode);
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a new child node.
|
||
* @param {Object|PMUI.item.TreeNode} item The item to add, it can be:
|
||
* - A object literal with the config options to create the {@link PMUI.item.TreeNode TreeNode} to be added. If
|
||
* you have set the {@link PMUI.item.TreeNode#property-childDefaultSettings childDefaultSettings property} the
|
||
* contents of the object literal will be merge with (and into) the contens of this property. The resulting object
|
||
* literal will be used to create the {@link PMUI.item.TreeNode TreeNode} to be added.
|
||
* - An instance of {@link PMUI.item.TreeNode TreeNode}.
|
||
* @param {Number} index The index position for the node insertion.
|
||
*/
|
||
TreeNode.prototype.addItem = function (item, index) {
|
||
var settings = {},
|
||
toAdd;
|
||
|
||
if (this.isSterile()) {
|
||
throw new Error('addItem(): The tree node is sterile, it can\'t have children.');
|
||
}
|
||
if (typeof item !== 'object' && !(item instanceof PMUI.item.TreeNode)) {
|
||
throw new Error('addItem(): The parameter must be an instance of PMUI.item.TreeNode or an object.');
|
||
}
|
||
|
||
if (item instanceof PMUI.item.TreeNode) {
|
||
item.setParent(this);
|
||
toAdd = item;
|
||
} else if (typeof item === 'object') {
|
||
if (this.recursiveChildrenDefaultSettings) {
|
||
item.childrenDefaultSettings = this.childrenDefaultSettings;
|
||
item.recursiveChildrenDefaultSettings = true;
|
||
}
|
||
jQuery.extend(true, settings, this.childrenDefaultSettings, item);
|
||
settings.parent = this;
|
||
toAdd = this.factory.make(settings);
|
||
}
|
||
|
||
if (toAdd) {
|
||
if (typeof this.onBeforeAppend === 'function') {
|
||
this.onBeforeAppend(this, toAdd);
|
||
}
|
||
this.onBeforeAppendHandler(toAdd);
|
||
TreeNode.superclass.prototype.addItem.call(this, toAdd, index);
|
||
this.onAppendHandler(toAdd);
|
||
}
|
||
|
||
if (this.html) {
|
||
this.updateNodeTypeClass();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
TreeNode.prototype.setItems = function (items) {
|
||
if (this.onAppend !== undefined) {
|
||
TreeNode.superclass.prototype.setItems.call(this, items);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes a direct child node.
|
||
* @param {Number|PMUI.item.TreeNode|String} item It can be a string (id of the child to remove),
|
||
* a number (index of the child to remove) or a TreeNode object.
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.removeItem = function (item) {
|
||
TreeNode.superclass.prototype.removeItem.call(this, item);
|
||
this.updateNodeTypeClass();
|
||
return this;
|
||
};
|
||
/**
|
||
* Toggles the collapsing/expanding actions.
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.toggleCollapsing = function () {
|
||
if (this.isCollapsed()) {
|
||
this.expand();
|
||
} else {
|
||
this.collapse();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Clears the current filter criteria.
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.clearFilter = function () {
|
||
this.filter("");
|
||
return this;
|
||
};
|
||
/**
|
||
* Filter the current node and all its children.
|
||
* @param {String} filterCriteria The criteria for filtering, the filtering will be perform in the node's data.
|
||
* @return {Boolean} True if any of its nodes meets the filtering criteria.
|
||
*/
|
||
TreeNode.prototype.filter = function (filterCriteria) {
|
||
var res = false,
|
||
childNodes = this.items.asArray(),
|
||
i,
|
||
regExp,
|
||
partialRes;
|
||
|
||
for (i = 0; i < childNodes.length; i += 1) {
|
||
childNodes[i].setVisible(partialRes = childNodes[i].filter(filterCriteria));
|
||
res = res || partialRes;
|
||
}
|
||
if (!res) {
|
||
regExp = new RegExp(filterCriteria, "i");
|
||
if (regExp.test(this.label)) {
|
||
return true;
|
||
}
|
||
}
|
||
return res;
|
||
};
|
||
/**
|
||
* Define then events for the object.
|
||
* @chainable
|
||
*/
|
||
TreeNode.prototype.defineEvents = function () {
|
||
var that;
|
||
|
||
TreeNode.superclass.prototype.defineEvents.call(this);
|
||
if (this.dom.title) {
|
||
that = this;
|
||
this.addEvent('click').listen(this.dom.title, function (e) {
|
||
var root = that.getRoot(),
|
||
panel = root.parent;
|
||
|
||
e.preventDefault();
|
||
if (typeof that.onClick === 'function') {
|
||
that.onClick();
|
||
}
|
||
if (panel instanceof PMUI.panel.TreePanel && typeof panel.onNodeClick === 'function') {
|
||
panel.onNodeClick(panel, that);
|
||
}
|
||
that.toggleCollapsing();
|
||
});
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the node's html.
|
||
* @return {HTMLELement}
|
||
*/
|
||
TreeNode.prototype.createHTML = function () {
|
||
var nodeElement,
|
||
title,
|
||
label,
|
||
icon,
|
||
childrenList,
|
||
elbow;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
html = PMUI.createHTMLElement(this.elementTag || "div");
|
||
html.id = this.id;
|
||
PMUI.linkToPMUIObject(html, this);
|
||
this.html = html;
|
||
this.actionHTML = html;
|
||
this.applyStyle();
|
||
|
||
nodeElement = this.html;
|
||
nodeElement.className = 'pmui-treepanel-node';
|
||
nodeElement.id = this.id;
|
||
title = PMUI.createHTMLElement('a');
|
||
title.className = 'pmui-treepanel-node-title';
|
||
title.href = '#';
|
||
elbow = PMUI.createHTMLElement('b');
|
||
elbow.className = 'pmui-treepanel-node-elbow';
|
||
elbow.innerHTML = ' ';
|
||
label = PMUI.createHTMLElement('span');
|
||
label.className = 'pmui-treepanel-node-label';
|
||
icon = PMUI.createHTMLElement('i');
|
||
icon.className = 'pmui-treepanel-node-icon';
|
||
icon.innerHTML = ' ';
|
||
childrenList = PMUI.createHTMLElement('ul');
|
||
childrenList.className = 'pmui-treepanel-list';
|
||
|
||
this.actionHTML = title;
|
||
|
||
title.appendChild(elbow);
|
||
title.appendChild(icon);
|
||
title.appendChild(label);
|
||
nodeElement.appendChild(title);
|
||
nodeElement.appendChild(childrenList);
|
||
|
||
this.dom.nodeElement = nodeElement;
|
||
this.dom.title = title;
|
||
this.dom.label = label;
|
||
this.dom.icon = icon;
|
||
this.containmentArea = childrenList;
|
||
|
||
this.html = nodeElement;
|
||
|
||
this.updateNodeTypeClass();
|
||
|
||
this.setParent(this.parent)
|
||
.setSterility(this.sterile)
|
||
.setLabel(this.label)
|
||
.setNodeClass(this.nodeClass);
|
||
if (this.items.getSize() > 0) {
|
||
this.paintItems(this.items.asArray().slice(0));
|
||
}
|
||
if (this.collapsed) {
|
||
this.collapse();
|
||
} else {
|
||
this.expand();
|
||
}
|
||
|
||
this.style.applyStyle();
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.item.TreeNode', TreeNode);
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.item.ListItem
|
||
*/
|
||
var ListItem = function (settings) {
|
||
ListItem.superclass.call(this, settings);
|
||
this.text = null;
|
||
this.iconClass = null;
|
||
this.toolbar = null;
|
||
this.dom = {};
|
||
this.actions = [];
|
||
this.visibleIcon = null;
|
||
this.data = null;
|
||
this.textDataBind = null;
|
||
this.onClick = null;
|
||
ListItem.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Item', ListItem);
|
||
|
||
ListItem.prototype.type = "ListItem";
|
||
|
||
ListItem.prototype.init = function (settings) {
|
||
var defaults = {
|
||
elementTag: 'li',
|
||
text: '[list-item]',
|
||
actions: [],
|
||
iconClass: null,
|
||
visibleIcon: false,
|
||
data: {},
|
||
textDataBind: null,
|
||
onClick: null
|
||
};
|
||
|
||
this.toolbar = new PMUI.toolbar.Toolbar({
|
||
style: {
|
||
cssClasses: ['pmui-listitem-actions']
|
||
}
|
||
});
|
||
|
||
this.data = new PMUI.data.DataField();
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setTextDataBind(defaults.textDataBind)
|
||
.setElementTag(defaults.elementTag)
|
||
.setText(defaults.text)
|
||
.setIconClass(defaults.iconClass)
|
||
.setActions(defaults.actions)
|
||
.setData(defaults.data)
|
||
.setOnClickHandler(defaults.onClick);
|
||
|
||
if (defaults.visibleIcon) {
|
||
this.showIcon();
|
||
} else {
|
||
this.hideIcon();
|
||
}
|
||
};
|
||
|
||
ListItem.prototype.setOnClickHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setOnClickHandler(): The parameter must be or null.");
|
||
}
|
||
this.onClick = handler;
|
||
return this;
|
||
};
|
||
|
||
ListItem.prototype.onClickHandler = function () {
|
||
var that = this;
|
||
|
||
return function () {
|
||
if (typeof that.onClick === 'function') {
|
||
that.onClick(that);
|
||
}
|
||
};
|
||
};
|
||
|
||
ListItem.prototype.setTextDataBind = function (textDataBind) {
|
||
if (textDataBind !== null && typeof textDataBind !== 'string') {
|
||
throw new Error("setTextDataBind(): the parameter must be a string or null.");
|
||
}
|
||
this.textDataBind = textDataBind;
|
||
return this.bindData();
|
||
};
|
||
|
||
ListItem.prototype.bindData = function () {
|
||
var data = this.data.getRecord();
|
||
|
||
this.setText(data[this.textDataBind] || this.text || "");
|
||
|
||
return this;
|
||
};
|
||
|
||
ListItem.prototype.setData = function (data) {
|
||
var key;
|
||
|
||
if (data instanceof PMUI.data.DataField) {
|
||
this.data = data;
|
||
} else if (typeof data === 'object') {
|
||
this.data.clear();
|
||
for (key in data) {
|
||
this.data.addAttribute(key, data[key]);
|
||
}
|
||
} else {
|
||
throw new Error("setData(): it only accepts a JSON object o an instance of PMUI.data.DataField as parameter.");
|
||
}
|
||
this.bindData();
|
||
|
||
return this;
|
||
};
|
||
|
||
ListItem.prototype.clearActions = function () {
|
||
this.toolbar.clearItems();
|
||
return this;
|
||
};
|
||
|
||
ListItem.prototype.addAction = function (action) {
|
||
var that = this,
|
||
aux,
|
||
handler;
|
||
|
||
aux = action.handler || null;
|
||
if (!(aux === null || typeof aux === 'function')) {
|
||
throw new Error("addAction(): The parameter's \"'handler\" property must be a function or null or not be specified.");
|
||
}
|
||
|
||
handler = aux ? function () {
|
||
if (aux) {
|
||
aux.call(that, that, this);
|
||
}
|
||
} : null;
|
||
|
||
action.action = handler;
|
||
|
||
if (action instanceof PMUI.toolbar.ToolbarAction) {
|
||
action.setAction(handler);
|
||
} else if (typeof action === 'object') {
|
||
action.action = handler;
|
||
}
|
||
|
||
this.toolbar.addItem(action);
|
||
|
||
return this;
|
||
};
|
||
|
||
ListItem.prototype.setActions = function (actions) {
|
||
var i;
|
||
|
||
if (!jQuery.isArray(actions)) {
|
||
throw new Error("setActions(): The parameter must be an array.");
|
||
}
|
||
this.clearActions();
|
||
for (i = 0; i < actions.length; i += 1) {
|
||
this.addAction(actions[i]);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListItem.prototype.setIconClass = function (iconClass) {
|
||
if (!(iconClass === null || typeof iconClass === 'string')) {
|
||
throw new Error("setIconClass(): the parameter must be a string or null.");
|
||
}
|
||
this.iconClass = iconClass;
|
||
if (this.dom.iconContainer) {
|
||
this.dom.iconContainer.className = 'pmui-listitem-icon ' + (iconClass || "");
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListItem.prototype.hideIcon = function () {
|
||
this.visibleIcon = false;
|
||
if (this.dom.iconContainer) {
|
||
this.dom.iconContainer.style.display = 'none';
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListItem.prototype.showIcon = function () {
|
||
this.visibleIcon = true;
|
||
if (this.dom.iconContainer) {
|
||
this.dom.iconContainer.style.display = '';
|
||
}
|
||
return this;
|
||
}
|
||
|
||
ListItem.prototype.setText = function (text) {
|
||
if (typeof text !== 'string') {
|
||
throw new Error("setText(): the parameter must be a string.");
|
||
}
|
||
this.text = text;
|
||
if (this.dom.textContainer) {
|
||
this.dom.textContainer.textContent = text;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ListItem.prototype.getData = function () {
|
||
return this.data.getRecord();
|
||
};
|
||
|
||
ListItem.prototype.defineEvents = function () {
|
||
return this;
|
||
};
|
||
|
||
ListItem.prototype.createHTML = function () {
|
||
var textContainer,
|
||
iconContainer,
|
||
that = this;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
ListItem.superclass.prototype.createHTML.call(this);
|
||
textContainer = PMUI.createHTMLElement('div');
|
||
textContainer.className = 'pmui-listitem-text';
|
||
iconContainer = PMUI.createHTMLElement('i');
|
||
iconContainer.className = 'pmui-listitem-icon';
|
||
|
||
this.dom.textContainer = textContainer;
|
||
this.dom.iconContainer = iconContainer;
|
||
|
||
this.html.appendChild(iconContainer);
|
||
this.html.appendChild(textContainer);
|
||
this.html.appendChild(this.toolbar.getHTML());
|
||
|
||
this.setText(this.text);
|
||
|
||
if (this.visibleIcon) {
|
||
this.showIcon();
|
||
} else {
|
||
this.hideIcon();
|
||
}
|
||
|
||
this.addEvent('click').listen(this.html, function (e) {
|
||
var parent = that.getParent();
|
||
e.stopPropagation();
|
||
if (typeof that.onClick === 'function') {
|
||
that.onClick(that);
|
||
}
|
||
if (parent) {
|
||
parent.onItemClickHandler(that);
|
||
}
|
||
});
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.item.ListItem', ListItem);
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.proxy.Proxy
|
||
* Defines the proxy functionality to persist data
|
||
* @abstract
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of this class
|
||
* @param {Object} options
|
||
*
|
||
* @cfg {Object} data Object that will be sent through the proxy
|
||
*/
|
||
var Proxy = function (options) {
|
||
/**
|
||
* Data object used to send/receive through proxy
|
||
* @type {Object}
|
||
*/
|
||
this.data = null;
|
||
Proxy.prototype.init.call(this, options);
|
||
};
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
Proxy.prototype.type = "Proxy";
|
||
|
||
/**
|
||
* Defines the object's family
|
||
* @type {String}
|
||
*/
|
||
Proxy.prototype.family = "Proxy";
|
||
|
||
/**
|
||
* @private
|
||
* Initilizes the object with the default values
|
||
* @param {Object} options
|
||
*/
|
||
Proxy.prototype.init = function (options) {
|
||
var defaults = {
|
||
data: null
|
||
};
|
||
|
||
jQuery.extend(true, defaults, options);
|
||
this.setData(defaults.data);
|
||
};
|
||
|
||
/**
|
||
* Sets the data
|
||
* @param {Object} data Object to be sent
|
||
*/
|
||
Proxy.prototype.setData = function (data) {
|
||
this.data = data;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the data related to this class
|
||
* @return {Object}
|
||
*/
|
||
Proxy.prototype.getData = function () {
|
||
return this.data;
|
||
};
|
||
|
||
/**
|
||
* @abstract
|
||
* Sends the data to the target
|
||
*/
|
||
Proxy.prototype.send = function () {
|
||
};
|
||
|
||
/**
|
||
* @abstract
|
||
* Receives the data from the target
|
||
*/
|
||
Proxy.prototype.receive = function () {
|
||
};
|
||
|
||
PMUI.extendNamespace("PMUI.proxy.Proxy", Proxy);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = Proxy;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.proxy.RestProxy
|
||
* @extend PMUI.proxy.Proxy
|
||
*
|
||
* How used the class
|
||
* The {@link PMUI.proxy.RestClient Restclient} class encapsulate all the funcionality about the communicate
|
||
* with the server.
|
||
*
|
||
* @example
|
||
* restclient = new PMUI.proxy.RestProxy({
|
||
* url: "url.php",
|
||
* method: "GET",
|
||
* data: {},
|
||
* dataType: "json",
|
||
* success: function () {
|
||
* ...
|
||
* },
|
||
* failure: function () {
|
||
* ...
|
||
* },
|
||
* complete: function() {
|
||
* ...
|
||
* }
|
||
* });
|
||
*
|
||
*
|
||
* @constructor
|
||
* Creates a new component
|
||
* @param {Object} [settings] settings The configuration options are specified on the config options:
|
||
*
|
||
* @cfg {String} [url=""] The url property defines the target for the RestClient.
|
||
* @cfg {String} method
|
||
* The available methods to consume are the follow:
|
||
*
|
||
* 'create', 'read', 'update', 'delete'
|
||
*
|
||
* These have a directly relation to:
|
||
*
|
||
* 'create': 'POST',
|
||
* 'read' : 'GET',
|
||
* 'update': 'PUT',
|
||
* 'delete': 'DELETE'
|
||
*
|
||
* Based in the {@link RestClient RestClient} library
|
||
* @cfg {Object} data Object that will be sent through the proxy.
|
||
* @cfg {String} [dataType='json'] The available options are the following sentences:
|
||
*
|
||
* json: 'application/json',
|
||
* plain: 'text/plain',
|
||
* form: 'application/x-www-form-urlencoded',
|
||
* html: 'text/html'
|
||
*
|
||
* @cfg {String} [authorizationType= "none"] The options availables for the property:
|
||
*
|
||
* "none"
|
||
* "basic"
|
||
* "oauth2"
|
||
*
|
||
* @cfg {Boolean} [authorizationOAuth=false] For enable the communicate between client-server
|
||
* through Oauth protocol the property must to be true
|
||
*
|
||
*/
|
||
var RestProxy = function (options) {
|
||
RestProxy.superclass.call(this, options);
|
||
this.url = null;
|
||
this.method = null;
|
||
this.rc = null;
|
||
this.data = null;
|
||
RestProxy.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.proxy.Proxy', RestProxy);
|
||
/**
|
||
* @property {String}
|
||
* @readonly
|
||
*/
|
||
RestProxy.prototype.type = "RestProxy";
|
||
RestProxy.prototype.init = function (options) {
|
||
var defaults = {
|
||
url: null,
|
||
method: 'GET',
|
||
data: {},
|
||
dataType: 'json',
|
||
authorizationType: 'none',
|
||
authorizationOAuth: false,
|
||
success: function () {
|
||
},
|
||
failure: function () {
|
||
},
|
||
complete: function () {
|
||
}
|
||
};
|
||
jQuery.extend(true, defaults, options);
|
||
this.setRestClient()
|
||
.setUrl(defaults.url)
|
||
.setAuthorizationOAuth(defaults.authorizationOAuth)
|
||
.setMethod(defaults.method)
|
||
.setData(defaults.data)
|
||
.setDataType(defaults.dataType)
|
||
.setSuccessAction(defaults.success)
|
||
.setFailureAction(defaults.failure)
|
||
.setCompleteAction(defaults.complete);
|
||
};
|
||
|
||
/**
|
||
* Creates an instance of the {@link RestClient ResClient} and
|
||
* stores the object inside of {@link RestProxy#rc rc property}
|
||
*/
|
||
RestProxy.prototype.setRestClient = function () {
|
||
if (this.rc instanceof RestClient === false) {
|
||
this.rc = new RestClient();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the url that will be used for send or get the data
|
||
* from server, It's a basic element for {@link RestClient RestClient}
|
||
* @param {String} url A string that represents the connection between
|
||
* Client and server
|
||
*
|
||
*
|
||
*/
|
||
RestProxy.prototype.setUrl = function (url) {
|
||
this.url = url;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the OAuth protocol to 'false' or 'true' for enable or disable the property.
|
||
*
|
||
* //Example
|
||
* obj = new PMUI.proxy.RestProxy();
|
||
* obj.setAuthorizationOAuth(true);
|
||
*
|
||
* @param {Boolean} option Defines the boolean option
|
||
*/
|
||
RestProxy.prototype.setAuthorizationOAuth = function (option) {
|
||
if (typeof option === 'boolean') {
|
||
this.rc.setSendBearerAuthorization(option);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* This method is useful for update the current action.
|
||
* The available methods to consume are the follow:
|
||
* 'create', 'read', 'update', 'delete'
|
||
* These have a directly relation to:
|
||
* 'create': 'POST',
|
||
* 'read' : 'GET',
|
||
* 'update': 'PUT',
|
||
* 'delete': 'DELETE'
|
||
* Based in the {@link RestClient RestClient} library
|
||
* @param {String} A string that reporesents
|
||
*/
|
||
RestProxy.prototype.setMethod = function (method) {
|
||
this.method = method;
|
||
return this;
|
||
};
|
||
RestProxy.prototype.setSuccessAction = function (action) {
|
||
RestProxy.prototype.success = action;
|
||
return this;
|
||
};
|
||
RestProxy.prototype.setFailureAction = function (action) {
|
||
RestProxy.prototype.failure = action;
|
||
return this;
|
||
};
|
||
RestProxy.prototype.setCompleteAction = function (action) {
|
||
RestProxy.prototype.complete = action;
|
||
return this;
|
||
};
|
||
/**
|
||
*
|
||
* @param {Object} data Data for send to server
|
||
* @return {PMUI.proxy.RestProxy} this The current component
|
||
*
|
||
*/
|
||
RestProxy.prototype.setData = function (data) {
|
||
this.data = data;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the Data type used for request data.
|
||
* the types availables for the methods are the following:
|
||
*
|
||
* json: 'application/json',
|
||
* plain: 'text/plain',
|
||
* form: 'application/x-www-form-urlencoded',
|
||
* html: 'text/html'
|
||
*
|
||
* //For example
|
||
* restclient = new PMUI,proxy.RestProxy();
|
||
* restclient.setDataType("json");
|
||
* ...
|
||
*
|
||
* @param {String} dataType Type
|
||
*/
|
||
RestProxy.prototype.setDataType = function (dataType) {
|
||
this.rc.setDataType(dataType);
|
||
return this;
|
||
};
|
||
RestProxy.prototype.setCredentials = function (usr, pass) {
|
||
this.rc.setBasicCredentials(usr, pass);
|
||
return this;
|
||
};
|
||
RestProxy.prototype.setContentType = function () {
|
||
this.rc.setContentType();
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the authorization type and credentials for the RestClient.
|
||
*
|
||
* The options availables about authorization types are:
|
||
*
|
||
* 'none'
|
||
* 'basic'
|
||
* 'oauth2'
|
||
*
|
||
* The credentials must have two keys: The username and password
|
||
*
|
||
* //For example
|
||
* restclient = new PMUI.proxy.RestProxy();
|
||
* restclient.setAuthorizationType('oauth2', credentials);
|
||
*
|
||
* Is possible sets the property while instances the class like to sentence below:
|
||
*
|
||
* restclient = new PMUI.proxy.RestProxy({
|
||
* ...
|
||
* authorizationOAuth: true
|
||
* ...
|
||
* });
|
||
*
|
||
*
|
||
* @param {Object} type Authorization type
|
||
* @param {Object} credentials These are the keys that represent the username and password
|
||
*/
|
||
RestProxy.prototype.setAuthorizationType = function (type, credentials) {
|
||
this.rc.setAuthorizationType(type);
|
||
switch (type) {
|
||
case 'none':
|
||
break;
|
||
case 'basic':
|
||
this.rc.setBasicCredentials(credentials.client, credentials.secret);
|
||
break;
|
||
case 'oauth2':
|
||
this.rc.setAccessToken(credentials);
|
||
break;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Send data to server using POST method from RestClient
|
||
* @param {Object} settings Configuration parameters
|
||
*
|
||
* //For example
|
||
* this.post({
|
||
* url: "url.php",
|
||
* data: {
|
||
* grant_type: "authorization_code",
|
||
* code: keys.authorizedCode
|
||
* },
|
||
* success: function (xhr, response) {
|
||
* console.log(response);
|
||
* },
|
||
* failure: function (xhr, response) {
|
||
* console.log(response);
|
||
* },
|
||
* complete: function (xhr, response) {
|
||
* console.error(response);
|
||
* }
|
||
* });
|
||
*
|
||
*/
|
||
RestProxy.prototype.post = function (settings) {
|
||
var that = this;
|
||
if (settings !== undefined) {
|
||
that.init(settings);
|
||
}
|
||
if (this.rc) {
|
||
that.rc.postCall({
|
||
url: that.url,
|
||
id: that.uid,
|
||
data: that.data,
|
||
success: function (xhr, response) {
|
||
that.success.call(that, xhr, response);
|
||
},
|
||
failure: function (xhr, response) {
|
||
that.failure.call(that, xhr, response);
|
||
},
|
||
complete: function (xhr, response) {
|
||
that.complete.call(that, xhr, response);
|
||
}
|
||
});
|
||
that.rc.setSendBearerAuthorization(false);
|
||
|
||
} else {
|
||
throw new Error("the RestClient was not defined, please verify the property 'rc' for continue.");
|
||
}
|
||
};
|
||
/**
|
||
* Updates data from the server using UPDATE method from RestClient
|
||
* @param {Object} settings
|
||
* If it necessary is possible overwrite all the data instantiated on the RestClient
|
||
*
|
||
* //For example
|
||
* this.update({
|
||
* url: "url.php",
|
||
* authorizationOAuth: true,
|
||
* success: function (xhr, response) {
|
||
* console.log(response);
|
||
* },
|
||
* failure: function (xhr, response) {
|
||
* console.error(response);
|
||
* },
|
||
* complete: function (xhr, response) {
|
||
* console.error(response);
|
||
* }
|
||
* });
|
||
*
|
||
*/
|
||
RestProxy.prototype.update = function (settings) {
|
||
var that = this;
|
||
|
||
if (settings !== undefined) {
|
||
that.init(settings);
|
||
}
|
||
if (this.rc) {
|
||
this.rc.putCall({
|
||
url: this.url,
|
||
id: this.uid,
|
||
data: this.data,
|
||
success: function (xhr, response) {
|
||
that.success.call(this, xhr, response);
|
||
},
|
||
failure: function (xhr, response) {
|
||
that.failure.call(this, xhr, response);
|
||
},
|
||
complete: function (xhr, response) {
|
||
that.complete.call(that, xhr, response);
|
||
}
|
||
});
|
||
} else {
|
||
throw new Error("the RestClient was not defined, please verify the property 'rc' for continue.");
|
||
}
|
||
};
|
||
/**
|
||
* Gets data from the server using GET method from RestClient
|
||
* @param {Object} settings
|
||
* If it necessary is possible overwrite all the data instantiated on the RestClient
|
||
*
|
||
* //For example
|
||
* this.get({
|
||
* url: "url.php",
|
||
* authorizationOAuth: true,
|
||
* success: function (xhr, response) {
|
||
* console.log(response);
|
||
* },
|
||
* failure: function (xhr, response) {
|
||
* console.error(response);
|
||
* },
|
||
* complete: function (xhr, response) {
|
||
* console.error(response);
|
||
* }
|
||
* });
|
||
*
|
||
*/
|
||
RestProxy.prototype.get = function (settings) {
|
||
var that = this;
|
||
|
||
if (settings !== undefined) {
|
||
that.init(settings);
|
||
}
|
||
if (this.rc) {
|
||
that.rc.getCall({
|
||
url: that.url,
|
||
id: that.uid,
|
||
data: that.data,
|
||
success: function (xhr, response) {
|
||
that.success.call(that, xhr, response);
|
||
},
|
||
failure: function (xhr, response) {
|
||
that.failure.call(that, xhr, response);
|
||
},
|
||
complete: function (xhr, response) {
|
||
that.complete.call(that, xhr, response);
|
||
}
|
||
});
|
||
that.rc.setSendBearerAuthorization(false);
|
||
|
||
} else {
|
||
throw new Error("the RestClient was not defined, please verify the property 'rc' for continue.");
|
||
}
|
||
};
|
||
/**
|
||
* Removes data using DELETE method from RestClient
|
||
* @param {Object} settings
|
||
* If it necessary is possible overwrite all the data instantiated on the RestClient
|
||
*
|
||
* //For example
|
||
* this.remove({
|
||
* url: "url.php",
|
||
* authorizationOAuth: true,
|
||
* success: function (xhr, response) {
|
||
* console.log(response);
|
||
* },
|
||
* failure: function (xhr, response) {
|
||
* console.error(response);
|
||
* },
|
||
* complete: function (xhr, response) {
|
||
* console.error(response);
|
||
* }
|
||
* });
|
||
*
|
||
*/
|
||
RestProxy.prototype.remove = function (settings) {
|
||
var that = this;
|
||
|
||
if (settings !== undefined) {
|
||
that.init(settings);
|
||
}
|
||
if (this.rc) {
|
||
this.rc.deleteCall({
|
||
url: this.url,
|
||
id: this.uid,
|
||
data: this.data,
|
||
success: function (xhr, response) {
|
||
that.success.call(this, xhr, response);
|
||
},
|
||
failure: function (xhr, response) {
|
||
that.failure.call(this, xhr, response);
|
||
},
|
||
complete: function (xhr, response) {
|
||
that.complete.call(that, xhr, response);
|
||
}
|
||
});
|
||
} else {
|
||
throw new Error("the RestClient was not defined, please verify the property for continue.");
|
||
}
|
||
};
|
||
/**
|
||
* This is the callback for {@link RestClient RestClient} and it will be actived
|
||
* and executed when the {@link RestClient RestClient} petition was success.
|
||
* @param {Object} xhr
|
||
* @param {Object} response
|
||
*/
|
||
RestProxy.prototype.success = function (xhr, response) {
|
||
};
|
||
/**
|
||
* If something happend with the connection or maybe the server is
|
||
* down, this callback will be executed
|
||
* @param {Object} xhr
|
||
* @param {Object} response
|
||
*/
|
||
RestProxy.prototype.failure = function (xhr, response) {
|
||
};
|
||
/**
|
||
* This is the callback for {@link RestClient RestClient} and it will be actived
|
||
* and executed when the {@link RestClient RestClient} petition finishes.
|
||
* @param {Object} xhr
|
||
* @param {Object} response
|
||
*/
|
||
RestProxy.prototype.complete = function (xhr, response) {
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.proxy.RestProxy', RestProxy);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = RestProxy;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.event.Event
|
||
* Handles the events generated in the PMUI library
|
||
* @abstract
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of class
|
||
* @param {Object} options
|
||
*
|
||
* @cfg {Object} element Defines the HTMLElement
|
||
* @cfg {Function} handler Defines the callback Function to be executed
|
||
* @cfg {PMUI.event.Action} action Defines an Action to be used to handle the callback
|
||
* @cfg {String} name Event name
|
||
*/
|
||
var Event = function (options) {
|
||
/**
|
||
* Stores the HTMLElement associated
|
||
* @type {Object}
|
||
*/
|
||
this.element = null;
|
||
/**
|
||
* Stores the callback function to be executed
|
||
* @type {Function}
|
||
*/
|
||
this.handler = null;
|
||
/**
|
||
* Stores the selector for delegated event listeners.
|
||
* @type {String}
|
||
*/
|
||
this.selector = null;
|
||
/**
|
||
* Event name
|
||
* @type {String}
|
||
*/
|
||
this.eventName = null;
|
||
Event.prototype.init.call(this, options);
|
||
};
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
Event.prototype.type = "Event";
|
||
|
||
/**
|
||
* Defines the object's family
|
||
* @type {String}
|
||
*/
|
||
Event.prototype.family = "Event";
|
||
|
||
/**
|
||
* @private
|
||
* Initializes the object with default options
|
||
* @param {Object} options
|
||
*/
|
||
Event.prototype.init = function (options) {
|
||
var defaults = {
|
||
handler: function (scope) {
|
||
}
|
||
};
|
||
jQuery.extend(true, defaults, options);
|
||
if (defaults.action && defaults.action instanceof PMUI.event.Action) {
|
||
this.setHandler(defaults.action.handler);
|
||
} else {
|
||
this.setHandler(defaults.handler);
|
||
}
|
||
this.setElement(defaults.element)
|
||
.setEventName(defaults.name);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the HTML Element
|
||
* @param {Object} element [description]
|
||
*/
|
||
Event.prototype.setElement = function (element) {
|
||
this.element = element;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the callback function
|
||
* @param {Function} fn
|
||
*/
|
||
Event.prototype.setHandler = function (fn) {
|
||
if (typeof fn === 'function') {
|
||
this.handler = fn;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the selector to be used for delegated event handlers.
|
||
* @param {String} selector
|
||
* @chainable
|
||
*/
|
||
Event.prototype.setSelector = function (selector) {
|
||
if (typeof selector === 'string') {
|
||
this.selector = selector;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the event name
|
||
* @param {String} name
|
||
*/
|
||
Event.prototype.setEventName = function (name) {
|
||
this.eventName = name;
|
||
return this;
|
||
};
|
||
/**
|
||
* Add a handler to listen for a event with delegation.
|
||
* @param {HTMLElement} parentElement The parent element whose child elements the event will be delegate to.
|
||
* @param {String} selector A valid jQuery selector to filter the descendants of the selected
|
||
* elements that trigger the event.
|
||
* @param {Function} handler A function to execute when the event is triggered.
|
||
* @chainable
|
||
*/
|
||
Event.prototype.listenWithDelegation = function (parentElement, selector, handler) {
|
||
var handlerFunction;
|
||
if (handler instanceof PMUI.event.Action) {
|
||
handlerFunction = handler.handler;
|
||
} else {
|
||
handlerFunction = handler;
|
||
}
|
||
$(parentElement).on(this.eventName, selector, handler);
|
||
this.setHandler(handler).setElement(parentElement).setSelector(selector);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* @abstract
|
||
* Defines the way to listen the event (jquery)
|
||
* @param {HTMLElement} element [description]
|
||
* @param {Function} handler [description]
|
||
*/
|
||
Event.prototype.listen = function (element, handler) {
|
||
var handlerFunction;
|
||
if (handler instanceof PMUI.event.Action) {
|
||
handlerFunction = handler.handler;
|
||
} else {
|
||
handlerFunction = handler;
|
||
}
|
||
jQuery(element).on(this.eventName, handlerFunction);
|
||
this.setHandler(handlerFunction).setElement(element);
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes the event listener.
|
||
* @chainable
|
||
*/
|
||
Event.prototype.unlisten = function () {
|
||
if (this.selector) {
|
||
jQuery(this.element).off(this.eventName, this.selector, this.handler);
|
||
} else {
|
||
jQuery(this.element).off(this.eventName, this.handler);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.event.Event', Event);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Event;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.event.EventFactory
|
||
* @extend PMUI.util.Factory
|
||
* Extends the factory class to produce Events instances
|
||
*
|
||
* @constructor
|
||
* Creates a new instance od the class
|
||
*/
|
||
var EventFactory = function () {
|
||
EventFactory.superclass.call(this);
|
||
EventFactory.prototype.init.call(this);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.util.Factory', EventFactory);
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
EventFactory.prototype.type = 'EventFactory';
|
||
|
||
/**
|
||
* @private
|
||
* Define the event types supported
|
||
* @type {Object}
|
||
*/
|
||
EventFactory.prototype.eventTypes = {
|
||
'click': 'mouse',
|
||
'mousedown': 'mouse',
|
||
'mouseup': 'mouse',
|
||
'mousemove': 'mouse',
|
||
'mouseover': 'mouse',
|
||
'mouseout': "mouse",
|
||
'mouseenter': "mouse",
|
||
'mouseleave': "mouse",
|
||
'dblclick': "mouse",
|
||
'drag': 'mouse',
|
||
'drop': 'mouse',
|
||
'resize': 'mouse',
|
||
'rightclick': 'mouse',
|
||
'contextmenu': 'mouse',
|
||
'blur': 'form',
|
||
'change': 'form',
|
||
'focus': 'form',
|
||
'select': 'form',
|
||
'submit': 'form',
|
||
'keyup': 'keyboard',
|
||
'keydown': 'keyboard',
|
||
'keypress': 'keyboard'
|
||
};
|
||
|
||
/**
|
||
* @private
|
||
* Initializes the object with default values
|
||
*/
|
||
EventFactory.prototype.init = function () {
|
||
var defaults = {
|
||
products: {
|
||
"mouse": PMUI.event.MouseEvent,
|
||
"form": PMUI.event.FormEvent,
|
||
"keyboard": PMUI.event.KeyboardEvent,
|
||
"event": PMUI.event.Event
|
||
},
|
||
defaultProduct: "event"
|
||
};
|
||
this.setProducts(defaults.products)
|
||
.setDefaultProduct(defaults.defaultProduct);
|
||
};
|
||
|
||
/**
|
||
* Overwrite the make function to accept strings
|
||
* @param {Object/String} type
|
||
* @return {PMUI.event.Event}
|
||
*/
|
||
EventFactory.prototype.make = function (type) {
|
||
var eventInstance,
|
||
eventType;
|
||
if (this.isValidClass(type)) {
|
||
eventInstance = type;
|
||
} else {
|
||
eventType = this.eventTypes[type] || 'event';
|
||
eventInstance = this.build(eventType, {name: type});
|
||
}
|
||
return eventInstance;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.event.EventFactory', EventFactory);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = EventFactory;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.event.MouseEvent
|
||
* @extend PMUI.event.Event
|
||
* Handles the events generated by the mouse
|
||
*
|
||
* @constructor
|
||
* Create a new instance
|
||
* @param {Object} options Constructor options
|
||
*
|
||
* @cfg {Object} element Defines the HTMLElement
|
||
* @cfg {Function} handler Defines the callback Function to be executed
|
||
* @cfg {PMUI.event.Action} action Defines an Action to be used to handle the callback
|
||
* @cfg {String} name Event name
|
||
*/
|
||
var MouseEvent = function (options) {
|
||
MouseEvent.superclass.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.event.Event', MouseEvent);
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
MouseEvent.prototype.type = "MouseEvent";
|
||
|
||
PMUI.extendNamespace('PMUI.event.MouseEvent', MouseEvent);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = MouseEvent;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.event.KeyboardEvent
|
||
* @extend PMUI.event.Event
|
||
* Handles the events generated by the mouse
|
||
*
|
||
* @constructor
|
||
* Create a new instance
|
||
* @param {Object} options Constructor options
|
||
*
|
||
* @cfg {Object} element Defines the HTMLElement
|
||
* @cfg {Function} handler Defines the callback Function to be executed
|
||
* @cfg {PMUI.event.Action} action Defines an Action to be used to handle the callback
|
||
* @cfg {String} name Event name
|
||
*/
|
||
var KeyboardEvent = function (options) {
|
||
KeyboardEvent.superclass.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.event.Event', KeyboardEvent);
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
KeyboardEvent.prototype.type = "KeyboardEvent";
|
||
|
||
PMUI.extendNamespace('PMUI.event.KeyboardEvent', KeyboardEvent);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = KeyboardEvent;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.event.FormEvent
|
||
* @extend PMUI.event.Event
|
||
* Handles the events generated by the mouse
|
||
*
|
||
* @constructor
|
||
* Create a new instance
|
||
* @param {Object} options Constructor options
|
||
*
|
||
* @cfg {Object} element Defines the HTMLElement
|
||
* @cfg {Function} handler Defines the callback Function to be executed
|
||
* @cfg {PMUI.event.Action} action Defines an Action to be used to handle the callback
|
||
* @cfg {String} name Event name
|
||
*/
|
||
var FormEvent = function (options) {
|
||
FormEvent.superclass.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.event.Event', FormEvent);
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
FormEvent.prototype.type = "FormEvent";
|
||
|
||
PMUI.extendNamespace('PMUI.event.FormEvent', FormEvent);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = FormEvent;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Core
|
||
* @extends PMUI.core.Element
|
||
*
|
||
* This class contains the common behavior of the main families of classes
|
||
* in the library
|
||
* This class should never be instantiated since its just an abstraction of
|
||
* properties that classes in the library share
|
||
*
|
||
* //e.g.
|
||
* //We will set the properties defined in this class, to a custom shape
|
||
* var customShape = new PMUI.draw.CustomShape({
|
||
* id : "someid",
|
||
* canvas : someCanvas //assuming there is a canvas instance
|
||
* style: { //style options regarding the objects
|
||
* cssProperties: {}, //These are the style properties we want the
|
||
* //object to have
|
||
* cssClasses: ["someclass"] //css classes that will be applied
|
||
* to the object
|
||
* },
|
||
* //now we set the width and height
|
||
* width : 30,
|
||
* height : 50,
|
||
* //and the coordinates we want the shape to be positioned
|
||
* x : 10,
|
||
* y : 5,
|
||
* //z-index of the element
|
||
* zOrder : 1,
|
||
* //set to true if we want to make it visible
|
||
* visible : true,
|
||
*
|
||
* });
|
||
*
|
||
* @constructor
|
||
* Creates an instance of the class
|
||
* @param {Object} options options for initializing the object
|
||
* @cfg {String} id id that will be assigned to the element
|
||
* @cfg {Object} [style={
|
||
* cssProperties: {},
|
||
* cssClasses: []
|
||
* }] style properties and classes that we want to assign to the element
|
||
* @cfg {PMUI.draw.Canvas} [canvas=null] canvas associated to the element
|
||
* @cfg {number} [width=0] width of the element
|
||
* @cfg {number} [height=0] height of the element
|
||
* @cfg {number} [x=0] x coordinate of the element
|
||
* @cfg {number} [y=0] y coordinate of the element
|
||
* @cfg {number} [zOrder=1] z-Index applied to the element
|
||
* @cfg {boolean} [visible=true] Determines whether an element will be visible
|
||
*/
|
||
|
||
var Core = function (options) {
|
||
Core.superclass.call(this, options);
|
||
|
||
/**
|
||
* Defines the canvas object
|
||
* @type {Object}
|
||
*/
|
||
this.canvas = null;
|
||
/**
|
||
* previous width of the Core
|
||
* @property {number}
|
||
*/
|
||
this.oldWidth = 0;
|
||
/**
|
||
* previous height of the Core
|
||
* @property {number}
|
||
*/
|
||
this.oldHeight = 0;
|
||
/**
|
||
* previous x coordinate of the Core
|
||
* @property {number}
|
||
*/
|
||
this.oldX = 0;
|
||
/**
|
||
* previous y coordinate of the Core
|
||
* @property {number}
|
||
*/
|
||
this.oldY = 0;
|
||
|
||
/**
|
||
* The x coordinate relative to the canvas
|
||
* @property {number}
|
||
* @deprecated Use {@link PMUI.draw.Core#getAbsoluteY} instead.
|
||
*/
|
||
this.absoluteX = 0;
|
||
/**
|
||
* The y coordinate relative to the canvas
|
||
* @property {number}
|
||
* @deprecated Use {@link PMUI.draw.Core#getAbsoluteX} instead.
|
||
*/
|
||
this.absoluteY = 0;
|
||
/**
|
||
* Previous x coordinate relative to the canvas
|
||
* @property {number}
|
||
*/
|
||
this.oldAbsoluteX = 0;
|
||
/**
|
||
* Previous y coordinate relative to the canvas
|
||
* @property {number}
|
||
*/
|
||
this.oldAbsoluteY = 0;
|
||
/**
|
||
* Zoom in x
|
||
* @property {number}
|
||
*/
|
||
this.zoomX = 0;
|
||
|
||
/**
|
||
* Zoom in y
|
||
* @property {number}
|
||
*/
|
||
this.zoomY = 0;
|
||
|
||
/**
|
||
* Width after the zoom
|
||
* @property {number}
|
||
*/
|
||
this.zoomWidth = 0;
|
||
|
||
/**
|
||
* Height after the zoom
|
||
* @property {number}
|
||
*/
|
||
this.zoomHeight = 0;
|
||
|
||
/**
|
||
* Saved options is a copy of the default initializer extended
|
||
* with the parameter 'options'
|
||
* @property {Object}
|
||
*/
|
||
this.savedOptions = {};
|
||
|
||
/**
|
||
* Defines the drag behavior object
|
||
* @type {PMUI.behavior.DragBehavior}
|
||
*/
|
||
this.drag = null;
|
||
|
||
Core.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Element', Core);
|
||
|
||
/**
|
||
* Denotes the type of the object
|
||
* @property {String}
|
||
*/
|
||
Core.prototype.type = "Core";
|
||
/**
|
||
* @abstract Method for applying the styles and preform tasks related to the
|
||
* view of the object
|
||
*/
|
||
Core.prototype.paint = function () {
|
||
};
|
||
|
||
|
||
/**
|
||
* Initializes the element with the options given
|
||
* @param {Object} options options for initializing the object
|
||
*/
|
||
Core.prototype.init = function (options) {
|
||
var defaults = {
|
||
zOrder: 1,
|
||
visible: true,
|
||
drag: "nodrag",
|
||
positionMode: "absolute"
|
||
};
|
||
$.extend(true, defaults, options);
|
||
this.setZOrder(defaults.zOrder)
|
||
.setVisible(defaults.visible)
|
||
// .setDragBehavior(defaults.drag)
|
||
.setCanvas(defaults.canvas);
|
||
};
|
||
|
||
Core.prototype.applyStyle = function () {
|
||
if (this.html) {
|
||
this.style.applyStyle();
|
||
|
||
this.style.addProperties({
|
||
display: this.visible ? this.display : "none",
|
||
position: "absolute", //TODO use this.positionMode instead,
|
||
left: this.zoomX,
|
||
top: this.zoomY,
|
||
width: this.zoomWidth,
|
||
height: this.zoomHeight,
|
||
zIndex: this.zOrder
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Core.prototype.createHTML = function () {
|
||
var properties;
|
||
if (!this.html) {
|
||
Core.superclass.prototype.createHTML.call(this);
|
||
this.defineEvents();
|
||
}
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Sets the position of the Core to a given pair of coordinates
|
||
* @param {Number} newX new x coordinate for the Core
|
||
* @param {Number} newY new y coordinate for the Core
|
||
* @chainable
|
||
*/
|
||
Core.prototype.setPosition = function (newX, newY) {
|
||
this.setX(newX);
|
||
this.setY(newY);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the dimension of the Core to a given width and height
|
||
* @param {Number} newWidth new width of the Core
|
||
* @param {Number} newHeight new height of the Core
|
||
* @chainable
|
||
*/
|
||
Core.prototype.setDimension = function (newWidth, newHeight) {
|
||
this.setWidth(newWidth);
|
||
this.setHeight(newHeight);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the x coordinate of the Core, returns true if successful
|
||
* @param {Number} newX
|
||
* @chainable
|
||
*/
|
||
Core.prototype.setX = function (newX) {
|
||
if (typeof newX === "number") {
|
||
newX = Math.round(newX);
|
||
this.x = newX;
|
||
if (this.canvas) {
|
||
this.zoomX = this.x * this.canvas.zoomFactor;
|
||
} else {
|
||
this.zoomX = this.x;
|
||
}
|
||
this.setAbsoluteX();
|
||
if (this.html) {
|
||
this.style.addProperties({left: this.zoomX});
|
||
}
|
||
} else {
|
||
throw new Error("setX : parameter newX is not a number");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the y coordinate of the Core, returns true if successful
|
||
* @param {Number} newY
|
||
* @chainable
|
||
*/
|
||
Core.prototype.setY = function (newY) {
|
||
if (typeof newY === "number") {
|
||
newY = Math.round(newY);
|
||
this.y = newY;
|
||
if (this.canvas) {
|
||
this.zoomY = this.y * this.canvas.zoomFactor;
|
||
} else {
|
||
this.zoomY = this.y;
|
||
}
|
||
this.setAbsoluteY();
|
||
if (this.html) {
|
||
this.style.addProperties({top: this.zoomY});
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the x coordinate of the Core relative to the canvas
|
||
* @chainable
|
||
* @deprecated absoluteX will be an in-moment property retrieved by the {PMUI.draw.Core#getAbsoluteX} method.
|
||
*/
|
||
Core.prototype.setAbsoluteX = function () {
|
||
if (!this.parent) {
|
||
this.absoluteX = this.zoomX;
|
||
} else {
|
||
this.absoluteX = this.zoomX + this.parent.absoluteX;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the value to an old X reference
|
||
* @param {Number} newX
|
||
* @chainable
|
||
*/
|
||
Core.prototype.setOldX = function (newX) {
|
||
if (typeof newX === "number") {
|
||
this.oldX = newX;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the value to an old y reference
|
||
* @param {Number} newY
|
||
* @chainable
|
||
*/
|
||
Core.prototype.setOldY = function (newY) {
|
||
if (typeof newY === "number") {
|
||
this.oldY = newY;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the y coordinate of the Core relative to the canvas
|
||
* @chainable
|
||
* @deprecated absoluteY will be an in-time generated property retrieved by the {PMUI.draw.Core#getAbsoluteY} getter.
|
||
*/
|
||
Core.prototype.setAbsoluteY = function () {
|
||
if (!this.parent) {
|
||
this.absoluteY = this.zoomY;
|
||
} else {
|
||
this.absoluteY = this.zoomY + this.parent.absoluteY;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the width of the Core, returns true if successful
|
||
* @param {Number} newWidth
|
||
* @chainable
|
||
*/
|
||
Core.prototype.setWidth = function (newWidth) {
|
||
var intPart;
|
||
if (typeof newWidth === "number" && newWidth >= 0) {
|
||
this.width = newWidth;
|
||
if (this.canvas) {
|
||
this.zoomWidth = this.width * this.canvas.zoomFactor;
|
||
intPart = Math.floor(this.zoomWidth);
|
||
this.zoomWidth = (this.zoomWidth % 2 === 0) ? intPart + 1 : intPart;
|
||
} else {
|
||
this.zoomWidth = this.width;
|
||
}
|
||
if (this.html) {
|
||
this.style.addProperties({width: this.zoomWidth});
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the height of the Core, returns true if successful
|
||
* @param {Number} newHeight
|
||
* @chainable
|
||
*/
|
||
Core.prototype.setHeight = function (newHeight) {
|
||
var intPart;
|
||
if (typeof newHeight === "number" && newHeight >= 0) {
|
||
this.height = newHeight;
|
||
if (this.canvas) {
|
||
this.zoomHeight = this.height * this.canvas.zoomFactor;
|
||
intPart = Math.floor(this.zoomHeight);
|
||
this.zoomHeight = (this.zoomHeight % 2 === 0) ? intPart + 1 : intPart;
|
||
} else {
|
||
this.zoomHeight = this.height;
|
||
}
|
||
if (this.html) {
|
||
this.style.addProperties({height: this.zoomHeight});
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the zOrder of this element
|
||
* @param {Number} newZOrder
|
||
* @chainable
|
||
*/
|
||
Core.prototype.setZOrder = function (newZOrder) {
|
||
if (typeof newZOrder === "number" && newZOrder > 0) {
|
||
this.zOrder = newZOrder;
|
||
if (this.html) {
|
||
this.style.addProperties({zIndex: this.zOrder});
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the canvas for the current object
|
||
* @param {PMUI.draw.Canvas} newCanvas
|
||
* @returns {PMUI.draw.Core}
|
||
*/
|
||
Core.prototype.setCanvas = function (newCanvas) {
|
||
if (newCanvas && newCanvas.family === "Canvas") {
|
||
this.canvas = newCanvas;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets this element to be visible or not if it has html, just sets the display
|
||
* property to inline or none
|
||
* @param {boolean} newVisible
|
||
* @chainable
|
||
*/
|
||
Core.prototype.setVisible = function (newVisible) {
|
||
|
||
if (typeof newVisible === "boolean") {
|
||
this.visible = newVisible;
|
||
if (this.html) {
|
||
if (newVisible) {
|
||
this.style.addProperties({display: "inline"});
|
||
} else {
|
||
this.style.addProperties({display: "none"});
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the id of this element and updates the html if there is such
|
||
* @param {String} newID
|
||
* @chainable
|
||
*/
|
||
Core.prototype.setID = function (newID) {
|
||
this.id = newID;
|
||
if (this.html) {
|
||
this.html.id = this.id;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the canvas related to this object
|
||
* @returns {PMUI.draw.Canvas}
|
||
*/
|
||
Core.prototype.getCanvas = function () {
|
||
return this.canvas;
|
||
};
|
||
|
||
/**
|
||
* Returns the x coordinate relative to the canvas of this object
|
||
* @return {Number}
|
||
*/
|
||
Core.prototype.getAbsoluteX = function () {
|
||
var x, oldDisplay;
|
||
if (this instanceof PMUI.draw.Canvas) {
|
||
return 0;
|
||
} else if (PMUI.isInDOM(this.html)) {
|
||
oldDisplay = this.html.style.display;
|
||
this.html.style.display = 'inline-block';
|
||
x = $(this.html).offset().left;
|
||
this.html.style.display = oldDisplay;
|
||
return x - $(this.canvas.html).offset().left;
|
||
} else {
|
||
return this.zoomX + this.parent.getAbsoluteX();
|
||
}
|
||
};
|
||
/**
|
||
* Returns the y coordinate relative to the canvas of this object
|
||
* @return {Number}
|
||
*/
|
||
Core.prototype.getAbsoluteY = function () {
|
||
var y, oldDisplay;
|
||
if (this instanceof PMUI.draw.Canvas) {
|
||
return 0;
|
||
} else if (PMUI.isInDOM(this.html)) {
|
||
oldDisplay = this.html.style.display;
|
||
this.html.style.display = 'inline-block';
|
||
y = $(this.html).offset().top;
|
||
this.html.style.display = oldDisplay;
|
||
return y - $(this.canvas.html).offset().top;
|
||
} else {
|
||
return this.zoomY + this.parent.getAbsoluteY();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Returns the style of this Core
|
||
* @return {PMUI.util.Style}
|
||
*/
|
||
Core.prototype.getStyle = function () {
|
||
return this.style;
|
||
};
|
||
|
||
/**
|
||
* Gets the x coordinate relative to the zoom scale
|
||
* @return {Number}
|
||
*/
|
||
Core.prototype.getZoomX = function () {
|
||
return this.zoomX;
|
||
};
|
||
|
||
/**
|
||
* Gets the y coordinate relative to the zoom scale
|
||
* @return {Number}
|
||
*/
|
||
Core.prototype.getZoomY = function () {
|
||
return this.zoomY;
|
||
};
|
||
|
||
/**
|
||
* Gets the width relative to the zoom scale
|
||
* @return {Number}
|
||
*/
|
||
Core.prototype.getZoomWidth = function () {
|
||
return this.zoomWidth;
|
||
};
|
||
|
||
/**
|
||
* Gets the height relative to the zoom scale
|
||
* @return {Number}
|
||
*/
|
||
Core.prototype.getZoomHeight = function () {
|
||
return this.zoomHeight;
|
||
};
|
||
|
||
/**
|
||
* Retrieves the previous value for coordinate x
|
||
* @return {Number}
|
||
*/
|
||
Core.prototype.getOldX = function () {
|
||
return this.oldX;
|
||
};
|
||
|
||
/**
|
||
* Retrieves the previous value for coordinate y
|
||
* @return {Number}
|
||
*/
|
||
Core.prototype.getOldY = function () {
|
||
return this.oldY;
|
||
};
|
||
|
||
/**
|
||
* Retrieves the previous value for width
|
||
* @return {Number}
|
||
*/
|
||
Core.prototype.getOldWidth = function () {
|
||
return this.oldWidth;
|
||
};
|
||
|
||
/**
|
||
* Retrieves the previous value for height
|
||
* @return {Number}
|
||
*/
|
||
Core.prototype.getOldHeight = function () {
|
||
return this.oldHeight;
|
||
};
|
||
|
||
/**
|
||
* Stringifies the basic data of this shape and the drag behavior of this shape
|
||
* @return {Object}
|
||
*/
|
||
Core.prototype.stringify = function () {
|
||
return {
|
||
id: this.getID(),
|
||
x: this.getX(),
|
||
y: this.getY(),
|
||
width: this.getWidth(),
|
||
height: this.getHeight(),
|
||
type: this.type,
|
||
style: this.getStyle().stringify(),
|
||
drag: this.savedOptions.drag
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Sets a valid drag behavior
|
||
* @param {Object} obj
|
||
*/
|
||
Core.prototype.setDragBehavior = function (obj) {
|
||
var factory = new PMUI.behavior.BehaviorFactory({
|
||
products: {
|
||
"customshapedrag": PMUI.behavior.CustomShapeDragBehavior,
|
||
"regulardrag": PMUI.behavior.RegularDragBehavior,
|
||
"connectiondrag": PMUI.behavior.ConnectionDragBehavior,
|
||
"connection": PMUI.behavior.ConnectionDragBehavior,
|
||
"nodrag": PMUI.behavior.NoDragBehavior
|
||
},
|
||
defaultProduct: "nodrag"
|
||
});
|
||
this.drag = factory.make(obj);
|
||
if (this.html && this.drag) {
|
||
this.drag.attachDragBehavior(this);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Functions that calculates the relative position over the canvas
|
||
* @param {Object} e jQuery Event
|
||
* @return {Object}
|
||
*/
|
||
Core.prototype.relativePoint = function (e) {
|
||
var auxX, auxY;
|
||
auxX = e.pageX - this.absoluteX;
|
||
auxY = e.pageY - this.absoluteY;
|
||
if (this.canvas) {
|
||
auxX += this.canvas.getLeftScroll();
|
||
auxY += this.canvas.getTopScroll();
|
||
auxX = Math.floor(auxX / this.canvas.zoomFactor);
|
||
auxY = Math.floor(auxY / this.canvas.zoomFactor);
|
||
}
|
||
return {
|
||
x: auxX,
|
||
y: auxY
|
||
};
|
||
};
|
||
|
||
/**
|
||
* JSON parser for creating PMDrawObjects
|
||
* @param {Object} json
|
||
*/
|
||
Core.prototype.parseJSON = function (json) {
|
||
this.initObject(json);
|
||
};
|
||
|
||
/**
|
||
* Number that represents the top direction
|
||
* @property {number}
|
||
*/
|
||
Core.prototype.TOP = 0;
|
||
/**
|
||
* Number that represents the right direction
|
||
* @property {number}
|
||
*/
|
||
Core.prototype.RIGHT = 1;
|
||
/**
|
||
* Number that represents the bottom direction
|
||
* @property {Number}
|
||
*/
|
||
Core.prototype.BOTTOM = 2;
|
||
/**
|
||
* Number that represents the left direction
|
||
* @property {Number}
|
||
*/
|
||
Core.prototype.LEFT = 3;
|
||
/**
|
||
* Number that represents horizontal direction
|
||
* @property {Number}
|
||
*/
|
||
Core.prototype.HORIZONTAL = 0;
|
||
/**
|
||
* Number that represents vertical direction
|
||
* @property {Number}
|
||
*/
|
||
Core.prototype.VERTICAL = 1;
|
||
/**
|
||
* Number of zoom scales available
|
||
* @property {Number}
|
||
*/
|
||
Core.prototype.ZOOMSCALES = 5;
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Core', Core);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Core;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.BehavioralElement
|
||
* Class that encapsulates the behavior of all elements that have container and
|
||
* drop behaviors attached to them.
|
||
* since this class inherits from {@link PMUI.draw.Core}, then the common behaviors
|
||
* and properties for all elements in the designer are also part of this class
|
||
* The purpose of this class is to encapsulate behaviors related to drop and
|
||
* containment of elements, so it shouldn't be instantiated, we should
|
||
* instantiate the elements that inherit from this class instead.
|
||
*
|
||
* //i.e
|
||
* //we will set the behaviors that are related only to this class
|
||
* var shape = new PMUI.draw.CustomShape({
|
||
* //we can set different types of containers here and the factory
|
||
* //will do all the work
|
||
* container : "regular",
|
||
* drop : {
|
||
* //type specifies the drop behavior we want, again we just need
|
||
* // to pass a string
|
||
* type : "container",
|
||
* //selectors are the css selectors that this element will
|
||
* //accept to be dropped
|
||
* selectors : [".firstselector",".secondselector"],
|
||
* //overwrite is an option to override previous and default
|
||
* //selectors
|
||
* overwrite : false
|
||
* }
|
||
* });
|
||
*
|
||
*
|
||
* @extends PMUI.draw.Core
|
||
*
|
||
* @constructor Creates a new instance of this class
|
||
* @param {Object} options
|
||
* @cfg {String} [container="nocontainer"] the type of container behavior
|
||
* we want for an object, it can be regular,or nocontainer, or any other class
|
||
* that extends the {@link PMUI.behavior.ContainerBehavior} class, but also note that we would
|
||
* need to override the factory for container behaviors located in this class.
|
||
* @cfg {Object} [drop={
|
||
* drop : "nodrop",
|
||
* selectors : [],
|
||
* overwrite : false
|
||
* }] Object that contains the options for the drop behavior we want an object
|
||
* to have, we can, assign type which can be container, connection,
|
||
* connectioncontainer, or no drop. As with the container behavior we can extend
|
||
* the behaviors and factory for this functionality.
|
||
* We also have selectors that specify the selectors the drop behavior will
|
||
* accept and the overwrite feature
|
||
*/
|
||
var BehavioralElement = function (options) {
|
||
BehavioralElement.superclass.call(this, options);
|
||
/**
|
||
* Determines the Behavior object that this object has
|
||
* @property {PMUI.behavior.ContainerBehavior}
|
||
*/
|
||
this.containerBehavior = null;
|
||
/**
|
||
* Determines the Drop Behavior of the element
|
||
* @type {PMUI.behavior.DropBehavior}
|
||
*/
|
||
this.dropBehavior = null
|
||
|
||
/**
|
||
* List of the children
|
||
* @property {*}
|
||
*/
|
||
this.children = null;
|
||
BehavioralElement.prototype.init.call(this, options);
|
||
};
|
||
PMUI.inheritFrom('PMUI.draw.Core', BehavioralElement);
|
||
/**
|
||
* Type of the all instances of this class
|
||
* @property {String}
|
||
*/
|
||
BehavioralElement.prototype.type = "BehavioralElement";
|
||
/**
|
||
* Instance initializer which uses options to extend the default config options.
|
||
* The default options are container: nocontainer, and drop: nodrop
|
||
* @param {Object} options
|
||
*/
|
||
BehavioralElement.prototype.init = function (options) {
|
||
var defaults = {
|
||
drop: "nodrop",
|
||
container: "nocontainer"
|
||
};
|
||
$.extend(true, defaults, options);
|
||
var defaults = {
|
||
drop: {
|
||
type: "nodrop",
|
||
selectors: [],
|
||
overwrite: false
|
||
},
|
||
container: "nocontainer"
|
||
};
|
||
$.extend(true, defaults, options);
|
||
this.setDropBehavior(defaults.drop.type, defaults.drop.selectors,
|
||
defaults.drop.overwrite);
|
||
this.setContainerBehavior(defaults.container);
|
||
this.children = new PMUI.util.ArrayList();
|
||
};
|
||
BehavioralElement.prototype.setDropBehavior = function (behavior, selectors,
|
||
overwrite) {
|
||
this.dropBehavior = this.dropBehaviorFactory(behavior, selectors);
|
||
this.dropBehavior.setSelectors(selectors, overwrite);
|
||
if (this.html && this.dropBehavior) {
|
||
this.dropBehavior.attachDropBehavior(this);
|
||
|
||
// update the saved object
|
||
// added by mauricio to save the drop behavior of this shape
|
||
$.extend(true, this.savedOptions.drop, {
|
||
type: behavior,
|
||
overwrite: overwrite
|
||
});
|
||
|
||
if (selectors && selectors.hasOwnProperty('length')) {
|
||
this.dropBehavior.updateSelectors(this, selectors, overwrite);
|
||
// update the saved object
|
||
// added by mauricio to save the drop behavior of this shape
|
||
$.extend(true, this.savedOptions.drop, {
|
||
selectors: selectors
|
||
});
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Factory of drop behaviors. It uses lazy instantiation to create instances of
|
||
* the different drop behaviors
|
||
* @param {String} type Type of drop behavior we want to assign to an object,
|
||
* it can be nodrop, container, connection or connectioncontainer
|
||
* @param {Array} selectors Array containing the css selectors that the drop
|
||
* behavior will accept
|
||
* @return {DropBehavior}
|
||
*/
|
||
BehavioralElement.prototype.dropBehaviorFactory = function (type, selectors) {
|
||
if (type === "nodrop") {
|
||
if (!this.noDropBehavior) {
|
||
this.noDropBehavior = new PMUI.behavior.NoDropBehavior(selectors);
|
||
}
|
||
return this.noDropBehavior;
|
||
}
|
||
if (type === "container") {
|
||
if (!this.containerDropBehavior) {
|
||
this.containerDropBehavior = new PMUI.behavior.ContainerDropBehavior(selectors);
|
||
}
|
||
return this.containerDropBehavior;
|
||
}
|
||
if (type === "connection") {
|
||
if (!this.connectionDropBehavior) {
|
||
this.connectionDropBehavior = new PMUI.behavior.ConnectionDropBehavior(selectors);
|
||
}
|
||
return this.connectionDropBehavior;
|
||
}
|
||
if (type === "connectioncontainer") {
|
||
if (!this.connectionContainerDropBehavior) {
|
||
this.connectionContainerDropBehavior =
|
||
new PMUI.behavior.ConnectionContainerDropBehavior(selectors);
|
||
}
|
||
return this.connectionContainerDropBehavior;
|
||
}
|
||
};
|
||
/**
|
||
* Sets the container behavior of an object, using the same options as
|
||
* the factory
|
||
* @param {String} behavior the container behavior we want the factory to
|
||
* assign, it can be regular, or nocontainer
|
||
* @chainable
|
||
*/
|
||
BehavioralElement.prototype.setContainerBehavior = function (behavior) {
|
||
// update the saved object
|
||
// added by mauricio to save the container behavior of this
|
||
$.extend(true, this.savedOptions, {container: behavior});
|
||
this.containerBehavior = this.containerBehaviorFactory(behavior);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Factory of container behaviors. It uses lazy instantiation to create
|
||
* instances of the different container behaviors
|
||
* @param {String} type An string that specifies the container behavior we want
|
||
* an instance to have, it can be regular or nocontainer
|
||
* @return {ContainerBehavior}
|
||
*/
|
||
BehavioralElement.prototype.containerBehaviorFactory = function (type) {
|
||
if (type === "regular") {
|
||
if (!this.regularContainerBehavior) {
|
||
this.regularContainerBehavior = new PMUI.behavior.RegularContainerBehavior();
|
||
}
|
||
return this.regularContainerBehavior;
|
||
|
||
}
|
||
if (!this.noContainerBehavior) {
|
||
this.noContainerBehavior = new PMUI.behavior.NoContainerBehavior();
|
||
}
|
||
return this.noContainerBehavior;
|
||
};
|
||
/**
|
||
* Updates the children positions of a container given the x and y difference
|
||
* @param {Number} diffX x difference
|
||
* @param {Number} diffY y difference
|
||
* @chainable
|
||
* // TODO make this method recursive
|
||
*/
|
||
BehavioralElement.prototype.updateChildrenPosition = function (diffX, diffY) {
|
||
var children = this.getChildren(),
|
||
child,
|
||
i,
|
||
updatedChildren = [],
|
||
previousValues = [],
|
||
newValues = [];
|
||
for (i = 0; i < children.getSize(); i += 1) {
|
||
child = children.get(i);
|
||
if ((diffX !== 0 || diffY !== 0) && !this.canvas.currentSelection.contains(child)) {
|
||
updatedChildren.push(child);
|
||
previousValues.push({
|
||
x: child.x,
|
||
y: child.y
|
||
});
|
||
newValues.push({
|
||
x: child.x + diffX,
|
||
y: child.y + diffY
|
||
});
|
||
}
|
||
child.setPosition(child.x + diffX, child.y + diffY);
|
||
}
|
||
if (updatedChildren.length > 0) {
|
||
this.canvas.triggerPositionChangeEvent(updatedChildren, previousValues,
|
||
newValues);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns whether the instance is a container or not
|
||
* @return {Boolean}
|
||
*/
|
||
BehavioralElement.prototype.isContainer = function () {
|
||
return this.containerBehavior &&
|
||
this.containerBehavior.type !== "NoContainerBehavior";
|
||
};
|
||
|
||
/**
|
||
* Encapsulates the functionality of adding an element this element according
|
||
* to its container behavior
|
||
* @param {PMUI.draw.Shape} shape Shape we want to add to the element
|
||
* @param {Number} x x coordinate where the shape will be positionated relative
|
||
* to this element
|
||
* @param {Number} y y coordinate where the shape will be positionated relative
|
||
* to this element
|
||
* @param {Boolean} topLeftCorner determines if the drop position should be
|
||
* calculated from the top left corner of the shape or, from its center
|
||
* @chainable
|
||
*/
|
||
BehavioralElement.prototype.addElement = function (shape, x, y,
|
||
topLeftCorner) {
|
||
this.containerBehavior.addToContainer(this, shape, x, y, topLeftCorner);
|
||
return this;
|
||
};
|
||
/**
|
||
* Encapsulates the functionality of removing an element this element according
|
||
* to its container behavior
|
||
* @param {PMUI.draw.Shape} shape shape to be removed from this element
|
||
* @chainable
|
||
*/
|
||
BehavioralElement.prototype.removeElement = function (shape) {
|
||
this.containerBehavior.removeFromContainer(shape);
|
||
return this;
|
||
};
|
||
/**
|
||
* Swaps a shape from this container to a different one
|
||
* @param {PMUI.draw.Shape} shape shape to be swapped
|
||
* @param {PMUI.draw.BehavioralElement} otherContainer the other container the shape will
|
||
* be swapped to
|
||
* @param {Number} x x coordinate where the shape will be positionated relative
|
||
* to this element
|
||
* @param {Number} y y coordinate where the shape will be positionated relative
|
||
* to this element
|
||
* @param {Boolean} topLeftCorner determines if the drop position should be
|
||
* calculated from the top left corner of the shape or, from its center
|
||
* @chainable
|
||
*/
|
||
BehavioralElement.prototype.swapElementContainer = function (shape,
|
||
otherContainer, x,
|
||
y, topLeftCorner) {
|
||
var newX = !x ? shape.getX() : x,
|
||
newY = !y ? shape.getY() : y;
|
||
shape.changedContainer = true;
|
||
this.removeElement(shape);
|
||
otherContainer.addElement(shape, newX, newY, topLeftCorner);
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the list of children belonging to this shape
|
||
* @returns {PMUI.util.ArrayList}
|
||
*/
|
||
BehavioralElement.prototype.getChildren = function () {
|
||
return this.children;
|
||
};
|
||
/**
|
||
* Updates the dimensions and position of this shape (note: 'this' is a shape)
|
||
* @param {Number} margin the margin for this element to consider towards the
|
||
* shapes near its borders
|
||
* @chainable
|
||
*/
|
||
BehavioralElement.prototype.updateDimensions = function (margin) {
|
||
// update its size (if an child grew out of the shape)
|
||
// only if it's not the canvas
|
||
if (this.family !== 'Canvas') {
|
||
this.updateSize(margin);
|
||
this.refreshConnections();
|
||
// updates JQueryUI's options (minWidth and minHeight)
|
||
PMUI.behavior.ResizeBehavior.prototype.updateResizeMinimums(this);
|
||
BehavioralElement.prototype.updateDimensions.call(this.parent, margin);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the selectors of the current drop behavior
|
||
* @param {Array} selectors new css selectors for the drop behavior
|
||
* @param {Boolean} overwrite determines whether the default selectors will
|
||
* be erased
|
||
* @chainable
|
||
*/
|
||
BehavioralElement.prototype.setDropAcceptedSelectors = function (selectors,
|
||
overwrite) {
|
||
if (selectors && selectors.hasOwnProperty('length')) {
|
||
this.drop.updateSelectors(this, selectors, overwrite);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Attach the drop behavior to the element, if there is such
|
||
* @chainable
|
||
*/
|
||
BehavioralElement.prototype.updateBehaviors = function () {
|
||
if (this.dropBehavior) {
|
||
this.dropBehavior.attachDropBehavior(this);
|
||
this.dropBehavior.updateSelectors(this);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Stringifies the container and drop behavior of this object
|
||
* @return {Object}
|
||
*/
|
||
BehavioralElement.prototype.stringify = function () {
|
||
var inheritedJSON = BehavioralElement.superclass.prototype.stringify.call(this),
|
||
thisJSON = {
|
||
container: this.savedOptions.container,
|
||
drop: this.savedOptions.drop
|
||
};
|
||
$.extend(true, inheritedJSON, thisJSON);
|
||
return inheritedJSON;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.BehavioralElement', BehavioralElement);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = BehavioralElement;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.BehaviorFactory
|
||
* @extend PMUI.util.Factory
|
||
* Extends the factory class to produce Behavior instances
|
||
*
|
||
* @constructor
|
||
* Creates a new instance od the class
|
||
* @param {Object} options
|
||
*/
|
||
var BehaviorFactory = function (options) {
|
||
BehaviorFactory.superclass.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.util.Factory', BehaviorFactory);
|
||
|
||
/**
|
||
* Defines the object's type
|
||
* @type {String}
|
||
*/
|
||
BehaviorFactory.prototype.type = 'BehaviorFactory';
|
||
|
||
/**
|
||
* Overwrite the make function to accept strings
|
||
* @param {Object/String} type
|
||
* @return {Object}
|
||
*/
|
||
BehaviorFactory.prototype.make = function (obj) {
|
||
var behaviorInstance,
|
||
behaviorType = obj.pmType;
|
||
|
||
if (this.isValidClass(obj)) {
|
||
behaviorInstance = obj;
|
||
} else if (this.isValidName(behaviorType)) {
|
||
behaviorInstance = this.build(behaviorType, obj);
|
||
} else if (this.isValidName(obj)) {
|
||
behaviorInstance = this.build(obj, {});
|
||
} else {
|
||
behaviorInstance = this.build(this.defaultProduct, obj);
|
||
}
|
||
return behaviorInstance;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.BehaviorFactory', BehaviorFactory);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = BehaviorFactory;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @abstract
|
||
* @class PMUI.behavior.DragBehavior
|
||
* Abstract class that encapsulates the drag behavior of an object
|
||
*
|
||
* @constructor Creates a new instance of the class
|
||
*
|
||
*/
|
||
var DragBehavior = function () {
|
||
};
|
||
|
||
/**
|
||
* Type of the object
|
||
* @property {String}
|
||
*/
|
||
DragBehavior.prototype.type = "DragBehavior";
|
||
/**
|
||
* Family of the object
|
||
* @property {String}
|
||
*/
|
||
DragBehavior.prototype.family = "DragBehavior";
|
||
|
||
|
||
/**
|
||
* Attach the drag listener and its corresponding ui properties to the shape
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
DragBehavior.prototype.attachDragBehavior = function (shape) {
|
||
var dragOptions,
|
||
$shape = $(shape.getHTML());
|
||
dragOptions = {
|
||
revert: false,
|
||
helper: "none",
|
||
cursorAt: false,
|
||
revertDuration: 0,
|
||
grid: [1, 1],
|
||
start: this.onDragStart(shape),
|
||
drag: this.onDrag(shape),
|
||
stop: this.onDragEnd(shape)
|
||
};
|
||
$shape.draggable(dragOptions);
|
||
};
|
||
/**
|
||
* @event dragStart
|
||
* @abstract drag start handler, function that runs when the drag start event occurs,
|
||
* it should return a function so that any implementation should go inside the
|
||
* return
|
||
* @param {PMUI.draw.Shape} shape current shape being dragged
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DragBehavior.prototype.onDragStart = function (shape) {
|
||
return function (e, ui) {
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event drag
|
||
* Drag handler, function that runs when dragging is occurring,
|
||
* it should return a function so that any implementation should go inside the
|
||
* return
|
||
* @param {PMUI.draw.Shape} shape shape being dragged
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DragBehavior.prototype.onDrag = function (shape) {
|
||
return function (e, ui) {
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event dragEnd
|
||
* Drag end handler, function that runs when the drag end event occurs,
|
||
* it should return a function so that any implementation should go inside the
|
||
* return
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DragBehavior.prototype.onDragEnd = function (shape) {
|
||
return function (e, ui) {
|
||
};
|
||
};
|
||
/**
|
||
* @abstract Executes the hook Function for the drag start event
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DragBehavior.prototype.dragStartHook = function (hookFunction) {
|
||
};
|
||
|
||
/**
|
||
* @abstract Executes the hook function for the drag event
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DragBehavior.prototype.dragHook = function (hookFunction) {
|
||
};
|
||
/**
|
||
* @abstract Executes the hook function for the drag end event
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DragBehavior.prototype.dragEndHook = function () {
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.DragBehavior', DragBehavior);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = DragBehavior;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.CustomShapeDragBehavior
|
||
* Encapsulates the drag behavior of a custom shape (with ports and connections)
|
||
* , it also encapsulates the behavior for multiple drag
|
||
* @extends PMUI.behavior.DragBehavior
|
||
*
|
||
* @constructor Creates a new instance of the class
|
||
*
|
||
*/
|
||
var CustomShapeDragBehavior = function () {
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.DragBehavior', CustomShapeDragBehavior);
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
CustomShapeDragBehavior.prototype.type = "CustomShapeDragBehavior";
|
||
/**
|
||
* Attach the drag behavior and ui properties to the corresponding shape
|
||
* @param {PMUI.draw.CustomShape} customShape
|
||
*/
|
||
CustomShapeDragBehavior.prototype.attachDragBehavior = function (customShape) {
|
||
var dragOptions,
|
||
$customShape = $(customShape.getHTML());
|
||
dragOptions = {
|
||
revert: false,
|
||
helper: "none",
|
||
cursorAt: false,
|
||
revertDuration: 0,
|
||
disable: false,
|
||
grid: [1, 1],
|
||
start: this.onDragStart(customShape),
|
||
drag: this.onDrag(customShape, true),
|
||
stop: this.onDragEnd(customShape, true)
|
||
};
|
||
$customShape.draggable({'cursor':"move"});
|
||
$customShape.draggable(dragOptions);
|
||
};
|
||
|
||
//TODO Encapsulates behaviors for multiple drag, and simple custom shape drag
|
||
//TODO Initialize all oldX and oldY values
|
||
/**
|
||
* On drag start handler, it uses the {@link PMUI.behavior.RegularDragBehavior}.onDragStart
|
||
* method to initialize the drag, but also initializes other properties
|
||
* @param {PMUI.draw.CustomShape} customShape
|
||
* @return {Function}
|
||
*/
|
||
CustomShapeDragBehavior.prototype.onDragStart = function (customShape) {
|
||
return function (e, ui) {
|
||
if(customShape.canvas.currentSelection.asArray().length == 0){
|
||
customShape.canvas.addToSelection(customShape);
|
||
}
|
||
PMUI.behavior.RegularDragBehavior.prototype.onDragStart.call(this,
|
||
customShape)(e, ui);
|
||
|
||
customShape.previousXDragPosition = customShape.getX();
|
||
customShape.previousYDragPosition = customShape.getY();
|
||
if (customShape.canvas.snapToGuide) {
|
||
//init snappers
|
||
customShape.canvas.startSnappers(e);
|
||
}
|
||
customShape.canvas.isDragging = true;
|
||
};
|
||
};
|
||
/**
|
||
* Procedure executed while dragging, it takes care of multiple drag, moving
|
||
* connections, updating positions and children of the shapes being dragged
|
||
* @param {PMUI.draw.CustomShape} customShape shape being dragged
|
||
* @param {boolean} root return whether this is the shape where the drag started
|
||
* @param {number} childDiffX x distance needed for the non-root shapes to move
|
||
* @param {number} childDiffY y distance needed for the non-root shapes to move
|
||
* @param {Object} e jQuery object containing the properties when a drag event
|
||
* occur
|
||
* @param {Object} ui JQuery UI object containing the properties when a drag
|
||
* event occur
|
||
*/
|
||
CustomShapeDragBehavior.prototype.onDragProcedure = function (customShape, root, childDiffX, childDiffY, e, ui) {
|
||
var i,
|
||
j,
|
||
sibling,
|
||
diffX,
|
||
diffY,
|
||
port,
|
||
child,
|
||
connection,
|
||
shape1,
|
||
shape2,
|
||
canvas = customShape.canvas,
|
||
k,
|
||
uiOffset,
|
||
positionsX1= [];
|
||
|
||
uiOffset = {};
|
||
uiOffset.x = ui.helper.position().left / canvas.zoomFactor;
|
||
uiOffset.y = ui.helper.position().top / canvas.zoomFactor;
|
||
uiOffset.diffX = customShape.x - uiOffset.x;
|
||
uiOffset.diffY = customShape.y - uiOffset.y;
|
||
|
||
for (k = 0; k < customShape.canvas.currentSelection.getSize(); k += 1) {
|
||
sibling = customShape.canvas.currentSelection.get(k);
|
||
if (sibling.id !== customShape.id) {
|
||
positionsX1.push(sibling.x + uiOffset.diffX);
|
||
}
|
||
}
|
||
|
||
// shapes
|
||
if (root) {
|
||
// Commented for problem on snappers
|
||
|
||
if (customShape.canvas.snapToGuide) {
|
||
customShape.canvas.processGuides(e, ui, customShape);
|
||
}
|
||
customShape.setPosition(ui.helper.position().left / canvas.zoomFactor,
|
||
ui.helper.position().top / canvas.zoomFactor);
|
||
|
||
diffX = customShape.x - customShape.previousXDragPosition;
|
||
diffY = customShape.y - customShape.previousYDragPosition;
|
||
|
||
customShape.previousXDragPosition = customShape.x;
|
||
customShape.previousYDragPosition = customShape.y;
|
||
|
||
for (i = 0; i < customShape.canvas.currentSelection.getSize(); i += 1) {
|
||
sibling = customShape.canvas.currentSelection.get(i);
|
||
if (sibling.id !== customShape.id) {
|
||
if (((sibling.x + diffX) >= 0) && ((sibling.y + diffY) >= 0)){
|
||
sibling.setPosition(sibling.x + diffX, sibling.y + diffY);
|
||
} else {
|
||
e.preventDefault();
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
customShape.setPosition(customShape.x, customShape.y);
|
||
}
|
||
|
||
// children
|
||
if (root) {
|
||
for (i = 0; i < customShape.canvas.currentSelection.getSize(); i += 1) {
|
||
sibling = customShape.canvas.currentSelection.get(i);
|
||
for (j = 0; j < sibling.children.getSize(); j += 1) {
|
||
child = sibling.children.get(j);
|
||
PMUI.behavior.CustomShapeDragBehavior.prototype.onDragProcedure.call(this, child,
|
||
false, diffX, diffY, e, ui);
|
||
}
|
||
}
|
||
} else {
|
||
for (i = 0; i < customShape.children.getSize(); i += 1) {
|
||
child = customShape.children.get(i);
|
||
PMUI.behavior.CustomShapeDragBehavior.prototype.onDragProcedure.call(this, child,
|
||
false, childDiffX, childDiffY, e, ui);
|
||
}
|
||
}
|
||
|
||
// connections
|
||
if (root) {
|
||
for (i = 0; i < customShape.canvas.currentSelection.getSize(); i += 1) {
|
||
sibling = customShape.canvas.currentSelection.get(i);
|
||
for (j = 0; j < sibling.ports.getSize(); j += 1) {
|
||
//for each port update its absolute position and repaint its connection
|
||
port = sibling.ports.get(j);
|
||
connection = port.connection;
|
||
port.setPosition(port.x, port.y);
|
||
|
||
if (customShape.canvas.sharedConnections.
|
||
find('id', connection.getID())) {
|
||
// move the segments of this connections
|
||
if (connection.srcPort.parent.getID() === sibling.getID()) {
|
||
// to avoid moving the connection twice
|
||
// (two times per shape), move it only if the shape
|
||
// holds the sourcePort
|
||
connection.move(diffX * canvas.zoomFactor,
|
||
diffY * canvas.zoomFactor);
|
||
}
|
||
} else {
|
||
connection
|
||
.setSegmentColor(PMUI.util.Color.GREY, false)
|
||
.setSegmentStyle("regular", false)
|
||
.disconnect()
|
||
.connect();
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
for (i = 0; i < customShape.ports.getSize(); i += 1) {
|
||
//for each port update its absolute position and repaint its connection
|
||
port = customShape.ports.get(i);
|
||
connection = port.connection;
|
||
shape1 = connection.srcPort.parent;
|
||
shape2 = connection.destPort.parent;
|
||
|
||
port.setPosition(port.x, port.y);
|
||
|
||
if (customShape.canvas.sharedConnections.
|
||
find('id', connection.getID())) {
|
||
// to avoid moving the connection twice
|
||
// (two times per shape), move it only if the shape
|
||
// holds the sourcePort
|
||
if (connection.srcPort.parent.getID() ===
|
||
customShape.getID()) {
|
||
connection.move(childDiffX * canvas.zoomFactor,
|
||
childDiffY * canvas.zoomFactor);
|
||
}
|
||
} else {
|
||
connection
|
||
.setSegmentColor(PMUI.util.Color.GREY, false)
|
||
.setSegmentStyle("regular", false)
|
||
.disconnect()
|
||
.connect();
|
||
}
|
||
}
|
||
}
|
||
};
|
||
/**
|
||
* On drag handler, calls the drag procedure while the dragging is occurring,
|
||
* and also takes care of the snappers
|
||
* @param {PMUI.draw.CustomShape} customShape shape being dragged
|
||
* @param {boolean} root return whether this is the shape where the drag started
|
||
* @param {number} childDiffX x distance needed for the non-root shapes to move
|
||
* @param {number} childDiffY y distance needed for the non-root shapes to move
|
||
* @return {Function}
|
||
*/
|
||
CustomShapeDragBehavior.prototype.onDrag = function (customShape, root, childDiffX, childDiffY) {
|
||
var self = this;
|
||
return function (e, ui) {
|
||
// call to dragEnd procedure
|
||
self.onDragProcedure(customShape, root, childDiffX,
|
||
childDiffY, e, ui);
|
||
};
|
||
};
|
||
/**
|
||
* Procedure executed on drag end, it takes care of multiple drag, moving
|
||
* connections, updating positions and children of the shapes being dragged
|
||
* @param {PMUI.draw.CustomShape} customShape shape being dragged
|
||
* @param {boolean} root return whether this is the shape where the drag started
|
||
* @param {Object} e jQuery object containing the properties when a drag event
|
||
* occur
|
||
* @param {Object} ui JQuery UI object containing the properties when a drag
|
||
* event occur
|
||
*/
|
||
CustomShapeDragBehavior.prototype.dragEndProcedure = function (customShape, root, e, ui) {
|
||
var i,
|
||
j,
|
||
sibling,
|
||
port,
|
||
child,
|
||
connection,
|
||
shape1,
|
||
shape2,
|
||
canvas = customShape.canvas;
|
||
|
||
// shapes
|
||
if (root) {
|
||
|
||
// the difference between this segment of code and the segment of code
|
||
// found in dragProcedure is that it's not needed to move the shapes
|
||
// anymore using differentials
|
||
customShape.setPosition(ui.helper.position().left / canvas.zoomFactor,
|
||
ui.helper.position().top / canvas.zoomFactor);
|
||
customShape.wasDragged = true;
|
||
customShape.canvas.isDragging = false;
|
||
for (i = 0; i < customShape.canvas.currentSelection.getSize(); i += 1) {
|
||
sibling = customShape.canvas.currentSelection.get(i);
|
||
sibling.setPosition(sibling.x, sibling.y);
|
||
}
|
||
} else {
|
||
customShape.setPosition(customShape.x, customShape.y);
|
||
}
|
||
|
||
// children
|
||
if (root) {
|
||
for (i = 0; i < customShape.canvas.currentSelection.getSize();
|
||
i += 1) {
|
||
sibling = customShape.canvas.currentSelection.get(i);
|
||
for (j = 0; j < sibling.children.getSize(); j += 1) {
|
||
child = sibling.children.get(j);
|
||
child.changedContainer = true;
|
||
PMUI.behavior.CustomShapeDragBehavior.prototype.dragEndProcedure.call(this,
|
||
child, false, e, ui);
|
||
}
|
||
}
|
||
} else {
|
||
for (i = 0; i < customShape.children.getSize(); i += 1) {
|
||
child = customShape.children.get(i);
|
||
PMUI.behavior.CustomShapeDragBehavior.prototype.dragEndProcedure.call(this,
|
||
child, false, e, ui);
|
||
}
|
||
}
|
||
|
||
// connections
|
||
if (root) {
|
||
for (i = 0; i < customShape.canvas.currentSelection.getSize();
|
||
i += 1) {
|
||
sibling = customShape.canvas.currentSelection.get(i);
|
||
for (j = 0; j < sibling.ports.getSize(); j += 1) {
|
||
|
||
// for each port update its absolute position and repaint
|
||
// its connection
|
||
port = sibling.ports.get(j);
|
||
connection = port.connection;
|
||
|
||
port.setPosition(port.x, port.y);
|
||
|
||
if (customShape.canvas.sharedConnections.
|
||
find('id', connection.getID())) {
|
||
// move the segments of this connections
|
||
if (connection.srcPort.parent.getID() ===
|
||
sibling.getID()) {
|
||
// to avoid moving the connection twice
|
||
// (two times per shape), move it only if the shape
|
||
// holds the sourcePort
|
||
connection.disconnect(true).connect({
|
||
algorithm: 'user',
|
||
points: connection.points,
|
||
dx: parseFloat($(connection.html).css('left')),
|
||
dy: parseFloat($(connection.html).css('top'))
|
||
});
|
||
connection.checkAndCreateIntersectionsWithAll();
|
||
}
|
||
} else {
|
||
connection
|
||
.setSegmentColor(connection.originalSegmentColor, false)
|
||
.setSegmentStyle(connection.originalSegmentStyle, false)
|
||
.disconnect()
|
||
.connect();
|
||
connection.setSegmentMoveHandlers();
|
||
connection.checkAndCreateIntersectionsWithAll();
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
for (i = 0; i < customShape.ports.getSize(); i += 1) {
|
||
//for each port update its absolute position and repaint
|
||
//its connection
|
||
port = customShape.ports.get(i);
|
||
connection = port.connection;
|
||
shape1 = connection.srcPort.parent;
|
||
shape2 = connection.destPort.parent;
|
||
|
||
port.setPosition(port.x, port.y);
|
||
if (customShape.canvas.sharedConnections.
|
||
find('id', connection.getID())) {
|
||
// to avoid moving the connection twice
|
||
// (two times per shape), move it only if the shape
|
||
// holds the sourcePort
|
||
if (connection.srcPort.parent.getID() ===
|
||
customShape.getID()) {
|
||
connection.checkAndCreateIntersectionsWithAll();
|
||
}
|
||
} else {
|
||
connection
|
||
.setSegmentColor(connection.originalSegmentColor, false)
|
||
.setSegmentStyle(connection.originalSegmentStyle, false)
|
||
.disconnect()
|
||
.connect();
|
||
connection.setSegmentMoveHandlers();
|
||
connection.checkAndCreateIntersectionsWithAll();
|
||
}
|
||
}
|
||
}
|
||
|
||
};
|
||
/**
|
||
* On drag end handler, ot calls drag end procedure, removes the snappers and,
|
||
* fires the command move if necessary
|
||
* @param {PMUI.draw.CustomShape} customShape
|
||
* @return {Function}
|
||
*/
|
||
CustomShapeDragBehavior.prototype.onDragEnd = function (customShape) {
|
||
var command,
|
||
self = this;
|
||
return function (e, ui) {
|
||
|
||
// call to dragEnd procedure
|
||
self.dragEndProcedure(customShape, true, e, ui);
|
||
|
||
customShape.dragging = false;
|
||
|
||
// hide the snappers
|
||
customShape.canvas.verticalSnapper.hide();
|
||
customShape.canvas.horizontalSnapper.hide();
|
||
|
||
if (!customShape.changedContainer) {
|
||
|
||
command = new PMUI.command.CommandMove(customShape.canvas.currentSelection);
|
||
command.execute();
|
||
customShape.canvas.commandStack.add(command);
|
||
}
|
||
customShape.changedContainer = false;
|
||
|
||
// decrease the zIndex of the oldParent of customShape
|
||
customShape.decreaseParentZIndex(customShape.oldParent);
|
||
customShape.canvas.emptyCurrentSelection();
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.CustomShapeDragBehavior', CustomShapeDragBehavior);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = CustomShapeDragBehavior;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.RegularDragBehavior
|
||
* Class that encapsulates the regular drag behavior of a shape
|
||
* @extends PMUI.behavior.DragBehavior
|
||
*
|
||
* @constructor Creates a new instance of the class
|
||
*
|
||
*/
|
||
var RegularDragBehavior = function () {
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.DragBehavior', RegularDragBehavior);
|
||
/**
|
||
* Type of the object
|
||
* @property {String}
|
||
*/
|
||
RegularDragBehavior.prototype.type = "RegularDragBehavior";
|
||
/**
|
||
* Attach the drag behavior to a given shape
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
RegularDragBehavior.prototype.attachDragBehavior = function (shape) {
|
||
var $shape = $(shape.getHTML());
|
||
RegularDragBehavior.superclass.prototype.attachDragBehavior.call(this, shape);
|
||
$shape.draggable({'cursor':"move"});
|
||
};
|
||
/**
|
||
* On drag start handler, initializes everything that is needed for a shape to
|
||
* be dragged
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @return {Function}
|
||
*/
|
||
RegularDragBehavior.prototype.onDragStart = function (shape) {
|
||
return function (e, ui) {
|
||
var canvas = shape.canvas,
|
||
currentLabel = canvas.currentLabel,
|
||
selectedShape,
|
||
i;
|
||
|
||
// hide the current connection if there was one
|
||
canvas.hideCurrentConnection();
|
||
if (currentLabel) {
|
||
currentLabel.loseFocus();
|
||
$(currentLabel.textField).focusout();
|
||
}
|
||
|
||
// sort the data of the snappers (a shape might have been inserted in
|
||
// the customShape arrayList or the regularShapes)
|
||
canvas.fixSnapData();
|
||
|
||
if (!canvas.currentSelection.contains(shape)) {
|
||
canvas.emptyCurrentSelection();
|
||
/* Also decreases the z-index */
|
||
canvas.addToSelection(shape);
|
||
}
|
||
|
||
// added by mauricio
|
||
// these lines must be here and not in the top (currentSelection
|
||
// is updated in the if above)
|
||
for (i = 0; i < canvas.currentSelection.getSize(); i += 1) {
|
||
selectedShape = canvas.currentSelection.get(i);
|
||
selectedShape.setOldX(selectedShape.getX());
|
||
selectedShape.setOldY(selectedShape.getY());
|
||
selectedShape.setOldParent(selectedShape.getParent());
|
||
}
|
||
|
||
// increase shape's ancestors zIndex
|
||
shape.increaseParentZIndex(shape.getParent());
|
||
shape.canvas.isDragging = true;
|
||
return true;
|
||
};
|
||
};
|
||
/**
|
||
* On drag handler, sets the position of the shape to current position of the
|
||
* shape in the screen
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @return {Function}
|
||
*/
|
||
RegularDragBehavior.prototype.onDrag = function (shape) {
|
||
return function (e, ui) {
|
||
shape.setPosition(ui.helper.position().left,
|
||
ui.helper.position().top);
|
||
|
||
// show or hide the snappers
|
||
shape.canvas.showOrHideSnappers(shape);
|
||
};
|
||
};
|
||
/**
|
||
* On drag end handler, set the final position of the shape and fires the
|
||
* command move
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @return {Function}
|
||
*/
|
||
RegularDragBehavior.prototype.onDragEnd = function (shape) {
|
||
return function (e, ui) {
|
||
var command;
|
||
shape.setPosition(ui.helper.position().left / shape.canvas.zoomFactor,ui.helper.position().top / shape.canvas.zoomFactor);
|
||
// decrease the zIndex of the oldParent of this shape
|
||
shape.decreaseParentZIndex(shape.oldParent);
|
||
|
||
shape.dragging = false;
|
||
shape.canvas.isDragging = false;
|
||
// hide the snappers
|
||
shape.canvas.verticalSnapper.hide();
|
||
shape.canvas.horizontalSnapper.hide();
|
||
if (!shape.changedContainer) {
|
||
command = new PMUI.command.CommandMove(shape.canvas.currentSelection);
|
||
command.execute();
|
||
shape.canvas.commandStack.add(command);
|
||
}
|
||
shape.changedContainer = false;
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.RegularDragBehavior', RegularDragBehavior);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = RegularDragBehavior;
|
||
}
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.ConnectionDragBehavior
|
||
* Class that encapsulates the behavior for a connection drag.
|
||
* A connection drag behavior means that instead of moving a shape when dragging
|
||
* occurs, it creates a connection segment that let's us connect to shapes
|
||
* @extends PMUI.behavior.DragBehavior
|
||
*
|
||
* @constructor Creates a new instance of the class
|
||
*
|
||
*/
|
||
var ConnectionDragBehavior = function () {
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.DragBehavior', ConnectionDragBehavior);
|
||
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
ConnectionDragBehavior.prototype.type = "ConnectionDragBehavior";
|
||
/**
|
||
* Attach the drag behavior and ui properties to the corresponding shape
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
ConnectionDragBehavior.prototype.attachDragBehavior = function (shape) {
|
||
var $shape = $(shape.getHTML()),
|
||
dragOptions;
|
||
|
||
dragOptions = {
|
||
helper: shape.createDragHelper,
|
||
cursorAt: {top: 0, left: 0},
|
||
revert: true
|
||
};
|
||
ConnectionDragBehavior.superclass.prototype.attachDragBehavior.call(this, shape);
|
||
$shape.draggable(dragOptions);
|
||
$shape.draggable('enable');
|
||
};
|
||
/**
|
||
* On drag start handler, initializes all properties needed to start a
|
||
* connection drag
|
||
* @param {PMUI.draw.CustomShape} customShape
|
||
* @return {Function}
|
||
*/
|
||
ConnectionDragBehavior.prototype.onDragStart = function (customShape) {
|
||
return function (e, ui) {
|
||
var canvas = customShape.canvas,
|
||
currentLabel = canvas.currentLabel,
|
||
realPoint = canvas.relativePoint(e),
|
||
startPortX = e.pageX - customShape.getAbsoluteX(),
|
||
startPortY = e.pageY - customShape.getAbsoluteY();
|
||
|
||
customShape.startConnectionPoint.portX = startPortX;
|
||
customShape.startConnectionPoint.portY = startPortY;
|
||
customShape.canvas.emptyCurrentSelection();
|
||
|
||
if (currentLabel) {
|
||
currentLabel.loseFocus();
|
||
$(currentLabel.textField).focusout();
|
||
}
|
||
if (customShape.family !== "CustomShape") {
|
||
return false;
|
||
}
|
||
customShape.setOldX(customShape.getX());
|
||
customShape.setOldY(customShape.getY());
|
||
customShape.startConnectionPoint.x = customShape.canvas.zoomFactor * realPoint.x;
|
||
customShape.startConnectionPoint.y = customShape.canvas.zoomFactor * realPoint.y;
|
||
return true;
|
||
|
||
};
|
||
};
|
||
/**
|
||
* On drag handler, creates a connection segment from the shape to the current
|
||
* mouse position
|
||
* @param {PMUI.draw.CustomShape} customShape
|
||
* @return {Function}
|
||
*/
|
||
ConnectionDragBehavior.prototype.onDrag = function (customShape) {
|
||
return function (e, ui) {
|
||
var canvas = customShape.getCanvas(),
|
||
endPoint = new PMUI.util.Point(),
|
||
realPoint = canvas.relativePoint(e);
|
||
|
||
if (canvas.connectionSegment) {
|
||
$(canvas.connectionSegment.getHTML()).remove();
|
||
}
|
||
|
||
// Determine the point where the mouse currently is
|
||
endPoint.x = realPoint.x * customShape.canvas.zoomFactor;
|
||
endPoint.y = realPoint.y * customShape.canvas.zoomFactor;
|
||
|
||
// Creates a new segment from where the helper was created to the
|
||
// currently mouse location
|
||
|
||
canvas.connectionSegment = new PMUI.draw.Segment({
|
||
startPoint: customShape.startConnectionPoint,
|
||
endPoint: endPoint,
|
||
parent: canvas,
|
||
zOrder: PMUI.util.Style.MAX_ZINDEX * 2
|
||
});
|
||
|
||
// We make the connection segment point to helper in order to get
|
||
// information when the drop occurs
|
||
canvas.connectionSegment.pointsTo = customShape;
|
||
|
||
// Create HTML and paint
|
||
canvas.connectionSegment.paint();
|
||
};
|
||
|
||
};
|
||
/**
|
||
* On drag end handler, deletes the connection segment created while dragging
|
||
* @param {PMUI.draw.CustomShape} customShape
|
||
* @return {Function}
|
||
*/
|
||
ConnectionDragBehavior.prototype.onDragEnd = function (customShape) {
|
||
return function (e, ui) {
|
||
if (customShape.canvas.connectionSegment) {
|
||
$(customShape.canvas.connectionSegment.getHTML()).remove();
|
||
}
|
||
customShape.setPosition(customShape.getOldX(), customShape.getOldY());
|
||
customShape.dragging = false;
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ConnectionDragBehavior', ConnectionDragBehavior);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = ConnectionDragBehavior;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.NoDragBehavior
|
||
* Class that encapsulates the drag behavior corresponding to the elements that
|
||
* cannot be dragged
|
||
* @extends PMUI.behavior.DragBehavior
|
||
*
|
||
* @constructor Creates a new instance of the class
|
||
*
|
||
*/
|
||
var NoDragBehavior = function () {
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.DragBehavior', NoDragBehavior);
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
NoDragBehavior.prototype.type = "NoDragBehavior";
|
||
|
||
/**
|
||
* On drag start handler, this method prevents drag from occurring
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @return {Function}
|
||
*/
|
||
NoDragBehavior.prototype.onDragStart = function (shape) {
|
||
// hide the current connection if there was one
|
||
return function (e, ui) {
|
||
shape.canvas.hideCurrentConnection();
|
||
return false;
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.NoDragBehavior', NoDragBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = NoDragBehavior;
|
||
}
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @abstract
|
||
* @class PMUI.behavior.DropBehavior
|
||
* Abstract class where all the drop behavior classes inherit from
|
||
* Strategy Pattern
|
||
* @constructor
|
||
* Creates a new instance of the class
|
||
* @param {Object} [options] css selectors that the drop behavior
|
||
* will accept
|
||
*/
|
||
var DropBehavior = function (options) {
|
||
/**
|
||
* css selectors that the used for the drop behaviors beside the defaults
|
||
* @property {Array}
|
||
*/
|
||
this.selectors = [];
|
||
DropBehavior.prototype.init.call(this, options);
|
||
};
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
DropBehavior.prototype.type = "DropBehavior";
|
||
/**
|
||
* Family of the instances
|
||
* @property {String}
|
||
*/
|
||
DropBehavior.prototype.family = "DropBehavior";
|
||
/**
|
||
* Default css selectors for the drop behavior
|
||
* @property {String}
|
||
*/
|
||
DropBehavior.prototype.defaultSelector = "";
|
||
|
||
/**
|
||
* @private
|
||
* Initializes the object with the default options
|
||
* @param {[type]} options
|
||
*/
|
||
DropBehavior.prototype.init = function (options) {
|
||
var defaults = {
|
||
selectors: []
|
||
};
|
||
jQuery.extend(true, defaults, options);
|
||
this.setSelectors(defaults.selectors);
|
||
};
|
||
/**
|
||
* Attach the drop behaviors and assign the handlers to the corresponding shape
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
DropBehavior.prototype.attachDropBehavior = function (shape) {
|
||
var $shape = $(shape.getHTML()),
|
||
dropOptions = {
|
||
accept: this.defaultSelector,
|
||
drop: this.onDrop(shape),
|
||
over: this.onDragEnter(shape),
|
||
out: this.onDragLeave(shape),
|
||
greedy: true
|
||
};
|
||
$shape.droppable(dropOptions);
|
||
};
|
||
|
||
/**
|
||
* @event dragEnter
|
||
* @abstract Handler for the drag enter event
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DropBehavior.prototype.onDragEnter = function (shape) {
|
||
return function (e, ui) {
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event dragLeave
|
||
* @abstract Handler for the drag leave event
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DropBehavior.prototype.onDragLeave = function (shape) {
|
||
return function (e, ui) {
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event drop
|
||
* @abstract Handler for the on drop event
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DropBehavior.prototype.onDrop = function (shape) {
|
||
return function (e, ui) {
|
||
};
|
||
};
|
||
/**
|
||
* Sets the selectors that the drop behavior will accept
|
||
* @param {Array} selectors css selectors
|
||
* @param {boolean} overwrite determines whether the default selectors will be
|
||
* overridden or not
|
||
* @chainable
|
||
*/
|
||
DropBehavior.prototype.setSelectors = function (selectors, overwrite) {
|
||
var currentSelectors = "",
|
||
index,
|
||
i;
|
||
if (selectors) {
|
||
this.selectors = selectors;
|
||
}
|
||
if (!overwrite) {
|
||
currentSelectors = this.defaultSelector;
|
||
index = 0;
|
||
} else if (selectors.length > 0) {
|
||
currentSelectors = selectors[0];
|
||
index = 1;
|
||
}
|
||
for (i = index; i < selectors.length; i += 1) {
|
||
currentSelectors += "," + this.selectors[i];
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Updates the accepted drop selectors
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @param {Array} selectors
|
||
* @chainable
|
||
*/
|
||
DropBehavior.prototype.updateSelectors = function (shape, selectors) {
|
||
var $shape = $(shape.getHTML()),
|
||
currentSelectors,
|
||
i;
|
||
if (selectors) {
|
||
this.selectors = selectors;
|
||
}
|
||
if (this.selectors.length > 0) {
|
||
currentSelectors = this.selectors[0];
|
||
}
|
||
for (i = 1; i < this.selectors.length; i += 1) {
|
||
currentSelectors += ',' + this.selectors[i];
|
||
}
|
||
$shape.droppable({"accept": currentSelectors});
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Hook for the drag enter handler
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DropBehavior.prototype.dragEnterHook = function () {
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* Hook for the drag leave handler
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DropBehavior.prototype.dragLeaveHook = function () {
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* Hook for the drop handler, executes before the on drop handler logic
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @param {Object} e jQuery object that contains the properties on the
|
||
* drop event
|
||
* @param {Object} ui jQuery object that contains the properties on the
|
||
* drop event
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DropBehavior.prototype.dropStartHook = function (shape, e, ui) {
|
||
return true;
|
||
};
|
||
/**
|
||
* Hook for the on drop handler
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @param {Object} e jQuery object that contains the properties on the
|
||
* drop event
|
||
* @param {Object} ui jQuery object that contains the properties on the
|
||
* drop event
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DropBehavior.prototype.dropHook = function (shape, e, ui) {
|
||
return true;
|
||
};
|
||
/**
|
||
* Hook for the on drop handler, executes after the drop logic has concluded
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @param {Object} e jQuery object that contains the properties on the
|
||
* drop event
|
||
* @param {Object} ui jQuery object that contains the properties on the
|
||
* drop event
|
||
* @template
|
||
* @protected
|
||
*/
|
||
DropBehavior.prototype.dropEndHook = function (shape, e, ui) {
|
||
return true;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.DropBehavior', DropBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = DropBehavior;
|
||
}
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.ConnectionDropBehavior
|
||
* Class that encapsulates the drop behavior for dropped connections in shapes
|
||
* @extends PMUI.behavior.DropBehavior
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class
|
||
* @param selectors
|
||
*/
|
||
var ConnectionDropBehavior = function (selectors) {
|
||
ConnectionDropBehavior.superclass.call(this, selectors);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.DropBehavior', ConnectionDropBehavior);
|
||
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
ConnectionDropBehavior.prototype.type = "ConnectionDropBehavior";
|
||
/**
|
||
* Defaults selectors for this drop behavior
|
||
* @property {String}
|
||
*/
|
||
ConnectionDropBehavior.prototype.defaultSelector = ".custom_shape,.port";
|
||
|
||
/**
|
||
* Sets the selectors for this drop behavior including the defaults
|
||
* @param selectors
|
||
* @param overwrite
|
||
* @return {*}
|
||
*/
|
||
ConnectionDropBehavior.prototype.setSelectors = function (selectors, overwrite) {
|
||
ConnectionDropBehavior.superclass.prototype.setSelectors.call(this, selectors, overwrite);
|
||
this.selectors.push(".port");
|
||
this.selectors.push(".custom_shape");
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Drag enter hook for this drop behavior, marks that a shape is over a
|
||
* droppable element
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @return {Function}
|
||
*/
|
||
ConnectionDropBehavior.prototype.onDragEnter = function (shape) {
|
||
return function (e, ui) {
|
||
shape.entered = true;
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Drag leave hook for this drop behavior, marks that a shape has left a
|
||
* droppable element
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @return {Function}
|
||
*/
|
||
ConnectionDropBehavior.prototype.onDragLeave = function (shape) {
|
||
return function (e, ui) {
|
||
shape.entered = false;
|
||
};
|
||
};
|
||
/**
|
||
* On drop handler for this drop behavior, creates a connection between the
|
||
* droppable element and the dropped element, or move ports among those shapes
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @return {Function}
|
||
*/
|
||
ConnectionDropBehavior.prototype.onDrop = function (shape) {
|
||
var that = this;
|
||
return function (e, ui) {
|
||
var canvas = shape.getCanvas(),
|
||
id = ui.draggable.attr('id'),
|
||
x,
|
||
y,
|
||
currLeft,
|
||
currTop,
|
||
startPoint,
|
||
sourceShape,
|
||
sourcePort,
|
||
realPoint,
|
||
endPort,
|
||
endPortXCoord,
|
||
endPortYCoord,
|
||
connection,
|
||
currentConnection = canvas.currentConnection,
|
||
srcPort,
|
||
dstPort,
|
||
port,
|
||
success = false,
|
||
command;
|
||
shape.entered = false;
|
||
if (!shape.dropBehavior.dropStartHook(shape, e, ui)) {
|
||
return false;
|
||
}
|
||
if (shape.getConnectionType() === "none") {
|
||
return true;
|
||
}
|
||
if (currentConnection) {
|
||
srcPort = currentConnection.srcPort;
|
||
dstPort = currentConnection.destPort;
|
||
if (srcPort.id === id) {
|
||
port = srcPort;
|
||
} else if (dstPort.id === id) {
|
||
port = dstPort;
|
||
} else {
|
||
port = null;
|
||
}
|
||
}
|
||
if (ui.helper && ui.helper.attr('id') === "drag-helper") {
|
||
|
||
// If its the helper then we need to create two ports and draw a
|
||
// connection.
|
||
// We get the points and the corresponding shapes involved
|
||
startPoint = shape.canvas.connectionSegment.startPoint;
|
||
sourceShape = shape.canvas.connectionSegment.pointsTo;
|
||
// Determine the points where the helper was created
|
||
if (sourceShape.parent && sourceShape.parent.id === shape.id) {
|
||
return true;
|
||
}
|
||
sourceShape.setPosition(sourceShape.oldX, sourceShape.oldY);
|
||
|
||
// Create the ports
|
||
sourcePort = new PMUI.draw.Port({
|
||
width: 8,
|
||
height: 8
|
||
});
|
||
endPort = new PMUI.draw.Port({
|
||
width: 8,
|
||
height: 8
|
||
});
|
||
|
||
realPoint = shape.canvas.relativePoint(e);
|
||
|
||
// Determine the position where the helper was dropped
|
||
endPortXCoord = ui.offset.left - shape.canvas.getX() -
|
||
shape.getAbsoluteX() + shape.canvas.getLeftScroll();
|
||
endPortYCoord = ui.offset.top - shape.canvas.getY() -
|
||
shape.getAbsoluteY() + shape.canvas.getTopScroll();
|
||
|
||
// Add ports to the corresponding shapes
|
||
// AddPort() determines the position of the ports
|
||
sourceShape.addPort(sourcePort, startPoint.x, startPoint.y);
|
||
shape.addPort(endPort, endPortXCoord, endPortYCoord,
|
||
false, sourcePort);
|
||
|
||
// Create the connection
|
||
connection = new PMUI.draw.Connection({
|
||
srcPort: sourcePort,
|
||
destPort: endPort,
|
||
canvas: shape.canvas,
|
||
segmentStyle: shape.connectionType
|
||
});
|
||
|
||
// Set its decorators
|
||
connection.setSrcDecorator(new PMUI.draw.ConnectionDecorator({
|
||
width: 11,
|
||
height: 11,
|
||
canvas: canvas,
|
||
decoratorPrefix: "con_normal",
|
||
decoratorType: "source",
|
||
parent: connection
|
||
}));
|
||
connection.setDestDecorator(new PMUI.draw.ConnectionDecorator({
|
||
width: 11,
|
||
height: 11,
|
||
canvas: canvas,
|
||
decoratorPrefix: "con_normal",
|
||
decoratorType: "target",
|
||
parent: connection
|
||
}));
|
||
|
||
connection.canvas.commandStack.add(new PMUI.command.CommandConnect(connection));
|
||
|
||
// Connect the two ports
|
||
connection.connect();
|
||
connection.setSegmentMoveHandlers();
|
||
|
||
// Add the connection to the canvas, that means insert its html to
|
||
// the DOM and adding it to the connections array
|
||
canvas.addConnection(connection);
|
||
|
||
// Now that the connection was drawn try to create the intersections
|
||
connection.checkAndCreateIntersectionsWithAll();
|
||
|
||
// Attaching port listeners
|
||
sourcePort.attachListeners(sourcePort);
|
||
endPort.attachListeners(endPort);
|
||
|
||
// Finally trigger createEvent
|
||
canvas.triggerCreateEvent(connection, []);
|
||
} else if (port) {
|
||
|
||
port.setOldParent(port.getParent());
|
||
port.setOldX(port.getX());
|
||
port.setOldY(port.getY());
|
||
|
||
x = ui.position.left;
|
||
y = ui.position.top;
|
||
port.setPosition(x, y);
|
||
shape.dragging = false;
|
||
if (shape.getID() !== port.parent.getID()) {
|
||
port.parent.removePort(port);
|
||
currLeft = ui.offset.left - canvas.getX() -
|
||
shape.absoluteX + shape.canvas.getLeftScroll();
|
||
currTop = ui.offset.top - canvas.getY() -
|
||
shape.absoluteY + shape.canvas.getTopScroll();
|
||
shape.addPort(port, currLeft, currTop, true);
|
||
canvas.regularShapes.insert(port);
|
||
} else {
|
||
shape.definePortPosition(port, port.getPoint(true));
|
||
}
|
||
|
||
// LOGIC: when portChangeEvent is triggered it gathers the state
|
||
// of the connection but since at this point there's only a segment
|
||
// let's paint the connection, gather the state and then disconnect
|
||
// it (the connection is later repainted on, I don't know how)
|
||
port.connection.connect();
|
||
canvas.triggerPortChangeEvent(port);
|
||
port.connection.disconnect();
|
||
|
||
command = new PMUI.command.CommandReconnect(port);
|
||
port.canvas.commandStack.add(command);
|
||
}
|
||
return false;
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ConnectionDropBehavior', ConnectionDropBehavior);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.ContainerDropBehavior
|
||
* Encapsulates the drop behavior of a container
|
||
* @extends PMUI.behavior.DropBehavior
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class
|
||
* @param {Array} [selectors=[]] css selectors that this drop behavior will
|
||
* accept
|
||
*/
|
||
var ContainerDropBehavior = function (selectors) {
|
||
ContainerDropBehavior.superclass.call(this, selectors);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.DropBehavior', ContainerDropBehavior);
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
ContainerDropBehavior.prototype.type = "ContainerDropBehavior";
|
||
/**
|
||
* Default selectors for this drop behavior
|
||
* @property {String}
|
||
*/
|
||
ContainerDropBehavior.prototype.defaultSelector = ".custom_shape";
|
||
|
||
/**
|
||
* On drop handler for this drop behavior, creates shapes when dropped from the
|
||
* toolbar, or move shapes among containers
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @return {Function}
|
||
*/
|
||
ContainerDropBehavior.prototype.onDrop = function (shape) {
|
||
return function (e, ui) {
|
||
var customShape = null,
|
||
canvas = shape.getCanvas(),
|
||
selection,
|
||
sibling,
|
||
i,
|
||
command,
|
||
coordinates,
|
||
id,
|
||
shapesAdded = [],
|
||
containerBehavior = shape.containerBehavior;
|
||
if (canvas.readOnly) {
|
||
return false;
|
||
}
|
||
|
||
shape.entered = false;
|
||
if (ui.helper && ui.helper.attr('id') === "drag-helper") {
|
||
return false;
|
||
}
|
||
id = ui.draggable.attr('id');
|
||
|
||
customShape = canvas.shapeFactory(id);
|
||
if (customShape === null) {
|
||
|
||
customShape = canvas.customShapes.find('id', id);
|
||
if (!customShape || !shape.dropBehavior.dropHook(shape, e, ui)) {
|
||
return false;
|
||
}
|
||
|
||
if (!(customShape.parent &&
|
||
customShape.parent.id === shape.id)) {
|
||
|
||
selection = canvas.currentSelection;
|
||
for (i = 0; i < selection.getSize(); i += 1) {
|
||
sibling = selection.get(i);
|
||
coordinates = PMUI.getPointRelativeToPage(sibling);
|
||
coordinates = PMUI.pageCoordinatesToShapeCoordinates(shape, null,
|
||
coordinates.x, coordinates.y, customShape);
|
||
shapesAdded.push({
|
||
shape: sibling,
|
||
container: shape,
|
||
x: coordinates.x,
|
||
y: coordinates.y,
|
||
topLeft: false
|
||
});
|
||
}
|
||
command = new PMUI.command.CommandSwitchContainer(shapesAdded);
|
||
command.execute();
|
||
canvas.commandStack.add(command);
|
||
canvas.multipleDrop = true;
|
||
|
||
}
|
||
|
||
// Fix resize minWidth and minHeight and also fix the dimension
|
||
// of this shape (if a child made it grow)
|
||
shape.updateDimensions(10);
|
||
canvas.updatedElement = null;
|
||
|
||
} else {
|
||
coordinates = PMUI.pageCoordinatesToShapeCoordinates(shape, e,null,null,customShape);
|
||
if (PMUI.validCoordinatedToCreate(shape, e, customShape)) {
|
||
shape.addElement(customShape, coordinates.x, coordinates.y,
|
||
customShape.topLeftOnCreation);
|
||
|
||
// Since it is a new element in the designer, we triggered the
|
||
// custom on create element event
|
||
canvas.updatedElement = customShape;
|
||
|
||
// Create the command for this new shape
|
||
command = new PMUI.command.CommandCreate(customShape);
|
||
canvas.commandStack.add(command);
|
||
command.execute();
|
||
canvas.hideAllFocusLabels();
|
||
if (customShape.label) {
|
||
customShape.label.getFocus();
|
||
}
|
||
}
|
||
}
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerDropBehavior', ContainerDropBehavior);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.ConnectionContainerDropBehavior
|
||
* Class that encapsulates the drop behaviors for containers that can also be
|
||
* connected
|
||
* @extends PMUI.behavior.DropBehavior
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class
|
||
* @param {Array} [selectors=[]] css selectors that this drop behavior will
|
||
* accept
|
||
*/
|
||
var ConnectionContainerDropBehavior = function (selectors) {
|
||
ConnectionContainerDropBehavior.superclass.call(this, selectors);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.DropBehavior', ConnectionContainerDropBehavior);
|
||
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
ConnectionContainerDropBehavior.prototype.type = "ConnectionContainerDropBehavior";
|
||
/**
|
||
* Default selectors for this drop behavior
|
||
* @property {String}
|
||
*/
|
||
ConnectionContainerDropBehavior.prototype.defaultSelector = ".custom_shape,.port";
|
||
/**
|
||
* Set the selectors for this drop behavior including the default selectors
|
||
* @param {Array} selectors css selectors
|
||
* @param {boolean} overwrite
|
||
* @return {*}
|
||
*/
|
||
ConnectionContainerDropBehavior.prototype.setSelectors = function (selectors, overwrite) {
|
||
ConnectionContainerDropBehavior.superclass.prototype
|
||
.setSelectors.call(this, selectors, overwrite);
|
||
this.selectors.push(".port");
|
||
this.selectors.push(".custom_shape");
|
||
return this;
|
||
};
|
||
/**
|
||
* On drop handler for this drop behavior, determines whether to create a
|
||
* connection or add a shape to the container that is using this drop behavior
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @return {Function}
|
||
*/
|
||
ConnectionContainerDropBehavior.prototype.onDrop = function (shape) {
|
||
return function (e, ui) {
|
||
if (!PMUI.behavior.ConnectionDropBehavior.prototype.onDrop.call(this, shape)(e, ui)) {
|
||
PMUI.behavior.ContainerDropBehavior.prototype.onDrop.call(this, shape)(e, ui);
|
||
}
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ConnectionContainerDropBehavior',
|
||
ConnectionContainerDropBehavior);
|
||
}());
|
||
|
||
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.NoDropBehavior
|
||
* Encapsulates the drop behavior representing an object that can't be droppable
|
||
* @extends PMUI.behavior.DropBehavior
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class
|
||
*/
|
||
var NoDropBehavior = function (selectors) {
|
||
NoDropBehavior.superclass.call(this, selectors);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.DropBehavior', NoDropBehavior);
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
NoDropBehavior.prototype.type = "NoDropBehavior";
|
||
/**
|
||
* Attach the drop behavior, sets the accepted elements to none
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
NoDropBehavior.prototype.attachDropBehavior = function (shape) {
|
||
//var $shape = $(shape.getHTML());
|
||
//NoDropBehavior.superclass.prototype.attachDropBehavior.call(this, shape);
|
||
//$(shape).droppable({ accept: "" });
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.NoDropBehavior', NoDropBehavior);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = NoDropBehavior;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @abstract
|
||
* @class PMUI.behavior.ContainerBehavior
|
||
* Object that encapsulates the container of shapes, this is an abstract class,
|
||
* so all its methods should be implemented by its subclasses
|
||
|
||
* @constructor
|
||
* Creates a new instance of the class
|
||
*/
|
||
var ContainerBehavior = function () {
|
||
};
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
ContainerBehavior.prototype.type = "ContainerBehavior";
|
||
/**
|
||
* Family of the instances
|
||
* @property {String}
|
||
*/
|
||
ContainerBehavior.prototype.family = "ContainerBehavior";
|
||
/**
|
||
* @abstract
|
||
* Sets a shape's container to a given container
|
||
* @param {PMUI.draw.BehavioralElement} container element using this behavior
|
||
* @param {PMUI.draw.Shape} shape shape to be added
|
||
* @template
|
||
* @protected
|
||
*/
|
||
ContainerBehavior.prototype.addToContainer = function (container, shape, x, y, topLeftCorner) {
|
||
};
|
||
/**
|
||
* @abstract
|
||
* Removes shape from its current container
|
||
* @param {PMUI.draw.Shape} shape shape to be removed
|
||
* @template
|
||
* @protected
|
||
*/
|
||
ContainerBehavior.prototype.removeFromContainer = function (shape) {
|
||
};
|
||
/**
|
||
* @abstract
|
||
* Adds a shape to a given container
|
||
* @param {PMUI.draw.BehavioralElement} container container element using this behavior
|
||
* @param {PMUI.draw.Shape} shape shape to be added to the container
|
||
* @template
|
||
* @protected
|
||
*/
|
||
ContainerBehavior.prototype.addShape = function (container, shape, x, y) {
|
||
};
|
||
/**
|
||
* Returns whether a shape is a container or not
|
||
* @return {boolean}
|
||
*/
|
||
ContainerBehavior.prototype.isContainer = function () {
|
||
return false;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerBehavior', ContainerBehavior);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = ContainerBehavior;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.RegularContainerBehavior
|
||
* Encapsulates the behavior of a regular container
|
||
* @extends PMUI.behavior.ContainerBehavior
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class
|
||
*/
|
||
var RegularContainerBehavior = function () {
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ContainerBehavior', RegularContainerBehavior);
|
||
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
RegularContainerBehavior.prototype.type = "RegularContainerBehavior";
|
||
/**
|
||
* Adds a shape to a given container given its coordinates
|
||
* @param {PMUI.draw.BehavioralElement} container container using this behavior
|
||
* @param {PMUI.draw.Shape} shape shape to be added
|
||
* @param {number} x x coordinate where the shape will be added
|
||
* @param {number} y y coordinate where the shape will be added
|
||
* @param {boolean} topLeftCorner Determines whether the x and y coordinates
|
||
* will be considered from the top left corner or from the center
|
||
*/
|
||
RegularContainerBehavior.prototype.addToContainer = function (container, shape, x, y, topLeftCorner) {
|
||
var shapeLeft = 0,
|
||
shapeTop = 0,
|
||
shapeWidth,
|
||
shapeHeight,
|
||
canvas,
|
||
topLeftFactor = (topLeftCorner === true) ? 0 : 1;
|
||
|
||
if (container.family === "Canvas") {
|
||
canvas = container;
|
||
} else {
|
||
canvas = container.canvas;
|
||
}
|
||
|
||
|
||
shapeWidth = shape.getZoomWidth();
|
||
shapeHeight = shape.getZoomHeight();
|
||
|
||
shapeLeft += x - (shapeWidth / 2) * topLeftFactor;
|
||
shapeTop += y - (shapeHeight / 2) * topLeftFactor;
|
||
|
||
shapeLeft /= canvas.zoomFactor;
|
||
shapeTop /= canvas.zoomFactor;
|
||
|
||
shape.setParent(container);
|
||
container.getChildren().insert(shape);
|
||
this.addShape(container, shape, shapeLeft, shapeTop);
|
||
|
||
// fix the zIndex of this shape and it's children
|
||
shape.fixZIndex(shape, 0);
|
||
|
||
// fix resize minWidth and minHeight and also fix the dimension
|
||
// of this shape (if a child made it grow)
|
||
container.updateDimensions(10);
|
||
|
||
// adds the shape to either the customShape arrayList or the regularShapes
|
||
// arrayList if possible
|
||
canvas.addToList(shape);
|
||
};
|
||
/**
|
||
* Removes a shape from the container implementing this behavior
|
||
* @param {PMUI.draw.Shape} shape shape to be removed
|
||
*/
|
||
RegularContainerBehavior.prototype.removeFromContainer = function (shape) {
|
||
var parent = shape.parent;
|
||
parent.getChildren().remove(shape);
|
||
if (parent.isResizable()) {
|
||
parent.resizeBehavior.updateResizeMinimums(shape.parent);
|
||
}
|
||
shape.parent = null;
|
||
};
|
||
/**
|
||
* Sets the position of the shape, and append its html
|
||
* @param {PMUI.draw.BehavioralElement} container element implementing this behavior
|
||
* @param {PMUI.draw.Shape} shape shape added to the container
|
||
* @param {number} x x coordinate of the position that will be set relative to
|
||
* the container
|
||
* @param {number} y y coordinate of the position that will be set relative to
|
||
* the container
|
||
* @chainable
|
||
*/
|
||
RegularContainerBehavior.prototype.addShape = function (container, shape, x, y) {
|
||
shape.setPosition(x, y);
|
||
//insert the shape HTML to the DOM
|
||
container.getHTML().appendChild(shape.getHTML());
|
||
|
||
shape.updateHTML();
|
||
shape.paint();
|
||
shape.applyBehaviors();
|
||
shape.attachListeners();
|
||
return this;
|
||
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.RegularContainerBehavior', RegularContainerBehavior);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = RegularContainerBehavior;
|
||
}
|
||
|
||
}());
|
||
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.NoContainerBehavior
|
||
* Encapsulates the behavior of elements that has no container behavior, useful
|
||
* for implementing the strategy pattern
|
||
* @extends PMUI.behavior.ContainerBehavior
|
||
*
|
||
*
|
||
* @constructor
|
||
* Creates a new instance of the class
|
||
*/
|
||
var NoContainerBehavior = function () {
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ContainerBehavior', NoContainerBehavior);
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
NoContainerBehavior.prototype.type = "NoContainerBehavior";
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.NoContainerBehavior', NoContainerBehavior);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = NoContainerBehavior;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @abstract
|
||
* @class PMUI.behavior.ResizeBehavior
|
||
* Abstract class which inherited classes' instances are used for delegation of the resize behavior of a shape.
|
||
*
|
||
* @constructor Creates an instance of the class ResizeBehavior
|
||
*/
|
||
var ResizeBehavior = function () {
|
||
};
|
||
|
||
/**
|
||
* The type of each instance of this class.
|
||
* @property {String}
|
||
*/
|
||
ResizeBehavior.prototype.type = "ResizeBehavior";
|
||
|
||
/**
|
||
* The family of each instance of this class.
|
||
* @property {String}
|
||
*/
|
||
ResizeBehavior.prototype.family = "ResizeBehavior";
|
||
|
||
|
||
/**
|
||
* Initialize JQueryUI's resize plugin
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
ResizeBehavior.prototype.init = function (shape) {
|
||
var $shape = $(shape.getHTML()),
|
||
shapeResizeOptions = {
|
||
handles: shape.getHandlesIDs(),
|
||
disable: false,
|
||
start: this.onResizeStart(shape),
|
||
resize: this.onResize(shape),
|
||
stop: this.onResizeEnd(shape)
|
||
};
|
||
$shape.resizable(shapeResizeOptions);
|
||
};
|
||
|
||
/**
|
||
* @abstract
|
||
* @event resizeStart
|
||
* Abstract method to be implemented in inherited classes
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
ResizeBehavior.prototype.onResizeStart = function (shape) {
|
||
};
|
||
/**
|
||
* @abstract
|
||
* @event resize
|
||
* Abstract method to be implemented in inherited classes
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
ResizeBehavior.prototype.onResize = function (shape) {
|
||
};
|
||
/**
|
||
* @abstract
|
||
* @event resizeEnd
|
||
* Abstract method to be implemented in inherited classes
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
ResizeBehavior.prototype.onResizeEnd = function (shape) {
|
||
};
|
||
/**
|
||
* Updates the minimum height and maximum height of the JQqueryUI's resizable plugin.
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @chainable
|
||
*/
|
||
ResizeBehavior.prototype.updateResizeMinimums = function (shape) {
|
||
var minW,
|
||
minH,
|
||
children = shape.getChildren(),
|
||
limits = children.getDimensionLimit(),
|
||
margin = 15,
|
||
$shape = $(shape.getHTML());
|
||
|
||
// TODO: consider the labels width and height
|
||
minW = limits[1] + margin;
|
||
minH = limits[2] + margin;
|
||
|
||
// update jQueryUI's minWidth and minHeight
|
||
$shape.resizable();
|
||
$shape.resizable('option', 'minWidth', minW);
|
||
$shape.resizable('option', 'minHeight', minH);
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ResizeBehavior', ResizeBehavior);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = ResizeBehavior;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.NoResizeBehavior
|
||
* Class that encapsulates the regular resize behavior of a shape when it's not supposed to be resizable
|
||
* @extends PMUI.behavior.ResizeBehavior
|
||
*
|
||
* @constructor Creates a new instance of the class RegularResizeBehavior
|
||
*/
|
||
var NoResizeBehavior = function () {
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ResizeBehavior', NoResizeBehavior);
|
||
|
||
/**
|
||
* The type of each instance of this class.
|
||
* @property {String}
|
||
*/
|
||
NoResizeBehavior.prototype.type = "NoResizeBehavior";
|
||
|
||
/**
|
||
* Initialize JQueryUI's resize plugin (disables the resizable plugin).
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
NoResizeBehavior.prototype.init = function (shape) {
|
||
var $shape = $(shape.getHTML());
|
||
NoResizeBehavior.superclass.prototype.init.call(this, shape);
|
||
$shape.resizable('disable');
|
||
$shape
|
||
.removeClass('ui-state-disabled');
|
||
shape.applyStyleToHandlers('nonResizableStyle');
|
||
shape.showOrHideResizeHandlers(false);
|
||
};
|
||
|
||
/**
|
||
* Overwrites the method {@link PMUI.behavior.ResizeBehavior#updateResizeMinimums} since
|
||
* a shape that is not resizable shouldn't update its resize minimums.
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
NoResizeBehavior.prototype.updateResizeMinimums = function (shape) {
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.NoResizeBehavior', NoResizeBehavior);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = NoResizeBehavior;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.RegularResizeBehavior
|
||
* Class that encapsulates the regular resize behavior of a shape
|
||
* @extends PMUI.behavior.ResizeBehavior
|
||
*
|
||
* @constructor Creates a new instance of the class RegularResizeBehavior
|
||
*/
|
||
var RegularResizeBehavior = function () {
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ResizeBehavior', RegularResizeBehavior);
|
||
|
||
/**
|
||
* The type of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
RegularResizeBehavior.prototype.type = "RegularResizeBehavior";
|
||
|
||
/**
|
||
* Initialize JQueryUI's resizable plugin
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
RegularResizeBehavior.prototype.init = function (shape) {
|
||
var $shape = $(shape.getHTML());
|
||
RegularResizeBehavior.superclass.prototype.init.call(this, shape);
|
||
$shape.resizable('enable');
|
||
shape.applyStyleToHandlers('resizableStyle');
|
||
|
||
// hide its handles (jQueryUI's resizable shows the handles by default)
|
||
shape.showOrHideResizeHandlers(false);
|
||
};
|
||
|
||
/**
|
||
* @event resizeStart
|
||
* ResizeStart event fired when the user resizes a shape.
|
||
* It does the following:
|
||
*
|
||
* - Save old values (for the undo-redo stack)
|
||
* - Empties the {@link PMUI.draw.Canvas#property-currentSelection}, and adds `shape` to that arrayList
|
||
* - Hides the resize handlers of the shape
|
||
*
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
RegularResizeBehavior.prototype.onResizeStart = function (shape) {
|
||
return function (e, ui) {
|
||
shape.resizing = true;
|
||
shape.canvas.isResizing = true;
|
||
shape.dragging = false;
|
||
|
||
shape.oldWidth = shape.width;
|
||
shape.oldHeight = shape.height;
|
||
shape.oldX = shape.x;
|
||
shape.oldY = shape.y;
|
||
shape.oldAbsoluteX = shape.absoluteX;
|
||
shape.oldAbsoluteY = shape.absoluteY;
|
||
|
||
if (shape.ports) {
|
||
shape.initPortsChange();
|
||
}
|
||
|
||
if (shape.canvas.currentSelection.getSize() > 1) {
|
||
shape.canvas.emptyCurrentSelection();
|
||
shape.canvas.addToSelection(shape);
|
||
}
|
||
shape.showOrHideResizeHandlers(false);
|
||
shape.calculateLabelsPercentage();
|
||
shape.canvas.hideAllFocusLabels();
|
||
return true;
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event resize
|
||
* Resize event fired when the user is resizing a shape.
|
||
* It does the following:
|
||
*
|
||
* - Sets the position and dimensions of the shape
|
||
* - Fixes the ports of `shape` and from the its children (recursively)
|
||
* - Updates the position of its labels
|
||
*
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
RegularResizeBehavior.prototype.onResize = function (shape) {
|
||
return function (e, ui) {
|
||
var i,
|
||
port,
|
||
canvas = shape.canvas;
|
||
shape.setPosition(ui.position.left / canvas.zoomFactor,
|
||
ui.position.top / canvas.zoomFactor);
|
||
shape.setDimension(ui.size.width / canvas.zoomFactor,
|
||
ui.size.height / canvas.zoomFactor);
|
||
|
||
// fix the position of the shape's ports (and the positions and port
|
||
// position of its children)
|
||
// parameters (shape, resizing, root)
|
||
shape.fixConnectionsOnResize(shape.resizing, true);
|
||
// fix the labels positions on resize (on x = true and y = true)
|
||
shape.updateLabelsPosition();
|
||
shape.canvas.hideAllFocusLabels();
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event resizeEnd
|
||
* ResizeEnd event fired when the user stops resizing a shape.
|
||
* It does the following:
|
||
*
|
||
* - Shows the handlers of `shape`
|
||
* - Updates the dimension of its parent (this shape might have outgrown the shape)
|
||
* - Creates an instance of {@link PMUI.command.CommandResize} to add it to the undo-redo stack
|
||
*
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
RegularResizeBehavior.prototype.onResizeEnd = function (shape) {
|
||
return function (e, ui) {
|
||
var i,
|
||
label,
|
||
command;
|
||
shape.resizing = false;
|
||
shape.canvas.isResizing = false;
|
||
// last resize
|
||
RegularResizeBehavior.prototype.onResize.call(this, shape)(e, ui);
|
||
|
||
// show the handlers again
|
||
shape.showOrHideResizeHandlers(true);
|
||
|
||
// update the dimensions of the parent if possible (a shape might
|
||
// have been resized out of the dimensions of its parent)
|
||
shape.parent.updateDimensions(10);
|
||
|
||
if (shape.ports) {
|
||
shape.firePortsChange();
|
||
}
|
||
|
||
// TESTING COMMANDS
|
||
command = new PMUI.command.CommandResize(shape);
|
||
shape.canvas.commandStack.add(command);
|
||
command.execute();
|
||
for (i = 0; i < shape.labels.getSize(); i += 1) {
|
||
label = shape.labels.get(i);
|
||
label.setLabelPosition(label.location, label.diffX, label.diffY);
|
||
}
|
||
|
||
return true;
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.RegularResizeBehavior', RegularResizeBehavior);
|
||
|
||
if (typeof exports !== 'undefined'){
|
||
module.exports = RegularResizeBehavior;
|
||
}
|
||
|
||
}());
|
||
|
||
(function() {
|
||
var DataControlDropBehavior = function(settings) {
|
||
DataControlDropBehavior.superclass.call(this, settings);
|
||
this.targetObject = null;
|
||
this.scope = null;
|
||
this.hoverClass = null;
|
||
DataControlDropBehavior.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.DropBehavior', DataControlDropBehavior);
|
||
|
||
DataControlDropBehavior.prototype.init = function(settings) {
|
||
var defaults = {
|
||
scope: 'pmui-datacontrol-dragdrop-scope',
|
||
hoverClass: 'pmui-dataControl-drag-over'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
if(!defaults.targetObject) {
|
||
throw new Error("The target object wasn't specified.");
|
||
}
|
||
|
||
this.targetObject = defaults.targetObject;
|
||
this.hoverClass = defaults.hoverClass;
|
||
this.setScope(defaults.scope);
|
||
};
|
||
|
||
DataControlDropBehavior.prototype.setScope = function(scope) {
|
||
if(typeof scope === 'string') {
|
||
this.scope = scope;
|
||
} else {
|
||
throw new Error("setScope(): the parameter must be a string.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
DataControlDropBehavior.prototype.attachDropBehavior = function() {
|
||
var html = this.targetObject.getHTML();
|
||
|
||
$(html).droppable({
|
||
greedy: true,
|
||
scope: this.scope,
|
||
hoverClass: this.hoverClass,
|
||
drop: this.onDrop(),
|
||
over: this.onDragEnter(),
|
||
out: this.onDragLeave()
|
||
});
|
||
|
||
return this;
|
||
};
|
||
|
||
DataControlDropBehavior.prototype.onDragLeave = function() {
|
||
return (this.targetObject.onDragLeaveHandler && this.targetObject.onDragLeaveHandler()) || null;
|
||
};
|
||
|
||
DataControlDropBehavior.prototype.onDragEnter = function() {
|
||
return (this.targetObject.onDragEnterHandler && this.targetObject.onDragEnterHandler()) || null;
|
||
};
|
||
|
||
DataControlDropBehavior.prototype.onDrop = function() {
|
||
var targetObject = this.targetObject;
|
||
return function(e, ui) {
|
||
var data = $(ui.draggable).data('pmui-datacontrol-data');
|
||
data.currentContainer.removeItem(data.index);
|
||
ui.helper.remove();
|
||
targetObject.addItem(data.data);
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.DataControlDropBehavior', DataControlDropBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = DataControlDropBehavior;
|
||
}
|
||
}());
|
||
(function() {
|
||
var DataControlNoDropBehavior = function(settings) {
|
||
DataControlNoDropBehavior.superclass.call(this, settings);
|
||
this.targetObject = null;
|
||
DataControlNoDropBehavior.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.NoDropBehavior', DataControlNoDropBehavior);
|
||
|
||
DataControlNoDropBehavior.prototype.init = function(settings) {
|
||
if(!settings.targetObject) {
|
||
throw new Error("The target object wasn't specified.");
|
||
}
|
||
|
||
this.targetObject = settings.targetObject;
|
||
};
|
||
|
||
DataControlNoDropBehavior.prototype.attachDropBehavior = function() {
|
||
var html = this.targetObject.getHTML();
|
||
|
||
try {
|
||
$(html).droppable('destroy');
|
||
} catch(e) {}
|
||
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.DataControlNoDropBehavior', DataControlNoDropBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = DataControlNoDropBehavior;
|
||
}
|
||
}());
|
||
(function () {
|
||
var DataControlDragBehavior = function (settings) {
|
||
DataControlDragBehavior.superclass.call(this, settings);
|
||
this.targetObject = null;
|
||
this.scope = null;
|
||
this.helper = null;
|
||
DataControlDragBehavior.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.DragBehavior', DataControlDragBehavior);
|
||
|
||
DataControlDragBehavior.prototype.init = function (settings) {
|
||
var defaults = {
|
||
scope: 'pmui-datacontrol-dragdrop-scope',
|
||
helper: 'original'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
//TODO: uncomment the following validation when the GridPanel's rows are handled through objects.
|
||
//by now it will accept html elements as the targetObject option.
|
||
/*if(!defaults.targetObject || typeof defaults.targetObject !== 'object') {
|
||
throw new Error("The target object is null or invalid.");
|
||
}*/
|
||
|
||
if (!defaults.targetObject) {
|
||
throw new Error("The target object is null or invalid.");
|
||
}
|
||
this.targetObject = defaults.targetObject;
|
||
this.helper = defaults.helper;
|
||
this.scope = defaults.scope;
|
||
};
|
||
|
||
DataControlDragBehavior.prototype.onReceiveHandler = function () {
|
||
var targetObject = this.targetObject;
|
||
return function (e, ui) {
|
||
var row,
|
||
index,
|
||
newIndex,
|
||
diff,
|
||
globalIndex,
|
||
grid,
|
||
auxArray;
|
||
row = ui.item.data("pmui-datacontrol-data");
|
||
grid = row.parent;
|
||
//remove the item from its previous grid
|
||
index = grid.getRowIndex(row);
|
||
grid.items.asArray().splice(index, 1);
|
||
grid.goToPage(grid.currentPage);
|
||
//append the object to the new grid
|
||
newIndex = $(targetObject.dom.tbody).find('tr').index(ui.item);
|
||
$(ui.item).detach();
|
||
targetObject.addItem(row, newIndex);
|
||
row.setCells();
|
||
};
|
||
};
|
||
|
||
DataControlDragBehavior.prototype.onDropHandler = function () {
|
||
return function (e, ui) {
|
||
if (ui.item.parent().get(0) === this) {
|
||
var row,
|
||
index,
|
||
newIndex,
|
||
diff,
|
||
globalIndex,
|
||
grid,
|
||
auxArray;
|
||
row = ui.item.data("pmui-datacontrol-data");
|
||
grid = row.parent;
|
||
index = row.parent.indexInPage(row);
|
||
newIndex = $(grid.dom.tbody).find('tr').index(ui.item);
|
||
diff = newIndex - index;
|
||
newIndex = index + diff;
|
||
globalIndex = grid.getRowIndex(row);
|
||
row = grid.items.asArray().splice(globalIndex, 1)[0];
|
||
newIndex = globalIndex + diff;
|
||
grid.items.asArray().splice(newIndex, 0, row);
|
||
}
|
||
};
|
||
};
|
||
|
||
DataControlDragBehavior.prototype.attachDragBehavior = function () {
|
||
var $html,
|
||
i,
|
||
items,
|
||
item,
|
||
index,
|
||
row,
|
||
object = this.targetObject;
|
||
items = this.targetObject.getItems();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
item = $(items[i].getHTML()).data("pmui-datacontrol-data", (function (j) {
|
||
return object.items.get(j);
|
||
}(i)));
|
||
if (!$html) {
|
||
$html = jQuery(item);
|
||
} else {
|
||
$html = $html.add(item);
|
||
}
|
||
}
|
||
|
||
try {
|
||
$(this.targetObject.dom.tbody).sortable("destroy");
|
||
} catch (e) {
|
||
}
|
||
|
||
$(this.targetObject.dom.tbody).sortable({
|
||
connectWith: '.pmui-gridpanel-tbody',
|
||
update: this.onDropHandler(),
|
||
receive: this.onReceiveHandler()
|
||
});
|
||
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.DataControlDragBehavior', DataControlDragBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = DataControlDragBehavior;
|
||
}
|
||
}());
|
||
(function () {
|
||
var DataControlNoDragBehavior = function (settings) {
|
||
DataControlNoDragBehavior.superclass.call(this, settings);
|
||
this.targetObject = null;
|
||
DataControlNoDragBehavior.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.NoDragBehavior', DataControlNoDragBehavior);
|
||
|
||
DataControlNoDragBehavior.prototype.init = function (settings) {
|
||
//TODO: uncomment the following validation when the GridPanel's rows are handled through objects.
|
||
//by now it will accept html elements as the targetObject option.
|
||
/*if(!defaults.targetObject || typeof defaults.targetObject !== 'object') {
|
||
throw new Error("The target object is null or invalid.");
|
||
}*/
|
||
this.targetObject = settings.targetObject;
|
||
};
|
||
|
||
DataControlNoDragBehavior.prototype.attachDragBehavior = function () {
|
||
var $html,
|
||
i,
|
||
items,
|
||
item;
|
||
|
||
if (this.targetObject instanceof PMUI.panel.GridPanel) {
|
||
html = $(this.targetObject.getHTML()).find('tr');
|
||
} else {
|
||
items = this.targetObject.getItems();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
item = $(items[i].getHTML()).data("'pmui-datacontrol-data'", items[i]);
|
||
if (!$html) {
|
||
$html = jQuery(item);
|
||
} else {
|
||
$html = $html.add(item);
|
||
}
|
||
}
|
||
}
|
||
try {
|
||
$(html).draggable("destroy");
|
||
} catch (e) {
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.DataControlNoDragBehavior', DataControlNoDragBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = DataControlNoDragBehavior;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.ContainerItemBehavior
|
||
* Abstract class that encapsulates common properties ans functionality for the specific behaviors that can be
|
||
* attached to the Container's subclasses.
|
||
* @extends {PMUI.core.Base}
|
||
* @abstract
|
||
*
|
||
* @cfg {PMUI.core.Container} targetObject The object the behavior will be applied to.
|
||
* @cfg {String} [scope="pmui-containeritem-behavior"] A string that identifies group sets of items that can
|
||
* interact with this target object's behavior.
|
||
* @cfg {String} [handle=null] If specified, restricts dragging from starting unless the mousedown occurs on the
|
||
* specified element(s). Only elements that descend from the draggable element are permitted.
|
||
*/
|
||
var ContainerItemBehavior = function (settings) {
|
||
ContainerItemBehavior.superclass.call(this, settings);
|
||
/**
|
||
* The object the behavior will be applied to.
|
||
* @type {PMUI.core.Container}
|
||
*/
|
||
this.targetObject = null;
|
||
/**
|
||
* The string that identifies group sets of items that can interact with this target object's behavior.
|
||
* @type {String}
|
||
*/
|
||
this.scope = null;
|
||
/**
|
||
* If the behavior has been attached to its
|
||
* {@link PMUI.behavior.ContainerItemContainer#property-targetObject targetObject}.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.behaviorAttached = null;
|
||
/**
|
||
* The JQuery Object the JQuery UI behavior is currently applied to.
|
||
* @type {Object}
|
||
* @private
|
||
*/
|
||
this.targetHTML = null;
|
||
/**
|
||
* The selector for the sortable items in case a related behavior is applied.
|
||
* @type {String}
|
||
* @private
|
||
*/
|
||
this.sortableItems = null;
|
||
/**
|
||
* If the behavior is disabled or not.
|
||
* @type {Boolean}
|
||
* @readonly
|
||
*/
|
||
this.disabled = null;
|
||
/**
|
||
* The current object that currently is being dragged.
|
||
* @type {PMUI.core.Element}
|
||
* @readonly
|
||
*/
|
||
this.draggedObject = null;
|
||
/**
|
||
* The class for the placeholder used in some behaviors.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.placeholderClass = null;
|
||
/**
|
||
* The class to be applied to the element when it is droppable and has a draggable element being dragged over it.
|
||
* @type {String}
|
||
* @readonly
|
||
*/
|
||
this.hoverClass = null;
|
||
|
||
this.sortItem = null;
|
||
|
||
this.sortIObject = null;
|
||
|
||
/**
|
||
* Restricts dragging/sorting from starting unless the mousedown occurs on the specified element(s).
|
||
* Only elements that descend from the draggable element are permitted.
|
||
* @type {String}
|
||
*/
|
||
this.handle = null;
|
||
|
||
ContainerItemBehavior.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Base', ContainerItemBehavior);
|
||
|
||
ContainerItemBehavior.prototype.init = function (settings) {
|
||
var defaults = {
|
||
scope: 'pmui-containeritem-behavior',
|
||
disabled: false,
|
||
placeholderClass: 'pmui-containeritembehavior-placeholder',
|
||
hoverClass: 'pmui-containeritembehavior-hover',
|
||
handle: null
|
||
};
|
||
|
||
$.extend(true, defaults, settings);
|
||
|
||
this.scope = defaults.scope;
|
||
this.placeholderClass = defaults.placeholderClass;
|
||
this.hoverClass = defaults.hoverClass;
|
||
this.setTargetObject(defaults.targetObject);
|
||
this.handle = defaults.handle;
|
||
|
||
if (defaults.disabled) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
};
|
||
/**
|
||
* Updates the behavior status (enabled/disabled).
|
||
* @chainable
|
||
* @abstract
|
||
* @private
|
||
*/
|
||
ContainerItemBehavior.prototype.updateBehaviorAvailability = function () {
|
||
};
|
||
/**
|
||
* Enables the behavior.
|
||
* @chainable
|
||
*/
|
||
ContainerItemBehavior.prototype.enable = function () {
|
||
this.disabled = false;
|
||
if (this.targetHTML) {
|
||
this.updateBehaviorAvailability();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables the behavior.
|
||
* @chainable
|
||
*/
|
||
ContainerItemBehavior.prototype.disable = function () {
|
||
this.disabled = true;
|
||
if (this.targetHTML) {
|
||
this.updateBehaviorAvailability();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the object the behavior will be applied to.
|
||
* @param {PMUI.core.Container} targetObject
|
||
* @private
|
||
*/
|
||
ContainerItemBehavior.prototype.setTargetObject = function (targetObject) {
|
||
if (targetObject instanceof PMUI.core.Container) {
|
||
this.targetObject = targetObject;
|
||
this.sortableItems = this.targetObject.sortableItems;
|
||
} else {
|
||
throw new Error("setTargetObject(): the parameter must be an instance of PMUI.core.Container.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the target object the behavior will be applied to.
|
||
* @return {PMUI.core.Container}
|
||
*/
|
||
ContainerItemBehavior.prototype.getTargetObject = function () {
|
||
return this.targetObject;
|
||
};
|
||
/**
|
||
* Returns true if the behavior has been attached to its
|
||
* {@link PMUI.behavior.ContainerItemContainer#property-targetObject targetObject}.
|
||
* @return {Boolean}
|
||
*/
|
||
ContainerItemBehavior.prototype.isBehaviorAttached = function () {
|
||
return this.behaviorAttached;
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when the
|
||
* {@link #property-targetObject targetObject}'s item dragging starts.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemBehavior.prototype.onStart = function () {
|
||
var that = this;
|
||
return function (e, ui) {
|
||
var targetObject = that.targetObject;
|
||
ui.helper.get(0).style.width = $(e.target).width() + "px";
|
||
$(this).hide();
|
||
that.draggedObject = PMUI.getPMUIObject(this);
|
||
if (typeof targetObject.onDragStart === 'function') {
|
||
targetObject.onDragStart(targetObject, that.draggedObject);
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Defines the handler to be executed while a {@link #property-targetObject targetObject}'s item is being dragged.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemBehavior.prototype.onDrag = function () {
|
||
var that = this;
|
||
return function (e, ui) {
|
||
};
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when the
|
||
* {@link #property-targetObject targetObject}'s item dragging stops.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemBehavior.prototype.onStop = function () {
|
||
var that = this;
|
||
return function (e, ui) {
|
||
var targetObject = that.targetObject;
|
||
that.draggedObject = PMUI.getPMUIObject(this);
|
||
if (typeof targetObject.onStopDrag === 'function') {
|
||
targetObject.onStopDrag(targetObject, that.draggedObject);
|
||
}
|
||
targetObject = $(this);
|
||
if (targetObject.parent().length) {
|
||
targetObject.show();
|
||
} else {
|
||
targetObject.remove();
|
||
}
|
||
that.draggedObject = null;
|
||
};
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when an accepted draggable is dropped on the
|
||
* {@link #property-targetObject targetObject}.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemBehavior.prototype.onDrop = function () {
|
||
var that = this;
|
||
return function (e, ui) {
|
||
var item = PMUI.getPMUIObject(ui.draggable.get(0)),
|
||
data,
|
||
placeholder = ui.draggable.data().sortableItem && ui.draggable.data().sortableItem.placeholder[0],
|
||
targetObject = that.targetObject, performDrop;
|
||
|
||
jQuery(ui.helper).remove();
|
||
|
||
if (!item || targetObject.isDirectParentOf(item)) {
|
||
return;
|
||
}
|
||
|
||
if (typeof targetObject.onBeforeDrop === 'function') {
|
||
targetObject.onBeforeDrop(targetObject, item, targetObject.items.getSize());
|
||
}
|
||
|
||
if (typeof targetObject.onDrop === 'function') {
|
||
performDrop = targetObject.onDrop(targetObject, item, targetObject.items.getSize() - 1);
|
||
}
|
||
if (performDrop || performDrop === undefined) {
|
||
item.getParent().behaviorObject.onDropOut(item, targetObject);
|
||
}
|
||
//The next lines avoid error when the dropped element is a sortable element
|
||
if (placeholder) {
|
||
placeholder.style.display = 'none';
|
||
targetObject.getContainmentArea().appendChild(placeholder);
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* The function to be perform when a draggable item is drop out from the container. Only applicable the behavior id
|
||
* of the drag type.
|
||
* @param {PMUI.core.Element} item The draggable item involved in the action.
|
||
* @param {PMUI.core.Container} destiny The container the draggable item was dropped on.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
ContainerItemBehavior.prototype.onDropOut = function (item, destiny, index) {
|
||
var targetObject = this.targetObject;
|
||
targetObject.removeItem(item);
|
||
if (destiny.canContain(item)) {
|
||
destiny.addItem(item, index);
|
||
item.setVisible(true);
|
||
} else {
|
||
data = item.getData();
|
||
destiny.addDataItem(data, index);
|
||
}
|
||
if (typeof targetObject.onDropOut === 'function') {
|
||
targetObject.onDropOut(item, targetObject, destiny);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Attaches event handlers for the mouse events triggered by the draggable/sortableItems.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
ContainerItemBehavior.prototype.attachOnDraggableMouseEvents = function () {
|
||
var that = this;
|
||
this.detachOnDraggableMouseEvents();
|
||
this.targetHTML.on('mouseover.pmui-containeritemdrag', function () {
|
||
var pmuiObject = PMUI.getPMUIObject(this);
|
||
that.targetObject.onDraggableMouseOver(pmuiObject);
|
||
return true;
|
||
}).on('mouseout.pmui-containeritemdrag', function () {
|
||
var pmuiObject = PMUI.getPMUIObject(this);
|
||
that.targetObject.onDraggableMouseOut(pmuiObject);
|
||
return true;
|
||
});
|
||
return this;
|
||
};
|
||
/**
|
||
* Attaches event handlers for the mouse events triggered by the draggable/sortableItems.
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
ContainerItemBehavior.prototype.detachOnDraggableMouseEvents = function () {
|
||
this.targetHTML.off('mouseover.pmui-containeritemdrag')
|
||
.off('mouseout.pmui-containeritemdrag');
|
||
return this;
|
||
};
|
||
/**
|
||
* Attaches the behavior to its
|
||
* {@link PMUI.behavior.ContainerItemContainer#property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemBehavior.prototype.attachBehavior = function () {
|
||
this.behaviorAttached = true;
|
||
this.updateBehaviorAvailability();
|
||
return this;
|
||
};
|
||
/**
|
||
* Detaches the behavior from its
|
||
* {@link PMUI.behavior.ContainerItemContainer#property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemBehavior.prototype.detachBehavior = function () {
|
||
this.behaviorAttached = false;
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerItemBehavior', ContainerItemBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ContainerItemBehavior;
|
||
}
|
||
}());
|
||
(function() {
|
||
/**
|
||
* @class PMUI.behavior.ContainerItemNoBehavior
|
||
* @extends PMUI.behavior.ContainerItemBehavior
|
||
*/
|
||
var ContainerItemNoBehavior = function(settings) {
|
||
ContainerItemNoBehavior.superclass.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ContainerItemBehavior', ContainerItemNoBehavior);
|
||
/** [attachBehavior description] */
|
||
ContainerItemNoBehavior.prototype.attachBehavior = function() {
|
||
var $html,
|
||
i,
|
||
items,
|
||
item,
|
||
targetObject = this.targetObject;
|
||
if(!this.behaviorAttached) {
|
||
items = targetObject.getItems();
|
||
for(i = 0; i < items.length; i += 1) {
|
||
item = items[i].getHTML();
|
||
if(!$html) {
|
||
$html = jQuery(item);
|
||
} else {
|
||
$html = $html.add(item);
|
||
}
|
||
}
|
||
|
||
try {
|
||
$html.draggable('destroy');
|
||
} catch(e) {}
|
||
|
||
try {
|
||
$(targetObject.getContainmentArea()).droppable('destroy');
|
||
} catch(e) {}
|
||
|
||
try {
|
||
$(targetObject.getContainmentArea()).sortable('destroy');
|
||
} catch(e) {}
|
||
}
|
||
return ContainerItemNoBehavior.superclass.prototype.attachBehavior.call(this);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerItemNoBehavior', ContainerItemNoBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ContainerItemNoBehavior;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.behavior.ContainerItemDragBehavior
|
||
* @extends PMUI.behavior.ContainerItemBehavior
|
||
* Class that encapsulates the drag behavior for the items of a {@link PMUI.core.Container Container}. The object
|
||
* that applies this behavior will be able to be dragged to another Containers that are applying dropping behaviors
|
||
* ({@link PMUI.behavior.ContainerItemDropBehavior drop},
|
||
* {@link PMUI.behavior.ContainerItemDragDropBehavior dragdrop},
|
||
* {@link PMUI.behavior.ContainerItemDropSortBehavior dropsort},
|
||
* {@link PMUI.behavior.ContainerItemDragDropSortBehavior dragdropsort}).
|
||
*
|
||
* Since this class is created through the
|
||
* {@link PMUI.behavior.ContainerItemBehaviorFactory ContainerItemBehaviorFactory} it shouldn't be instantiated in
|
||
* most cases (it is instantiated internally by the object of the Container class).
|
||
* If you want to apply this behavior to a {@link PMUI.core.Container Container} object, just call its
|
||
* {@link PMUI.core.Container#method-setBehavior setBehavior()} method with the string parameter "drag" or set it
|
||
* at instantiation time using its {@link PMUI.core.Container#cfg-behavior behavior} config option.
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var tree = new PMUI.panel.TreePanel({
|
||
* items: [
|
||
* {
|
||
* label: "draggable item #1"
|
||
* }, {
|
||
* label: "draggable item #2"
|
||
* }, {
|
||
* label: "draggable item #3"
|
||
* }, {
|
||
* label: "draggable item #4"
|
||
* }, {
|
||
* label: "draggable item #5"
|
||
* }, {
|
||
* label: "draggable item #6"
|
||
* }
|
||
* ]
|
||
* }), tree2 = new PMUI.panel.TreePanel({
|
||
* style: {
|
||
* cssClasses: ["droppable-list"]
|
||
* },
|
||
* items: [
|
||
* {
|
||
* label: 'Drop Here!'
|
||
* }
|
||
* ]
|
||
* });
|
||
*
|
||
* tree.setBehavior("drag");
|
||
* tree2.setBehavior("drop");
|
||
* document.body.appendChild(tree.getHTML());
|
||
* //Add a separator
|
||
* document.body.appendChild(document.createElement('hr'));
|
||
* document.body.appendChild(tree2.getHTML());
|
||
*/
|
||
var ContainerItemDragBehavior = function (settings) {
|
||
ContainerItemDragBehavior.superclass.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ContainerItemBehavior', ContainerItemDragBehavior);
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDragBehavior.prototype.updateBehaviorAvailability = function () {
|
||
this.targetHTML.draggable(this.disabled ? 'disable' : 'enable');
|
||
if (this.disabled) {
|
||
this.detachOnDraggableMouseEvents();
|
||
} else {
|
||
this.attachOnDraggableMouseEvents();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the items from the {@link PMUI.behavior.ContainerItemDragBehavior#property-targetObject targetObject}
|
||
* related to the behavior.
|
||
* @return {Object} A jQuery object.
|
||
* @private
|
||
*/
|
||
ContainerItemDragBehavior.prototype.getTargetObjectItems = function () {
|
||
var $html = $(null),
|
||
i,
|
||
item,
|
||
items,
|
||
targetObject = this.targetObject;
|
||
items = targetObject.getBehavioralItems();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
item = items[i].getHTML();
|
||
$html = $html.add(item);
|
||
}
|
||
return $html;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDragBehavior.prototype.onDropOut = function (item, targetObject, index) {
|
||
var aux;
|
||
ContainerItemDragBehavior.superclass.prototype.onDropOut.apply(this, arguments);
|
||
//The next lines avoid an uncontrolable error generated on the jquery ui's stop callback
|
||
//when it try to access certain data that will be undefined because of the destruction of the
|
||
//drag behavior when it is added to the new container in which it was dropped on.
|
||
//What it does is add some data in the jquery data of the object's html.
|
||
this.draggedObject = item;
|
||
aux = jQuery(this.draggedObject.html).data('ui-draggable');
|
||
if (!aux) {
|
||
aux = {};
|
||
jQuery(this.draggedObject.html).data('ui-draggable', aux);
|
||
}
|
||
if (!aux.sortables) {
|
||
aux.sortables = [];
|
||
}
|
||
if (!aux.options) {
|
||
aux.options = {};
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Attaches the behavior to the {@link PMUI.behavior.ContainerItemDragBehavior#property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemDragBehavior.prototype.attachBehavior = function (index) {
|
||
var $html,
|
||
i,
|
||
items,
|
||
item,
|
||
targetObject = this.targetObject,
|
||
behaviorAttached;
|
||
if (index !== undefined) {
|
||
$html = $(this.targetObject.items.get(index).getHTML());
|
||
behaviorAttached = this.targetObject.items.get(index).behaviorObject.behaviorAttached;
|
||
} else {
|
||
$html = this.getTargetObjectItems();
|
||
behaviorAttached = this.behaviorAttached;
|
||
}
|
||
if (!behaviorAttached) {
|
||
if (index !== undefined) {
|
||
$html = $(this.targetObject.items.get(index).getHTML());
|
||
} else {
|
||
$html = this.getTargetObjectItems();
|
||
}
|
||
this.targetHTML = $html;
|
||
$html.draggable({
|
||
appendTo: document.body,
|
||
connectToSortable: '.pmui-containeritembehavior-sort',
|
||
helper: 'clone',
|
||
revert: "invalid",
|
||
scope: this.scope,
|
||
drag: this.onDrag(),
|
||
start: this.onStart(),
|
||
stop: this.onStop(),
|
||
items: this.draggableItems,
|
||
handle: this.handle || false,
|
||
zIndex: 1000
|
||
});
|
||
this.attachOnDraggableMouseEvents();
|
||
if (index !== undefined) {
|
||
this.targetObject.items.get(index).behaviorObject.behaviorAttached = true;
|
||
this.targetObject.items.get(index).behaviorObject.updateBehaviorAvailability();
|
||
} else {
|
||
ContainerItemDragBehavior.superclass.prototype.attachBehavior.call(this);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Detaches the behavior from the
|
||
* {@link PMUI.behavior.ContainerItemDragBehavior#property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemDragBehavior.prototype.detachBehavior = function () {
|
||
if (this.behaviorAttached) {
|
||
try {
|
||
this.targetHTML.draggable('destroy');
|
||
this.detachOnDraggableMouseEvents();
|
||
} catch (e) {
|
||
}
|
||
}
|
||
return ContainerItemDragBehavior.superclass.prototype.detachBehavior.call(this);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerItemDragBehavior', ContainerItemDragBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ContainerItemDragBehavior;
|
||
}
|
||
}());
|
||
(function() {
|
||
/**
|
||
* @class PMUI.behavior.ContainerItemDragCloneBehavior
|
||
* @extends PMUI.behavior.ContainerItemDragBehavior
|
||
* Class that encapsulates the drag behavior for the items of a {@link PMUI.core.Container Container}. The object
|
||
* that applies this behavior will be able to create a clone item to be dragged to another Containers that are
|
||
* applying dropping behaviors
|
||
* ({@link PMUI.behavior.ContainerItemDropBehavior drop},
|
||
* {@link PMUI.behavior.ContainerItemDragDropBehavior dragdrop},
|
||
* {@link PMUI.behavior.ContainerItemDropSortBehavior dropsort},
|
||
* {@link PMUI.behavior.ContainerItemDragDropSortBehavior dragdropsort}).
|
||
*
|
||
* Since this class is created through the
|
||
* {@link PMUI.behavior.ContainerItemBehaviorFactory ContainerItemBehaviorFactory} it shouldn't be instantiated in
|
||
* most cases (it is instantiated internally by the object of the Container class).
|
||
* If you want to apply this behavior to a {@link PMUI.core.Container Container} object, just call its
|
||
* {@link PMUI.core.Container#method-setBehavior setBehavior()} method with the string parameter "dragclone" or set it
|
||
* at instantiation time using its {@link PMUI.core.Container#cfg-behavior behavior} config option.
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var tree = new PMUI.panel.TreePanel({
|
||
* items: [
|
||
* {
|
||
* label: "draggable item #1"
|
||
* }, {
|
||
* label: "draggable item #2"
|
||
* }, {
|
||
* label: "draggable item #3"
|
||
* }, {
|
||
* label: "draggable item #4"
|
||
* }, {
|
||
* label: "draggable item #5"
|
||
* }, {
|
||
* label: "draggable item #6"
|
||
* }
|
||
* ]
|
||
* }), tree2 = new PMUI.panel.TreePanel({
|
||
* style: {
|
||
* cssClasses: ["droppable-list"]
|
||
* },
|
||
* items: [
|
||
* {
|
||
* label: 'Drop Here!'
|
||
* }
|
||
* ]
|
||
* });
|
||
*
|
||
* tree.setBehavior("dragclone");
|
||
* tree2.setBehavior("drop");
|
||
* document.body.appendChild(tree.getHTML());
|
||
* //Add a separator
|
||
* document.body.appendChild(document.createElement('hr'));
|
||
* document.body.appendChild(tree2.getHTML());
|
||
*/
|
||
var ContainerItemDragCloneBehavior = function(settings) {
|
||
ContainerItemDragCloneBehavior.superclass.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ContainerItemDragBehavior', ContainerItemDragCloneBehavior);
|
||
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDragCloneBehavior.prototype.onStart = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
var targetObject = that.targetObject;
|
||
ui.helper.get(0).style.width = $(e.target).width() + "px";
|
||
that.draggedObject = PMUI.getPMUIObject(this);
|
||
if(typeof targetObject.onDragStart === 'function') {
|
||
targetObject.onDragStart(targetObject, that.draggedObject);
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* @inheritodc
|
||
*/
|
||
ContainerItemDragCloneBehavior.prototype.onDropOut = function(item, destiny, index) {
|
||
var targetObject = this.targetObject;
|
||
data = item.getData();
|
||
destiny.addDataItem(data, index);
|
||
if(typeof targetObject.onDropOut === 'function') {
|
||
targetObject.onDropOut(item, targetObject, destiny);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerItemDragCloneBehavior', ContainerItemDragCloneBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ContainerItemDragCloneBehavior;
|
||
}
|
||
}());
|
||
(function() {
|
||
/**
|
||
* @class PMUI.behavior.ContainerItemDropBehavior
|
||
* @extends PMUI.behavior.ContainerItemBehavior
|
||
* Class that encapsulates the drop behavior for {@link PMUI.core.Container Container} objects. The object that
|
||
* applies this behavior will be able to accept draggable items from other Containers which ones are applying
|
||
* dragging behaviors ({@link PMUI.behavior.ContainerItemDragBehavior drag},
|
||
* {@link PMUI.behavior.ContainerItemDragDropBehavior dragdrop},
|
||
* {@link PMUI.behavior.ContainerItemDragSortBehavior dragsort},
|
||
* {@link PMUI.behavior.ContainerItemDragDropSortBehavior dragdropsort}). .
|
||
*
|
||
* Since this class is created through the
|
||
* {@link PMUI.behavior.ContainerItemBehaviorFactory ContainerItemBehaviorFactory} it shouldn't be instantiated in
|
||
* most cases (it is instantiated internally by the object of the Container class).
|
||
* If you want to apply this behavior to a {@link PMUI.core.Container Container} object, just call its
|
||
* {@link PMUI.core.Container#method-setBehavior setBehavior()} method with the string parameter "drop" or set it
|
||
* at instantiation time using its {@link PMUI.core.Container#cfg-behavior behavior} config option.
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var tree = new PMUI.panel.TreePanel({
|
||
* items: [
|
||
* {
|
||
* label: "draggable item #1"
|
||
* }, {
|
||
* label: "draggable item #2"
|
||
* }, {
|
||
* label: "draggable item #3"
|
||
* }, {
|
||
* label: "draggable item #4"
|
||
* }, {
|
||
* label: "draggable item #5"
|
||
* }, {
|
||
* label: "draggable item #6"
|
||
* }
|
||
* ]
|
||
* }), tree2 = new PMUI.panel.TreePanel({
|
||
* style: {
|
||
* cssClasses: ["droppable-list"]
|
||
* },
|
||
* items: [
|
||
* {
|
||
* label: 'Drop Here!'
|
||
* }
|
||
* ]
|
||
* });
|
||
*
|
||
* tree.setBehavior("drag");
|
||
* tree2.setBehavior("drop");
|
||
* document.body.appendChild(tree.getHTML());
|
||
* //Add a separator
|
||
* document.body.appendChild(document.createElement('hr'));
|
||
* document.body.appendChild(tree2.getHTML());
|
||
*/
|
||
var ContainerItemDropBehavior = function(settings) {
|
||
ContainerItemDropBehavior.superclass.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ContainerItemBehavior', ContainerItemDropBehavior);
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDropBehavior.prototype.updateBehaviorAvailability = function() {
|
||
this.targetHTML.droppable(this.disabled ? 'disable' : 'enable');
|
||
return this;
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when an accepted draggable is dragged over the
|
||
* {@link #property-targetObject targetObject}.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemDropBehavior.prototype.onOver = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
(that.targetObject.onDragOver()());
|
||
};
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when an accepted draggable is dragged out of the
|
||
* {@link PMUI.behavior.ContainerItemDragBehavior#property-targetObject targetObject}.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemDropBehavior.prototype.onOut = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
|
||
};
|
||
};
|
||
/**
|
||
* Attaches the behavior to the {@link #property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemDropBehavior.prototype.attachBehavior = function() {
|
||
var $html,
|
||
i,
|
||
items,
|
||
item,
|
||
targetObject = this.targetObject;
|
||
if(!this.behaviorAttached) {
|
||
this.targetHTML = $(this.targetObject.getContainmentArea());
|
||
this.targetHTML.droppable({
|
||
scope: this.scope,
|
||
drop: this.onDrop(),
|
||
out: this.onOut(),
|
||
over: this.onOver(),
|
||
hoverClass: this.hoverClass,
|
||
tolerance: 'pointer'
|
||
});
|
||
}
|
||
return ContainerItemDropBehavior.superclass.prototype.attachBehavior.call(this);
|
||
};
|
||
/**
|
||
* Detaches the behavior from the
|
||
* {@link #property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemDropBehavior.prototype.detachBehavior = function() {
|
||
if(this.behaviorAttached) {
|
||
try {
|
||
this.targetHTML.droppable('destroy');
|
||
} catch(e) {}
|
||
}
|
||
return ContainerItemDropBehavior.superclass.prototype.detachBehavior.call(this);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerItemDropBehavior', ContainerItemDropBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ContainerItemDropBehavior;
|
||
}
|
||
}());
|
||
(function() {
|
||
/**
|
||
* @class PMUI.behavior.ContainerItemSortBehavior
|
||
* @extends PMUI.behavior.ContainerItemDragBehavior
|
||
* Class that encapsulates the sort behavior for {@link PMUI.core.Container Container} objects. This behavior
|
||
* enables the {@link #property-targetObject targetObject}'s' items to be sortable.
|
||
*
|
||
* Since this class is created through the
|
||
* {@link PMUI.behavior.ContainerItemBehaviorFactory ContainerItemBehaviorFactory} it shouldn't be instantiated in
|
||
* most cases (it is instantiated internally by the object of the Container class).
|
||
* If you want to apply this behavior to a {@link PMUI.core.Container Container} object, just call its
|
||
* {@link PMUI.core.Container#method-setBehavior setBehavior()} method with the string parameter "sort" or set it
|
||
* at instantiation time using its {@link PMUI.core.Container#cfg-behavior behavior} config option.
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var tree = new PMUI.panel.TreePanel({
|
||
* items: [
|
||
* {
|
||
* label: "sortable item #1"
|
||
* }, {
|
||
* label: "sortable item #2"
|
||
* }, {
|
||
* label: "sortable item #3"
|
||
* }, {
|
||
* label: "sortable item #4"
|
||
* }, {
|
||
* label: "sortable item #5"
|
||
* }, {
|
||
* label: "sortable item #6"
|
||
* }
|
||
* ]
|
||
* });
|
||
*
|
||
* tree.setBehavior("sort");
|
||
* document.body.appendChild(tree.getHTML());
|
||
*/
|
||
var ContainerItemSortBehavior = function(settings) {
|
||
ContainerItemSortBehavior.superclass.call(this, settings);
|
||
this.alignment = null;
|
||
ContainerItemSortBehavior.prototype.init.call(this,settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ContainerItemDragBehavior', ContainerItemSortBehavior);/**
|
||
* @inheritdoc
|
||
*/
|
||
|
||
ContainerItemSortBehavior.prototype.init = function (settings) {
|
||
var defaults = {
|
||
alignment : 'vertical'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
this.setAlignment(defaults.alignment);
|
||
};
|
||
|
||
ContainerItemSortBehavior.prototype.setAlignment = function (alignment) {
|
||
if (!(typeof alignment === "string" && (alignment === "vertical" || alignment === "horizontal"))){
|
||
throw new Error ("ContainerItemSortBehavior.setAlignment(): the parameter is no valid, must be a vertical or horizontal value");
|
||
}
|
||
this.alignment = alignment;
|
||
return this;
|
||
};
|
||
|
||
ContainerItemSortBehavior.prototype.updateBehaviorAvailability = function() {
|
||
this.targetHTML.sortable(this.disabled ? 'disable' : 'enable');
|
||
return this;
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when the
|
||
* {@link #property-targetObject targetObject}'s item sorting starts.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemSortBehavior.prototype.onStart = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
var targetObject,
|
||
o;
|
||
that.cancelledDrop = null;
|
||
o = PMUI.getPMUIObject(ui.item.get(0));
|
||
|
||
if(that.targetObject.isDirectParentOf(o)) {
|
||
targetObject = that.targetObject;
|
||
|
||
if ( that.alignment == "vertical" ) {
|
||
ui.helper.get(0).style.width = $(e.target).width() + "px";
|
||
}
|
||
that.sortIObject = o;
|
||
if(typeof targetObject.onSortStart === 'function') {
|
||
targetObject.onSortStart(targetObject, that.sortIObject);
|
||
}
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when the
|
||
* {@link #property-targetObject targetObject}'s item sorting stops.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemSortBehavior.prototype.onStop = function() {
|
||
var that = this;
|
||
return function() {};
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when the user stopped sorting and the
|
||
* {@link #property-targetObject targetObject}'s items positions have
|
||
* changed.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemSortBehavior.prototype.onUpdate = function() {
|
||
return this.targetObject.onSortingChange();
|
||
};
|
||
/**
|
||
* Attaches the behavior to the {@link #property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemSortBehavior.prototype.attachBehavior = function() {
|
||
var $html,
|
||
i,
|
||
items,
|
||
item,
|
||
targetObject = this.targetObject;
|
||
if(!this.behaviorAttached) {
|
||
this.targetHTML = jQuery(this.targetObject.getContainmentArea());
|
||
this.targetHTML.sortable({
|
||
containment: 'parent',
|
||
sort: this.onDrag(),
|
||
start: this.onStart(),
|
||
stop: this.onStop(),
|
||
update: this.onUpdate(),
|
||
handle: this.handle || false
|
||
});
|
||
}
|
||
return ContainerItemSortBehavior.superclass.superclass.prototype.attachBehavior.call(this);
|
||
};
|
||
/**
|
||
* Detaches the behavior from the
|
||
* {@link #property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemSortBehavior.prototype.detachBehavior = function() {
|
||
if(this.behaviorAttached) {
|
||
try {
|
||
targetHTML.sortable('destroy');
|
||
} catch(e) {}
|
||
}
|
||
return ContainerItemSortBehavior.superclass.superclass.prototype.detachBehavior.call(this);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerItemSortBehavior', ContainerItemSortBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ContainerItemSortBehavior;
|
||
}
|
||
}());
|
||
(function() {
|
||
/**
|
||
* @class PMUI.behavior.ContainerItemDragDropBehavior
|
||
* @extends PMUI.behavior.ContainerItemBehavior
|
||
* Class that encapsulates the drop behavior for a {@link PMUI.core.Container Container} object and the drag
|
||
* behavior for its items. The object that applies this behavior, will be able to:
|
||
*
|
||
* - Accept draggable items from other Containers which ones are applying dragging behaviors
|
||
* ({@link PMUI.behavior.ContainerItemDragBehavior drag},
|
||
* {@link PMUI.behavior.ContainerItemDragDropBehavior dragdrop},
|
||
* {@link PMUI.behavior.ContainerItemDragSortBehavior dragsort},
|
||
* {@link PMUI.behavior.ContainerItemDragDropSortBehavior dragdropsort}).
|
||
* - The object's items will be able to be dragged to another Containers that are applying dropping behaviors
|
||
* ({@link PMUI.behavior.ContainerItemDropBehavior drop},
|
||
* {@link PMUI.behavior.ContainerItemDragDropBehavior dragdrop},
|
||
* {@link PMUI.behavior.ContainerItemDropSortBehavior dropsort},
|
||
* {@link PMUI.behavior.ContainerItemDragDropSortBehavior dragdropsort}).
|
||
*
|
||
* Since this class is created through the
|
||
* {@link PMUI.behavior.ContainerItemBehaviorFactory ContainerItemBehaviorFactory} it shouldn't be instantiated in
|
||
* most cases (it is instantiated internally by the object of the Container class).
|
||
* If you want to apply this behavior to a {@link PMUI.core.Container Container} object, just call its
|
||
* {@link PMUI.core.Container#method-setBehavior setBehavior()} method with the string parameter "dragdrop" or set it
|
||
* at instantiation time using its {@link PMUI.core.Container#cfg-behavior behavior} config option.
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var tree = new PMUI.panel.TreePanel({
|
||
* items: [
|
||
* {
|
||
* label: "draggable item #1"
|
||
* }, {
|
||
* label: "draggable item #2"
|
||
* }, {
|
||
* label: "draggable item #3"
|
||
* }, {
|
||
* label: "draggable item #4"
|
||
* }, {
|
||
* label: "draggable item #5"
|
||
* }, {
|
||
* label: "draggable item #6"
|
||
* }
|
||
* ]
|
||
* }), tree2 = new PMUI.panel.TreePanel({
|
||
* style: {
|
||
* cssClasses: ["droppable-list"]
|
||
* },
|
||
* items: [
|
||
* {
|
||
* label: "draggable item #7"
|
||
* }, {
|
||
* label: "draggable item #8"
|
||
* }, {
|
||
* label: "draggable item #9"
|
||
* }, {
|
||
* label: "draggable item #10"
|
||
* }, {
|
||
* label: "draggable item #11"
|
||
* }, {
|
||
* label: "draggable item #12"
|
||
* }
|
||
* ]
|
||
* });
|
||
*
|
||
* tree.setBehavior("dragdrop");
|
||
* tree2.setBehavior("dragdrop");
|
||
* document.body.appendChild(tree.getHTML());
|
||
* //Add a separator
|
||
* document.body.appendChild(document.createElement('hr'));
|
||
* document.body.appendChild(tree2.getHTML());
|
||
*/
|
||
var ContainerItemDragDropBehavior = function(settings) {
|
||
ContainerItemDragDropBehavior.superclass.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ContainerItemBehavior', ContainerItemDragDropBehavior);
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDragDropBehavior.prototype.updateBehaviorAvailability = function() {
|
||
var d = this.disabled ? 'disable' : 'enable';
|
||
this.targetHTML.droppable(d);
|
||
jQuery(this.getTargetObjectItems()).draggable(d);
|
||
if(this.disabled) {
|
||
this.detachOnDraggableMouseEvents();
|
||
} else {
|
||
this.attachOnDraggableMouseEvents();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the html from the items of the {@link #property-targetObject targetObject}
|
||
* @return {Object} A jQuery object with all the target object' items html.
|
||
*/
|
||
ContainerItemDragDropBehavior.prototype.getTargetObjectItems = function() {
|
||
var $html = $(null),
|
||
i,
|
||
item,
|
||
items,
|
||
targetObject = this.targetObject;
|
||
items = targetObject.getBehavioralItems();
|
||
for(i = 0; i < items.length; i += 1) {
|
||
item = items[i].getHTML();
|
||
$html = $html.add(item);
|
||
}
|
||
return $html;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDragDropBehavior.prototype.onDropOut = function() {
|
||
var aux;
|
||
ContainerItemDragDropBehavior.superclass.prototype.onDropOut.apply(this, arguments);
|
||
//The next lines avoid an uncontrolable error generated on the jquery ui's stop callback
|
||
//when it try to access certain data that will be undefined because of the destruction of the
|
||
//drag behavior when it is added to the new container in which it was dropped on.
|
||
//What it does is add some data in the jquery data of the object's html.
|
||
aux = jQuery(this.draggedObject.html).data('ui-draggable');
|
||
if(!aux) {
|
||
aux = {};
|
||
jQuery(this.draggedObject.html).data('ui-draggable', aux);
|
||
}
|
||
if(!aux.sortables) {
|
||
aux.sortables = [];
|
||
}
|
||
if(!aux.options) {
|
||
aux.options = {};
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when an accepted draggable is dragged over the
|
||
* {@link #property-targetObject targetObject}.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemDragDropBehavior.prototype.onOver = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
(that.targetObject.onDragOver()());
|
||
};
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when an accepted draggable is dragged out of the
|
||
* {@link #property-targetObject targetObject}.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemDragDropBehavior.prototype.onOut = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
|
||
};
|
||
};
|
||
/**
|
||
* Attaches the behavior to the {@link #property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemDragDropBehavior.prototype.attachBehavior = function() {
|
||
var $html,
|
||
i,
|
||
items,
|
||
item,
|
||
targetObject = this.targetObject;
|
||
if(!this.behaviorAttached) {
|
||
$html = this.getTargetObjectItems();
|
||
|
||
$html.draggable({
|
||
appendTo: document.body,
|
||
connectToSortable: '.pmui-containeritembehavior-sort',
|
||
helper: 'clone',
|
||
revert: "invalid",
|
||
drag: this.onDrag(),
|
||
start: this.onStart(),
|
||
stop: this.onStop(),
|
||
scope: this.scope,
|
||
handle: this.handle || false
|
||
});
|
||
this.targetHTML = jQuery(this.targetObject.getContainmentArea());
|
||
this.targetHTML.droppable({
|
||
drop: this.onDrop(),
|
||
out: this.onOut(),
|
||
over: this.onOver(),
|
||
tolerance: 'pointer',
|
||
scope: this.scope
|
||
});
|
||
this.attachOnDraggableMouseEvents();
|
||
}
|
||
return ContainerItemDragDropBehavior.superclass.prototype.attachBehavior.call(this);
|
||
};
|
||
/**
|
||
* Detaches the behavior from the
|
||
* {@link #property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemDragDropBehavior.prototype.detachBehavior = function() {
|
||
if(this.behaviorAttached) {
|
||
try {
|
||
this.getTargetObjectItems().draggable('destroy');
|
||
this.targetHTML.droppable('destroy');
|
||
this.detachOnDraggableMouseEvents();
|
||
} catch(e) {}
|
||
}
|
||
return ContainerItemDragDropBehavior.superclass.prototype.detachBehavior.call(this);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerItemDragDropBehavior', ContainerItemDragDropBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ContainerItemDragDropBehavior;
|
||
}
|
||
}());
|
||
(function() {
|
||
/**
|
||
* @class PMUI.behavior.ContainerItemDragSortBehavior
|
||
* @extends PMUI.behavior.ContainerItemDragBehavior
|
||
* Class that encapsulates the drag and sort behaviors for a {@link PMUI.core.Container Container} object items.
|
||
* The items of the object that applies this behavior, will be able to:
|
||
*
|
||
* - Be dragged to another Containers that are applying dropping behaviors
|
||
* ({@link PMUI.behavior.ContainerItemDropBehavior drop},
|
||
* {@link PMUI.behavior.ContainerItemDragDropBehavior dragdrop},
|
||
* {@link PMUI.behavior.ContainerItemDropSortBehavior dropsort},
|
||
* {@link PMUI.behavior.ContainerItemDragDropSortBehavior dragdropsort}).
|
||
* - Be sortable.
|
||
*
|
||
* Since this class is created through the
|
||
* {@link PMUI.behavior.ContainerItemBehaviorFactory ContainerItemBehaviorFactory} it shouldn't be instantiated in
|
||
* most cases (it is instantiated internally by the object of the Container class).
|
||
* If you want to apply this behavior to a {@link PMUI.core.Container Container} object, just call its
|
||
* {@link PMUI.core.Container#method-setBehavior setBehavior()} method with the string parameter "dragsort" or set it
|
||
* at instantiation time using its {@link PMUI.core.Container#cfg-behavior behavior} config option.
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var tree = new PMUI.panel.TreePanel({
|
||
* items: [
|
||
* {
|
||
* label: "draggable item #1"
|
||
* }, {
|
||
* label: "draggable item #2"
|
||
* }, {
|
||
* label: "draggable item #3"
|
||
* }, {
|
||
* label: "draggable item #4"
|
||
* }, {
|
||
* label: "draggable item #5"
|
||
* }, {
|
||
* label: "draggable item #6"
|
||
* }
|
||
* ]
|
||
* }), tree2 = new PMUI.panel.TreePanel({
|
||
* style: {
|
||
* cssClasses: ["droppable-list"]
|
||
* },
|
||
* items: [
|
||
* {
|
||
* label: 'Drop Here!'
|
||
* }
|
||
* ]
|
||
* });
|
||
*
|
||
* tree.setBehavior("dragsort");
|
||
* tree2.setBehavior("drop");
|
||
* document.body.appendChild(tree.getHTML());
|
||
* //Add a separator
|
||
* document.body.appendChild(document.createElement('hr'));
|
||
* document.body.appendChild(tree2.getHTML());
|
||
*/
|
||
var ContainerItemDragSortBehavior = function(settings) {
|
||
ContainerItemDragSortBehavior.superclass.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ContainerItemDragBehavior', ContainerItemDragSortBehavior);
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDragSortBehavior.prototype.updateBehaviorAvailability = function() {
|
||
this.targetHTML.sortable(this.disabled ? 'disable' : 'enable');
|
||
if(this.disabled) {
|
||
this.detachOnDraggableMouseEvents();
|
||
} else {
|
||
this.attachOnDraggableMouseEvents();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDragSortBehavior.prototype.onStart = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
var targetObject, o;
|
||
//Since the jQuery sortable's start callback is executed when the sorting starts and not neccesarily when
|
||
//one of its own items starts dragging we need to do the next validation:
|
||
//check if the item dragged belongs to the sortable html. In that case we fire the onDragStart callback.
|
||
o = PMUI.getPMUIObject(ui.item.get(0));
|
||
if(that.targetObject.isDirectParentOf(o)) {
|
||
targetObject = that.targetObject;
|
||
ui.helper.get(0).style.width = $(e.target).width() + "px";
|
||
ui.item.hide();
|
||
that.draggedObject = o;
|
||
if(typeof targetObject.onDragStart === 'function') {
|
||
targetObject.onDragStart(targetObject, that.draggedObject);
|
||
}
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when the user stopped sorting and the
|
||
* {@link #property-targetObject targetObject}'s items positions have
|
||
* changed.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemDragSortBehavior.prototype.onUpdate = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
var parentHTML = that.targetObject.getHTML(),
|
||
item = PMUI.getPMUIObject(ui.item.get(0));
|
||
|
||
if(item && jQuery(parentHTML).has(item.getHTML()).length) {
|
||
(that.targetObject.onSortingChange()(e, ui));
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Attaches the behavior to the {@link #property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemDragSortBehavior.prototype.attachBehavior = function() {
|
||
var $html,
|
||
i,
|
||
items,
|
||
item,
|
||
targetObject = this.targetObject;
|
||
if(!this.behaviorAttached) {
|
||
this.targetHTML = jQuery(targetObject.getContainmentArea());
|
||
this.targetHTML.sortable({
|
||
appendTo: document.body,
|
||
connectWith: '.pmui-containeritembehavior-sort',
|
||
helper: 'clone',
|
||
revert: "invalid",
|
||
start: this.onStart(),
|
||
update: this.onUpdate(),
|
||
items: this.sortableItems,
|
||
placeholder: this.placeholderClass,
|
||
handle: this.handle || false,
|
||
zIndex: 1000
|
||
});
|
||
this.attachOnDraggableMouseEvents();
|
||
}
|
||
return ContainerItemDragSortBehavior.superclass.superclass.prototype.attachBehavior.call(this);
|
||
};
|
||
/**
|
||
* Detaches the behavior from the
|
||
* {@link #property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemDragSortBehavior.prototype.detachBehavior = function() {
|
||
if(this.behaviorAttached) {
|
||
try {
|
||
this.targetHTML.sortable('destroy');
|
||
} catch(e) {}
|
||
}
|
||
return ContainerItemDragSortBehavior.superclass.prototype.detachBehavior.call(this);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerItemDragSortBehavior', ContainerItemDragSortBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ContainerItemDragSortBehavior;
|
||
}
|
||
}());
|
||
(function() {
|
||
/**
|
||
* @class PMUI.behavior.ContainerItemDropSortBehavior
|
||
* @extends PMUI.behavior.ContainerItemDropBehavior
|
||
* Class that encapsulates the drop behavior for a {@link PMUI.core.Container Container} object and the drag
|
||
* behavior for its items. The object that applies this behavior, will be able to:
|
||
*
|
||
* - Accept draggable items from other Containers which ones are applying dragging behaviors
|
||
* ({@link PMUI.behavior.ContainerItemDragBehavior drag},
|
||
* {@link PMUI.behavior.ContainerItemDragDropBehavior dragdrop},
|
||
* {@link PMUI.behavior.ContainerItemDragSortBehavior dragsort},
|
||
* {@link PMUI.behavior.ContainerItemDragDropSortBehavior dragdropsort}).
|
||
*
|
||
* - The object items will be sortable.
|
||
*
|
||
* Since this class is created through the
|
||
* {@link PMUI.behavior.ContainerItemBehaviorFactory ContainerItemBehaviorFactory} it shouldn't be instantiated in
|
||
* most cases (it is instantiated internally by the object of the Container class).
|
||
* If you want to apply this behavior to a {@link PMUI.core.Container Container} object, just call its
|
||
* {@link PMUI.core.Container#method-setBehavior setBehavior()} method with the string parameter "dropsort" or set it
|
||
* at instantiation time using its {@link PMUI.core.Container#cfg-behavior behavior} config option.
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var tree = new PMUI.panel.TreePanel({
|
||
* items: [
|
||
* {
|
||
* label: "sortable item #1"
|
||
* }, {
|
||
* label: "sortable item #2"
|
||
* }, {
|
||
* label: "sortable item #3"
|
||
* }, {
|
||
* label: "sortable item #4"
|
||
* }, {
|
||
* label: "sortable item #5"
|
||
* }, {
|
||
* label: "sortable item #6"
|
||
* }
|
||
* ]
|
||
* }), tree2 = new PMUI.panel.TreePanel({
|
||
* style: {
|
||
* cssClasses: ["droppable-list"]
|
||
* },
|
||
* items: [
|
||
* {
|
||
* label: "draggable item #1"
|
||
* }, {
|
||
* label: "draggable item #2"
|
||
* }, {
|
||
* label: "draggable item #3"
|
||
* }, {
|
||
* label: "draggable item #4"
|
||
* }, {
|
||
* label: "draggable item #5"
|
||
* }, {
|
||
* label: "draggable item #6"
|
||
* }
|
||
* ]
|
||
* });
|
||
*
|
||
* tree.setBehavior("dropsort");
|
||
* tree2.setBehavior("drag");
|
||
* document.body.appendChild(tree.getHTML());
|
||
* //Add a separator
|
||
* document.body.appendChild(document.createElement('hr'));
|
||
* document.body.appendChild(tree2.getHTML());
|
||
*/
|
||
var ContainerItemDropSortBehavior = function(settings) {
|
||
ContainerItemDropSortBehavior.superclass.call(this, settings);
|
||
this.dropped = null;
|
||
this.cancelledDrop = null;
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ContainerItemDropBehavior', ContainerItemDropSortBehavior);
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDropSortBehavior.prototype.updateBehaviorAvailability = function() {
|
||
this.targetHTML.sortable(this.disabled ? 'disable' : 'enable');
|
||
return this;
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when an accepted draggable is dropped on the
|
||
* {@link #property-targetObject targetObject}.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemDropSortBehavior.prototype.onDrop = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
var droppable = $(this),
|
||
targetObject = that.targetObject,
|
||
item = PMUI.getPMUIObject(ui.item.get(0)),
|
||
index = !targetObject.getItems().length ? 0 : droppable.find('>*').index(item.getHTML()),
|
||
data,
|
||
performDrop;
|
||
|
||
if(index < 0) {
|
||
index = droppable.find('>*').index(droppable.find('.ui-draggable'));
|
||
}
|
||
if(typeof targetObject.onBeforeDrop === 'function') {
|
||
targetObject.onBeforeDrop(targetObject, item, index);
|
||
}
|
||
if(typeof targetObject.onDrop === 'function') {
|
||
performDrop = targetObject.onDrop(targetObject, item, index);
|
||
}
|
||
if(performDrop || performDrop === undefined) {
|
||
item.getParent().behaviorObject.onDropOut(item, targetObject, index);
|
||
that.dropped = true;
|
||
if(!targetObject.canContain(item)) {
|
||
$(e.target).find('.ui-draggable').detach();
|
||
}
|
||
that.cancelledDrop = false;
|
||
} else {
|
||
//if the dropped object came from a container with draggable or sortable behavior
|
||
if(ui.helper) {
|
||
ui.sender.draggable('cancel');
|
||
} else {
|
||
ui.sender.sortable('cancel');
|
||
}
|
||
that.cancelledDrop = true;
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when the user stopped sorting and the
|
||
* {@link #property-targetObject targetObject}'s items positions have
|
||
* changed.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemDropSortBehavior.prototype.onUpdate = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
var parentHTML = that.targetObject.getHTML(),
|
||
item = PMUI.getPMUIObject(ui.item.get(0));
|
||
|
||
if(that.dropped) {
|
||
that.dropped = false;
|
||
return;
|
||
}
|
||
|
||
if(item && jQuery(parentHTML).has(item.getHTML()).length) {
|
||
(that.targetObject.onSortingChange()(e, ui));
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDropSortBehavior.prototype.onStop = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
if(that.cancelledDrop) {
|
||
ui.item.remove();
|
||
}
|
||
that.cancelledDrop = null;
|
||
};
|
||
};
|
||
/**
|
||
* @inherit
|
||
*/
|
||
ContainerItemDropSortBehavior.prototype.onStart = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
that.cancelledDrop = null;
|
||
};
|
||
};
|
||
/**
|
||
* Attaches the behavior to the {@link #property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemDropSortBehavior.prototype.attachBehavior = function() {
|
||
var $html,
|
||
i,
|
||
items,
|
||
item,
|
||
targetObject = this.targetObject;
|
||
if(!this.behaviorAttached) {
|
||
this.targetHTML = jQuery(targetObject.getContainmentArea());
|
||
this.targetHTML.addClass('pmui-containeritembehavior-sort').sortable({
|
||
containment: targetObject.getContainmentArea(),
|
||
receive: this.onDrop(),
|
||
start: this.onStart(),
|
||
update: this.onUpdate(),
|
||
items: this.sortableItems,
|
||
stop: this.onStop(),
|
||
tolerance: 'pointer',
|
||
handle: this.handle || false,
|
||
placeholder: this.placeholderClass
|
||
});
|
||
}
|
||
return ContainerItemDropSortBehavior.superclass.superclass.prototype.attachBehavior.call(this);
|
||
};
|
||
/**
|
||
* Detaches the behavior from the
|
||
* {@link #property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemDropSortBehavior.prototype.detachBehavior = function() {
|
||
if(this.behaviorAttached) {
|
||
try {
|
||
this.targetHTML.removeClass('pmui-containeritembehavior-sort').sortable('destroy');
|
||
} catch(e) {}
|
||
}
|
||
return ContainerItemDropSortBehavior.superclass.prototype.detachBehavior.call(this);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerItemDropSortBehavior', ContainerItemDropSortBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ContainerItemDropSortBehavior;
|
||
}
|
||
}());
|
||
(function() {
|
||
/**
|
||
* @class PMUI.behavior.ContainerItemDragDropSortBehavior
|
||
* @extends PMUI.behavior.ContainerItemDragDropBehavior
|
||
* Class that encapsulates the drop behavior for a {@link PMUI.core.Container Container} object and the drag and
|
||
* sort behaviors for its items. The object that applies this behavior, will be able to:
|
||
*
|
||
* - Accept draggable items from other Containers which ones are applying dragging behaviors
|
||
* ({@link PMUI.behavior.ContainerItemDragBehavior drag},
|
||
* {@link PMUI.behavior.ContainerItemDragDropBehavior dragdrop},
|
||
* {@link PMUI.behavior.ContainerItemDragSortBehavior dragsort},
|
||
* {@link PMUI.behavior.ContainerItemDragDropSortBehavior dragdropsort}).
|
||
*
|
||
* - The object's items will be able to be dragged to another Containers that are applying dropping behaviors
|
||
* ({@link PMUI.behavior.ContainerItemDropBehavior drop},
|
||
* {@link PMUI.behavior.ContainerItemDragDropBehavior dragdrop},
|
||
* {@link PMUI.behavior.ContainerItemDropSortBehavior dropsort},
|
||
* {@link PMUI.behavior.ContainerItemDragDropSortBehavior dragdropsort}).
|
||
*
|
||
* - The object's items will be enabled for sorting.
|
||
*
|
||
* Since this class is created through the
|
||
* {@link PMUI.behavior.ContainerItemBehaviorFactory ContainerItemBehaviorFactory} it shouldn't be instantiated in
|
||
* most cases (it is instantiated internally by the object of the Container class).
|
||
* If you want to apply this behavior to a {@link PMUI.core.Container Container} object, just call its
|
||
* {@link PMUI.core.Container#method-setBehavior setBehavior()} method with the string parameter "dragdropsort" or set it
|
||
* at instantiation time using its {@link PMUI.core.Container#cfg-behavior behavior} config option.
|
||
*
|
||
* Usage example:
|
||
*
|
||
* @example
|
||
* var tree = new PMUI.panel.TreePanel({
|
||
* items: [
|
||
* {
|
||
* label: "draggable item #1"
|
||
* }, {
|
||
* label: "draggable item #2"
|
||
* }, {
|
||
* label: "draggable item #3"
|
||
* }, {
|
||
* label: "draggable item #4"
|
||
* }, {
|
||
* label: "draggable item #5"
|
||
* }, {
|
||
* label: "draggable item #6"
|
||
* }
|
||
* ]
|
||
* }), tree2 = new PMUI.panel.TreePanel({
|
||
* style: {
|
||
* cssClasses: ["droppable-list"]
|
||
* },
|
||
* items: [
|
||
* {
|
||
* label: "draggable item #7"
|
||
* }, {
|
||
* label: "draggable item #8"
|
||
* }, {
|
||
* label: "draggable item #9"
|
||
* }, {
|
||
* label: "draggable item #10"
|
||
* }, {
|
||
* label: "draggable item #11"
|
||
* }, {
|
||
* label: "draggable item #12"
|
||
* }
|
||
* ]
|
||
* });
|
||
*
|
||
* tree.setBehavior("dragdropsort");
|
||
* tree2.setBehavior("dragdropsort");
|
||
* document.body.appendChild(tree.getHTML());
|
||
* //Add a separator
|
||
* document.body.appendChild(document.createElement('hr'));
|
||
* document.body.appendChild(tree2.getHTML());
|
||
*/
|
||
var ContainerItemDragDropSortBehavior = function(settings) {
|
||
ContainerItemDragDropSortBehavior.superclass.call(this, settings);
|
||
this.dropped = null;
|
||
this.cancelledDrop = null;
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.behavior.ContainerItemDragDropBehavior', ContainerItemDragDropSortBehavior);
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDragDropSortBehavior.prototype.updateBehaviorAvailability = function() {
|
||
this.targetHTML.sortable(this.disabled ? 'disable' : 'enable');
|
||
if(this.disabled) {
|
||
this.detachOnDraggableMouseEvents();
|
||
} else {
|
||
this.attachOnDraggableMouseEvents();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when the user stopped sorting and the
|
||
* {@link #property-targetObject targetObject}'s items positions have
|
||
* changed.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemDragDropSortBehavior.prototype.onUpdate = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
var parentHTML = that.targetObject.getHTML(),
|
||
item = PMUI.getPMUIObject(ui.item.get(0));
|
||
if(that.dropped) {
|
||
that.dropped = false;
|
||
return;
|
||
}
|
||
|
||
if(!item) {
|
||
return;
|
||
}
|
||
|
||
if(jQuery(parentHTML).has(item.getHTML()).length) {
|
||
(that.targetObject.onSortingChange()(e, ui));
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDragDropSortBehavior.prototype.onStart = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
var targetObject, o;
|
||
that.cancelledDrop = null;
|
||
//Since the jQuery sortable's start callback is executed when the sorting starts and not neccesarily when
|
||
//one of its own items starts dragging we need to do the next validation:
|
||
//check if the item dragged belongs to the sortable html. In that case we fire the onDragStart callback.
|
||
o = PMUI.getPMUIObject(ui.item.get(0));
|
||
if(that.targetObject.isDirectParentOf(o)) {
|
||
targetObject = that.targetObject;
|
||
ui.helper.get(0).style.width = $(e.target).width() + "px";
|
||
ui.item.hide();
|
||
that.draggedObject = o;
|
||
if(typeof targetObject.onDragStart === 'function') {
|
||
targetObject.onDragStart(targetObject, that.draggedObject);
|
||
}
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Defines the handler to be executed when an accepted draggable is dropped on the
|
||
* {@link #property-targetObject targetObject}.
|
||
* @return {Function} The handler.
|
||
* @private
|
||
*/
|
||
ContainerItemDragDropSortBehavior.prototype.onDrop = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
var targetObject = that.targetObject,
|
||
droppable = $(this),
|
||
item = PMUI.getPMUIObject(ui.item.get(0)),
|
||
data,
|
||
index = !targetObject.getItems().length ? 0
|
||
: droppable.find('>*').index(item.getHTML()),
|
||
performDrop;
|
||
|
||
if(index < 0) {
|
||
index = droppable.find('>*').index(droppable.find('.ui-draggable'));
|
||
}
|
||
if(typeof targetObject.onBeforeDrop === 'function') {
|
||
targetObject.onBeforeDrop(targetObject, item, index);
|
||
}
|
||
if(typeof targetObject.onDrop === 'function') {
|
||
performDrop = targetObject.onDrop(targetObject, item, index);
|
||
}
|
||
if(performDrop || performDrop === undefined) {
|
||
item.getParent().behaviorObject.onDropOut(item, targetObject, index);
|
||
that.dropped = true;
|
||
if(!targetObject.canContain(item)) {
|
||
$(e.target).find('.ui-draggable').detach();
|
||
}
|
||
that.cancelledDrop = false;
|
||
} else {
|
||
//if the dropped object came from a container with draggable or sortable behavior
|
||
if(ui.helper) {
|
||
//from draggable
|
||
ui.sender.draggable('cancel');
|
||
} else {
|
||
//from sortable
|
||
ui.sender.sortable('cancel');
|
||
}
|
||
that.cancelledDrop = true;
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* @inheritdoc
|
||
*/
|
||
ContainerItemDragDropSortBehavior.prototype.onStop = function() {
|
||
var that = this;
|
||
return function(e, ui) {
|
||
if(that.cancelledDrop) {
|
||
ui.item.remove();
|
||
}
|
||
that.cancelledDrop = null;
|
||
};
|
||
};
|
||
/**
|
||
* Attaches the behavior to the {@link #property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemDragDropSortBehavior.prototype.attachBehavior = function() {
|
||
var $html,
|
||
i,
|
||
items,
|
||
item,
|
||
targetObject = this.targetObject;
|
||
if(!this.behaviorAttached) {
|
||
this.targetHTML = jQuery(this.targetObject.getContainmentArea());
|
||
this.targetHTML.addClass('pmui-containeritembehavior-sort').sortable({
|
||
appendTo: document.body,
|
||
connectWith: '.pmui-containeritembehavior-sort',
|
||
helper: 'clone',
|
||
sort: this.onDrag(),
|
||
start: this.onStart(),
|
||
stop: this.onStop(),
|
||
receive: this.onDrop(),
|
||
out: this.onOut(),
|
||
over: this.onOver(),
|
||
update: this.onUpdate(),
|
||
items: this.sortableItems,
|
||
tolerance: 'pointer',
|
||
placeholder: this.placeholderClass,
|
||
handle: this.handle || false,
|
||
zIndex: 1000
|
||
});
|
||
this.attachOnDraggableMouseEvents();
|
||
}
|
||
return ContainerItemDragDropSortBehavior.superclass.superclass.prototype.attachBehavior.call(this);
|
||
};
|
||
/**
|
||
* Detaches the behavior from the
|
||
* {@link #property-targetObject targetObject}.
|
||
* @chainable
|
||
*/
|
||
ContainerItemDragDropSortBehavior.prototype.detachBehavior = function() {
|
||
if(this.behaviorAttached) {
|
||
try {
|
||
this.targetHTML.removeClass('pmui-containeritembehavior-sort').sortable('destroy');
|
||
this.detachOnDraggableMouseEvents();
|
||
} catch(e) {}
|
||
}
|
||
return ContainerItemDragDropSortBehavior.superclass.prototype.detachBehavior.call(this);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerItemDragDropSortBehavior', ContainerItemDragDropSortBehavior);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ContainerItemDragDropSortBehavior;
|
||
}
|
||
}());
|
||
(function() {
|
||
/**
|
||
* @class PMUI.behavior.ContainerItemBehaviorFactory
|
||
* A factory that produces the behavior objects for {@link PMUI.core.Container Container} objects.
|
||
*
|
||
* It accepts the following pmTypes:
|
||
*
|
||
* - using "nobehavior" you get a {@link PMUI.behavior.ContainerItemNoBehavior ContainerItemNoBehavior object}.
|
||
* - using "drag" you get a {@link PMUI.behavior.ContainerItemDragBehavior ContainerItemDragBehavior object}.
|
||
* - using "drop" you get a {@link PMUI.behavior.ContainerItemDropBehavior ContainerItemDropBehavior object}.
|
||
* - using "sort" you get a {@link PMUI.behavior.ContainerItemSortBehavior ContainerItemSortBehavior object}.
|
||
* - using "dragdrop" you get a {@link PMUI.behavior.ContainerItemDragDropBehavior ContainerItemDragDropBehavior object}.
|
||
* - using "dragsort" you get a {@link PMUI.behavior.ContainerItemDragSortBehavior ContainerItemDragSortBehavior object}.
|
||
* - using "dropsort" you get a {@link PMUI.behavior.ContainerItemDropSortBehavior ContainerItemDropSortBehavior object}.
|
||
* - using "dragdropsort" you get a {@link PMUI.behavior.ContainerItemDragDropSortBehavior ContainerItemDragDropSortBehavior object}.
|
||
*
|
||
* The default pmType is 'nobehavior'.
|
||
* @extends {PMUI.util.Factory}
|
||
*/
|
||
var ContainerItemBehaviorFactory = function(settings) {
|
||
ContainerItemBehaviorFactory.superclass.call(this, settings);
|
||
ContainerItemBehaviorFactory.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.util.Factory', ContainerItemBehaviorFactory);
|
||
/**
|
||
* Initializes the new instance.
|
||
* @param {Object} settings An object with the config options.
|
||
* @private
|
||
*/
|
||
ContainerItemBehaviorFactory.prototype.init = function(settings) {
|
||
var defaults = {
|
||
products: {
|
||
'nobehavior': PMUI.behavior.ContainerItemNoBehavior,
|
||
'drag': PMUI.behavior.ContainerItemDragBehavior,
|
||
'dragclone': PMUI.behavior.ContainerItemDragCloneBehavior,
|
||
'drop': PMUI.behavior.ContainerItemDropBehavior,
|
||
'sort': PMUI.behavior.ContainerItemSortBehavior,
|
||
'dragdrop': PMUI.behavior.ContainerItemDragDropBehavior,
|
||
'dragsort': PMUI.behavior.ContainerItemDragSortBehavior,
|
||
'dropsort': PMUI.behavior.ContainerItemDropSortBehavior,
|
||
'dragdropsort': PMUI.behavior.ContainerItemDragDropSortBehavior
|
||
},
|
||
defaultProduct: 'nobehavior'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setProducts(defaults.products)
|
||
.setDefaultProduct(defaults.defaultProduct);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.behavior.ContainerItemBehaviorFactory', ContainerItemBehaviorFactory);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ContainerItemBehaviorFactory;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.command.Command
|
||
* Abstract class command which declares some abstract methods such as
|
||
* execute (redo) and inverseExecute (undo) a command.
|
||
*
|
||
* A command is implemented in the library as follows:
|
||
*
|
||
* - The command must define a method execute which does the operation desired (e.g. commandDelete's execute
|
||
* method deletes shapes and connections from a canvas).
|
||
* - The command must define a method undo which undoes what the method execute did.
|
||
* - The command must define a method redo which simply calls the execute method (redo must do the
|
||
* same operation as execute).
|
||
*
|
||
* Finally to execute and save the command let's use the
|
||
{@link PMUI.draw.Canvas#property-commandStack} property that any
|
||
* canvas has so:
|
||
*
|
||
* // e.g.
|
||
* // let's assume that canvas is an instance of the class Canvas
|
||
* // let's create an instance of commandDelete
|
||
* // let's assume that config has the correct configuration options of this command
|
||
* var command = new PMUI.command.CommandDelete(config)
|
||
* // let's add the command to the canvas's commandStack
|
||
* canvas.commandStack.add(command);
|
||
* // finally let's execute the command
|
||
* command.execute(); // this line actually removes the shapes!
|
||
*
|
||
* // if we want to undo the last command
|
||
* canvas.commandStack.undo(); // this line recreates the shapes
|
||
*
|
||
* // if we want to redo the last command
|
||
* canvas.commandStack.redo(); // this line removes the shapes again
|
||
*
|
||
* @abstract
|
||
* @constructor Creates an instance of the class command
|
||
* @param {Object} receiver The object that will execute the command
|
||
*/
|
||
var Command = function (receiver) {
|
||
|
||
/**
|
||
* The object that executes the command
|
||
* @property {Object}
|
||
*/
|
||
this.receiver = receiver;
|
||
/**
|
||
* Reference to the canvas
|
||
* @property {PMUI.draw.Canvas}
|
||
*/
|
||
|
||
this.canvas = this.getCanvas(receiver);
|
||
|
||
};
|
||
|
||
/**
|
||
* Family of this command
|
||
* @property {String}
|
||
*/
|
||
Command.prototype.family = "Command";
|
||
|
||
/**
|
||
* Executes the command
|
||
* @template
|
||
* @protected
|
||
*/
|
||
Command.prototype.execute = function (stopTrigger) {
|
||
};
|
||
|
||
/**
|
||
* InverseExecutes the command (a.k.a. undo)
|
||
* @template
|
||
* @protected
|
||
*/
|
||
Command.prototype.undo = function (stopTrigger) {
|
||
};
|
||
|
||
/**
|
||
* Executes the command (a.k.a. redo)
|
||
* @template
|
||
* @protected
|
||
*/
|
||
Command.prototype.redo = function (stopTrigger) {
|
||
};
|
||
|
||
Command.prototype.getCanvas = function (obj) {
|
||
var aux,
|
||
canvas;
|
||
|
||
if (obj.getSize) {
|
||
aux = obj.get(0);
|
||
canvas = aux.getCanvas();
|
||
} else if (obj.getCanvas) {
|
||
canvas = obj.getCanvas();
|
||
} else {
|
||
canvas = null;
|
||
}
|
||
return canvas;
|
||
};
|
||
|
||
// extend the namespace
|
||
PMUI.extendNamespace('PMUI.command.Command', Command);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.command.CommandConnect
|
||
* Class CommandConnect determines the actions executed when a connection is created (redo) and the actions
|
||
* executed when it's destroyed (undo).
|
||
*
|
||
* Instances of this class are created in {@link PMUI.draw.Canvas#removeElements}.
|
||
*
|
||
* @extends PMUI.command.Command
|
||
*
|
||
* @constructor Creates an instance of the class CommandConnect.
|
||
* @param {Object} receiver The object that will execute the command
|
||
*/
|
||
var CommandConnect = function (receiver) {
|
||
CommandConnect.superclass.call(this, receiver);
|
||
};
|
||
PMUI.inheritFrom('PMUI.command.Command', CommandConnect);
|
||
/**
|
||
* Type of command
|
||
* @property {String}
|
||
*/
|
||
CommandConnect.prototype.type = "CommandConnect";
|
||
/**
|
||
* Build the connection.
|
||
* The steps are:
|
||
*
|
||
* 1. Insert the ports in their respective parents (shapes)
|
||
* 2. Append the html of the ports
|
||
* 3. Add the connection html to the canvas
|
||
* 4. Trigger the create event *
|
||
* @chainable
|
||
*/
|
||
CommandConnect.prototype.buildConnection = function() {
|
||
var connection = this.receiver,
|
||
canvas = connection.canvas,
|
||
srcPort = connection.getSrcPort(),
|
||
destPort = connection.getDestPort();
|
||
|
||
// save the ports in its parents' ports array
|
||
srcPort.parent.ports.insert(srcPort);
|
||
destPort.parent.ports.insert(destPort);
|
||
|
||
// append the html of the ports to its parents (customShapes)
|
||
srcPort.parent.html.appendChild(srcPort.getHTML());
|
||
destPort.parent.html.appendChild(destPort.getHTML());
|
||
|
||
// add the connection to the canvas (its html is appended)
|
||
canvas.addConnection(connection);
|
||
canvas.updatedElement = connection;
|
||
return connection;
|
||
};
|
||
/**
|
||
* Executes the command.
|
||
* The steps are:
|
||
*
|
||
* 1. Insert the ports in their respective parents (shapes)
|
||
* 2. Append the html of the ports
|
||
* 3. Add the connection html to the canvas
|
||
* 4. Trigger the create event
|
||
*
|
||
* @chainable
|
||
*/
|
||
CommandConnect.prototype.execute = function () {
|
||
var connection = this.receiver,
|
||
canvas = connection.canvas,
|
||
srcPort = connection.getSrcPort(),
|
||
destPort = connection.getDestPort();
|
||
// save the ports in its parents' ports array
|
||
srcPort.parent.ports.insert(srcPort);
|
||
destPort.parent.ports.insert(destPort);
|
||
// append the html of the ports to its parents (customShapes)
|
||
srcPort.parent.html.appendChild(srcPort.getHTML());
|
||
destPort.parent.html.appendChild(destPort.getHTML());
|
||
// add the connection to the canvas (its html is appended)
|
||
canvas.addConnection(connection);
|
||
connection.checkAndCreateIntersectionsWithAll()
|
||
canvas.updatedElement = connection;
|
||
canvas.triggerCreateEvent(connection, []);
|
||
return this;
|
||
};
|
||
/**
|
||
* Inverse executes the command a.k.a. undo.
|
||
* The steps are:
|
||
*
|
||
* 1. Save the connection (detach it from the DOM)
|
||
* 2. Trigger the remove event
|
||
*
|
||
* @chainable
|
||
*/
|
||
CommandConnect.prototype.undo = function () {
|
||
this.receiver.saveAndDestroy();
|
||
this.receiver.canvas.triggerRemoveEvent(this.receiver, []);
|
||
return this;
|
||
};
|
||
/**
|
||
* Executes the command a.k.a. redo by calling `this.execute`
|
||
* @chainable
|
||
*/
|
||
CommandConnect.prototype.redo = function () {
|
||
this.execute();
|
||
return this;
|
||
};
|
||
|
||
// extend the namespace
|
||
PMUI.extendNamespace('PMUI.command.CommandConnect', CommandConnect);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.command.CommandCreate
|
||
* Class CommandCreate determines the actions executed when some shapes are created (redo) and the actions
|
||
* executed when they're destroyed (undo).
|
||
*
|
||
* Instances of this class are created in {@link PMUI.behavior.ConnectionDropBehavior#onDrop}.
|
||
* @extends PMUI.command.Command
|
||
*
|
||
* @constructor Creates an instance of the class CommandCreate
|
||
* @param {Object} receiver The object that will execute the command
|
||
*
|
||
*/
|
||
var CommandCreate = function (receiver) {
|
||
CommandCreate.superclass.call(this, receiver);
|
||
|
||
/**
|
||
* Object that represents the state of the receiver before
|
||
* it was created
|
||
* @property {Object}
|
||
*/
|
||
this.before = null;
|
||
|
||
/**
|
||
* Object that represents the state of the receiver after
|
||
* it was created
|
||
* @property {Object}
|
||
*/
|
||
this.after = null;
|
||
|
||
CommandCreate.prototype.initObject.call(this, receiver);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.command.Command', CommandCreate);
|
||
|
||
/**
|
||
* Type of command
|
||
* @property {String}
|
||
*/
|
||
CommandCreate.prototype.type = "CommandCreate";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance
|
||
* @param {Object} receiver
|
||
* @private
|
||
*/
|
||
CommandCreate.prototype.initObject = function (receiver) {
|
||
this.before = {};
|
||
this.after = {
|
||
x: receiver.getX(),
|
||
y: receiver.getY(),
|
||
parent: receiver.getParent()
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Executes the command.
|
||
* The steps are:
|
||
*
|
||
* 1. Insert the current shape to the children of its parent if it's possible
|
||
* 2. Append it to the HTML of its parent
|
||
* 3. Add the shape to either `canvas.customShapes` or `canvas.regularShapes`
|
||
* 4. Trigger the create event
|
||
*
|
||
* @chainable
|
||
*/
|
||
CommandCreate.prototype.execute = function () {
|
||
|
||
// execute the trigger
|
||
var shape = this.receiver,
|
||
parent = shape.parent;
|
||
|
||
// append the html to its parent
|
||
// NOTE: in the first execution (in containerDropBehavior) the html is
|
||
// already in the parent so the following line appends it again (html
|
||
// is not created)
|
||
|
||
// note that during the execution of this command the next line may called twice (one in
|
||
// RegularContainerBehavior.addToContainer and the other here) so check if it's not
|
||
// already in its children
|
||
if (!parent.getChildren().contains(shape)) {
|
||
parent.getChildren().insert(shape);
|
||
}
|
||
this.after.parent.html.appendChild(shape.getHTML());
|
||
shape.canvas.addToList(shape);
|
||
shape.showOrHideResizeHandlers(false);
|
||
shape.canvas.triggerCreateEvent(shape, []);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Inverse executes the command a.k.a. undo
|
||
*
|
||
* The steps are:
|
||
*
|
||
* 1. Remove the current shape from the children of its parent if it's possible
|
||
* 2. Remove its HTML (detach it from the DOM)
|
||
* 4. Trigger the remove event
|
||
*
|
||
* @chainable
|
||
*/
|
||
CommandCreate.prototype.undo = function () {
|
||
this.receiver.parent.getChildren().remove(this.receiver);
|
||
this.receiver.saveAndDestroy();
|
||
this.receiver.canvas.triggerRemoveEvent(this.receiver, []);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Executes the command a.k.a redo
|
||
* @chainable
|
||
*/
|
||
CommandCreate.prototype.redo = function () {
|
||
this.execute();
|
||
return this;
|
||
};
|
||
|
||
// extend the namespace
|
||
PMUI.extendNamespace('PMUI.command.CommandCreate', CommandCreate);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.command.CommandDelete
|
||
* Class CommandDelete determines the actions executed when some shapes are deleted (redo) and the actions
|
||
* executed when they're recreated (undo).
|
||
*
|
||
* Instances of this class are created in {@link PMUI.draw.Canvas#removeElements}.
|
||
* @extends PMUI.command.Command
|
||
*
|
||
* @constructor Creates an instance of the class CommandDelete
|
||
* @param {Object} receiver The object that will execute the command
|
||
*/
|
||
var CommandDelete = function (receiver) {
|
||
CommandDelete.superclass.call(this, receiver);
|
||
/**
|
||
* A stack of commandsConnect
|
||
* @property {Array}
|
||
*/
|
||
this.stackCommandConnect = [];
|
||
/**
|
||
* ArrayList that represents the selection that was active before deleting the elements
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.currentSelection = new PMUI.util.ArrayList();
|
||
/**
|
||
* Reference to the current connection in the canvas
|
||
* @property {PMUI.draw.Connection}
|
||
*/
|
||
this.currentConnection = null;
|
||
/**
|
||
* List of all the elements related to the commands
|
||
* @property {Array}
|
||
*/
|
||
this.relatedElements = [];
|
||
CommandDelete.prototype.initObject.call(this, receiver);
|
||
};
|
||
PMUI.inheritFrom('PMUI.command.Command', CommandDelete);
|
||
/**
|
||
* Type of command
|
||
* @property {String}
|
||
*/
|
||
CommandDelete.prototype.type = "CommandDelete";
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance
|
||
* @param {Object} receiver The object that will execute the command
|
||
* @private
|
||
*/
|
||
CommandDelete.prototype.initObject = function (receiver) {
|
||
var i,
|
||
shape;
|
||
// move the current selection to this.currentSelection array
|
||
for (i = 0; i < receiver.getCurrentSelection().getSize() > 0; i += 1) {
|
||
shape = receiver.getCurrentSelection().get(i);
|
||
this.currentSelection.insert(shape);
|
||
}
|
||
// save the currentConnection of the canvas if possible
|
||
if (receiver.currentConnection) {
|
||
this.currentConnection = receiver.currentConnection;
|
||
}
|
||
};
|
||
/**
|
||
* Saves and destroys connections and shapes
|
||
* @private
|
||
* @param {Object} shape
|
||
* @param {boolean} root True if `shape` is a root element in the tree
|
||
* @param {boolean} [fillArray] If set to true it'll fill `this.relatedElements` with the objects erased
|
||
* @return {boolean}
|
||
*/
|
||
CommandDelete.prototype.saveAndDestroy = function (shape, root, fillArray) {
|
||
var i,
|
||
child,
|
||
parent,
|
||
children = null,
|
||
connection,
|
||
canvas = shape.canvas;
|
||
if (shape.hasOwnProperty("children")) {
|
||
children = shape.children;
|
||
}
|
||
// special function to be called as an afterwards
|
||
// BIG NOTE: doesn't have to delete html
|
||
if (shape.destroy) {
|
||
shape.destroy();
|
||
}
|
||
for (i = 0; i < children.getSize(); i += 1) {
|
||
child = children.get(i);
|
||
this.saveAndDestroy(child, false, fillArray);
|
||
}
|
||
while (shape.ports && shape.ports.getSize() > 0) {
|
||
connection = shape.ports.getFirst().connection;
|
||
if (fillArray) {
|
||
this.relatedElements.push(connection);
|
||
}
|
||
this.stackCommandConnect.push(
|
||
new PMUI.command.CommandConnect(connection)
|
||
);
|
||
connection.saveAndDestroy();
|
||
}
|
||
// remove from the children array of its parent
|
||
if (root) {
|
||
parent = shape.parent;
|
||
parent.getChildren().remove(shape);
|
||
if (parent.isResizable()) {
|
||
parent.resizeBehavior.updateResizeMinimums(shape.parent);
|
||
}
|
||
// remove from the currentSelection and from either the customShapes
|
||
// arrayList or the regularShapes arrayList
|
||
canvas.removeFromList(shape);
|
||
// remove the html only from the root
|
||
shape.html = $(shape.html).detach()[0];
|
||
}
|
||
if (fillArray) {
|
||
this.relatedElements.push(shape);
|
||
}
|
||
return true;
|
||
};
|
||
/**
|
||
* Executes the command
|
||
* The steps are:
|
||
*
|
||
* 1. Retrieve the old currentSelection (saved in `this.initObject()`)
|
||
* 2. Remove the shapes (detaching them from the DOM)
|
||
* 3. Remove the currentConnection if there's one
|
||
* 4. Trigger the remove event
|
||
*
|
||
* @chainable
|
||
*/
|
||
CommandDelete.prototype.execute = function () {
|
||
var shape,
|
||
i,
|
||
canvas = this.receiver,
|
||
currentConnection,
|
||
stringified,
|
||
fillArray = false,
|
||
mainShape = null;
|
||
if (this.relatedElements.length === 0) {
|
||
fillArray = true;
|
||
}
|
||
canvas.emptyCurrentSelection();
|
||
// copy from this.currentConnection
|
||
for (i = 0; i < this.currentSelection.getSize(); i += 1) {
|
||
shape = this.currentSelection.get(i);
|
||
canvas.addToSelection(shape);
|
||
}
|
||
if (canvas.currentSelection.getSize() === 1) {
|
||
mainShape = shape;
|
||
}
|
||
|
||
// remove the elements in the canvas current selection
|
||
stringified = [];
|
||
while (canvas.getCurrentSelection().getSize() > 0) {
|
||
shape = canvas.getCurrentSelection().getFirst();
|
||
this.saveAndDestroy(shape, true, fillArray);
|
||
stringified.push(shape.stringify());
|
||
}
|
||
|
||
// destroy the currentConnection
|
||
canvas.currentConnection = this.currentConnection;
|
||
currentConnection = canvas.currentConnection;
|
||
if (currentConnection) {
|
||
// add to relatedElements just in the case when only a connection is
|
||
// selected and deleted
|
||
this.relatedElements.push(currentConnection);
|
||
this.stackCommandConnect.push(
|
||
new PMUI.command.CommandConnect(currentConnection)
|
||
);
|
||
currentConnection.saveAndDestroy();
|
||
currentConnection = null;
|
||
}
|
||
canvas.triggerRemoveEvent(mainShape, this.relatedElements);
|
||
return this;
|
||
};
|
||
/**
|
||
* Inverse executes the command a.k.a. undo
|
||
*
|
||
* The steps are:
|
||
*
|
||
* 1. Retrieve the old currentSelection (saved in `this.initObject()`)
|
||
* 2. Restore the shapes (attaching them to the DOM)
|
||
* 3. Restore the currentConnection if there was one
|
||
* 4. Trigger the create event
|
||
*
|
||
* @chainable
|
||
*/
|
||
CommandDelete.prototype.undo = function () {
|
||
// undo recreates the shapes
|
||
var i,
|
||
shape,
|
||
mainShape = this.receiver.currentSelection.getFirst();
|
||
for (i = 0; i < this.currentSelection.getSize(); i += 1) {
|
||
shape = this.currentSelection.get(i);
|
||
// add to the canvas array of regularShapes and customShapes
|
||
shape.canvas.addToList(shape);
|
||
// add to the children of the parent
|
||
shape.parent.getChildren().insert(shape);
|
||
shape.parent.html.appendChild(shape.getHTML());
|
||
shape.showOrHideResizeHandlers(false);
|
||
}
|
||
// reconnect using the stack of commandConnect
|
||
for (i = this.stackCommandConnect.length - 1; i >= 0; i -= 1) {
|
||
this.stackCommandConnect[i].redo();
|
||
}
|
||
this.receiver.triggerCreateEvent(mainShape, this.relatedElements);
|
||
return this;
|
||
};
|
||
/**
|
||
* Executes the command (a.k.a redo)
|
||
* @chainable
|
||
*/
|
||
CommandDelete.prototype.redo = function () {
|
||
this.execute();
|
||
return this;
|
||
};
|
||
// extend namespace
|
||
PMUI.extendNamespace('PMUI.command.CommandDelete', CommandDelete);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.command.CommandEditLabel
|
||
* Encapsulates the action of editing a label
|
||
*
|
||
* //e.g.
|
||
* // var command = new PMUI.command.CommandEditLabel(label, "new message");
|
||
* @extends PMUI.command.Command
|
||
*
|
||
* @constructor
|
||
* Creates an instance of this command
|
||
* @param {PMUI.draw.Label} receiver The object that will perform the action
|
||
* @param {String} newMessage
|
||
*/
|
||
var CommandEditLabel = function (receiver, newMessage) {
|
||
CommandEditLabel.superclass.call(this, receiver);
|
||
this.before = null;
|
||
this.after = null;
|
||
CommandEditLabel.prototype.initObject.call(this, receiver, newMessage);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.command.Command', CommandEditLabel);
|
||
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
CommandEditLabel.prototype.type = "CommandEditLabel";
|
||
/**
|
||
* Initializes the command
|
||
* @param {PMUI.draw.Label} receiver The object that will perform the action
|
||
* @param {String} newMessage
|
||
*/
|
||
CommandEditLabel.prototype.initObject = function (receiver, newMessage) {
|
||
var parentHeight = 0,
|
||
parentWidth = 0;
|
||
if (receiver.parent) {
|
||
parentHeight = receiver.parent.height;
|
||
parentWidth = receiver.parent.width;
|
||
}
|
||
this.before = {
|
||
message: receiver.message,
|
||
width: receiver.width,
|
||
height: receiver.height,
|
||
parentHeight: parentHeight,
|
||
parentWidth: parentWidth
|
||
};
|
||
this.after = {
|
||
message: newMessage,
|
||
width: 0,
|
||
height: 0,
|
||
parentHeight: parentWidth,
|
||
parentWidth: parentHeight
|
||
};
|
||
};
|
||
/**
|
||
* Executes the command, sets the new message updates the dimensions and its,
|
||
* parent if necessary
|
||
*/
|
||
CommandEditLabel.prototype.execute = function (stopTrigger) {
|
||
this.receiver.setMessage(this.after.message);
|
||
this.receiver.updateDimension();
|
||
if (this.after.width === 0) {
|
||
this.after.width = this.receiver.width;
|
||
this.after.height = this.receiver.height;
|
||
if (this.after.parentWidth !== 0) {
|
||
this.after.parentWidth = this.receiver.parent.width;
|
||
this.after.parentHeight = this.receiver.parent.height;
|
||
}
|
||
}
|
||
this.receiver.paint();
|
||
if (!stopTrigger) {
|
||
this.receiver.canvas.triggerTextChangeEvent(
|
||
this.receiver,
|
||
this.before.message,
|
||
this.after.message
|
||
);
|
||
if ((this.after.parentWidth !== this.before.parentWidth) &&
|
||
(this.before.parentHeight !== this.after.parentHeight)) {
|
||
this.receiver.canvas.triggerDimensionChangeEvent(
|
||
this.receiver.parent,
|
||
this.before.parentWidth,
|
||
this.before.parentHeight,
|
||
this.after.parentWidth,
|
||
this.after.parentHeight
|
||
);
|
||
}
|
||
}
|
||
};
|
||
/**
|
||
* Returns to the previous state before executing the command
|
||
*/
|
||
CommandEditLabel.prototype.undo = function (stopTrigger) {
|
||
this.receiver.setMessage(this.before.message);
|
||
|
||
if (this.receiver.parent) {
|
||
this.receiver.parent.setDimension(this.before.parentWidth, this.before.parentHeight);
|
||
}
|
||
this.receiver.setDimension(this.before.width, this.before.height);
|
||
this.receiver.updateDimension();
|
||
this.receiver.paint();
|
||
this.receiver.canvas.triggerTextChangeEvent(
|
||
this.receiver,
|
||
this.after.message,
|
||
this.before.message
|
||
);
|
||
if ((this.after.parentWidth !== this.before.parentWidth) &&
|
||
(this.before.parentHeight !== this.after.parentHeight)) {
|
||
this.receiver.canvas.triggerDimensionChangeEvent(
|
||
this.receiver.parent,
|
||
this.after.parentWidth,
|
||
this.after.parentHeight,
|
||
this.before.parentWidth,
|
||
this.before.parentHeight
|
||
);
|
||
}
|
||
};
|
||
/**
|
||
* Executes the command again after an undo action has been done
|
||
*/
|
||
CommandEditLabel.prototype.redo = function () {
|
||
this.execute();
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.command.CommandEditLabel', CommandEditLabel);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.command.CommandMove
|
||
* Encapsulates the action of moving an element
|
||
*
|
||
* //e.g.
|
||
* var command = new PMUI.command.CommandMove(shape);
|
||
* @extends PMUI.command.Command
|
||
*
|
||
* @constructor
|
||
* Creates an instance of CommandMove
|
||
* @param {Object} receiver The object that will perform the action
|
||
*/
|
||
var CommandMove = function (receiver) {
|
||
CommandMove.superclass.call(this, receiver);
|
||
this.before = null;
|
||
this.after = null;
|
||
this.relatedShapes = [];
|
||
CommandMove.prototype.initObject.call(this, receiver);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.command.Command', CommandMove);
|
||
/**
|
||
* Type of the instances of this class
|
||
* @property {String}
|
||
*/
|
||
CommandMove.prototype.type = "CommandMove";
|
||
|
||
/**
|
||
* Initializes the command parameters
|
||
* @param {PMUI.draw.Core} receiver The object that will perform the action
|
||
*/
|
||
CommandMove.prototype.initObject = function (receiver) {
|
||
var i,
|
||
beforeShapes = [],
|
||
afterShapes = [];
|
||
for (i = 0; i < receiver.getSize(); i += 1) {
|
||
this.relatedShapes.push(receiver.get(i));
|
||
beforeShapes.push({
|
||
x: receiver.get(i).getOldX(),
|
||
y: receiver.get(i).getOldY()
|
||
});
|
||
afterShapes.push({
|
||
x: receiver.get(i).getX(),
|
||
y: receiver.get(i).getY()
|
||
});
|
||
}
|
||
this.before = {
|
||
shapes: beforeShapes
|
||
};
|
||
this.after = {
|
||
shapes: afterShapes
|
||
};
|
||
this.moveUndo = false;
|
||
};
|
||
|
||
/**
|
||
* Executes the command, changes the position of the element, and if necessary
|
||
* updates the position of its children, and refreshes all connections
|
||
*/
|
||
CommandMove.prototype.execute = function () {
|
||
var i,
|
||
j,
|
||
max,
|
||
connection,
|
||
shape,
|
||
delta;
|
||
//clear used array
|
||
PMUI.getActiveCanvas().refreshArray.clear();
|
||
PMUI.getActiveCanvas().connToRefresh.clear();
|
||
for (i = 0; i < this.relatedShapes.length; i += 1) {
|
||
shape = this.relatedShapes[i];
|
||
//delta to move user connections
|
||
delta = {
|
||
dx: this.after.shapes[i].x - this.before.shapes[i].x,
|
||
dy: this.after.shapes[i].y - this.before.shapes[i].y
|
||
};
|
||
shape.setPosition(this.after.shapes[i].x, this.after.shapes[i].y)
|
||
.refreshChildrenPositions(true, delta);
|
||
|
||
for (j = 0, max = this.canvas.connToRefresh.getSize(); j < max; j += 1) {
|
||
connection = this.canvas.connToRefresh.get(j);
|
||
connection.reconectSwitcher(delta, false);
|
||
}
|
||
shape.refreshConnections(false, this.relatedShapes, delta);
|
||
|
||
}
|
||
this.canvas.triggerPositionChangeEvent(this.relatedShapes,
|
||
this.before.shapes, this.after.shapes);
|
||
if (this.moveUndo) {
|
||
for (j = 0; j < PMUI.getActiveCanvas().refreshArray.getSize(); j += 1) {
|
||
connection = PMUI.getActiveCanvas().refreshArray.get(j);
|
||
connection.reconnectUser(delta, false);
|
||
connection.setSegmentMoveHandlers()
|
||
.checkAndCreateIntersectionsWithAll();
|
||
PMUI.getActiveCanvas().triggerConnectionStateChangeEvent(connection);
|
||
}
|
||
this.moveUndo = false;
|
||
}
|
||
|
||
};
|
||
|
||
/**
|
||
* Returns to the state before the command was executed
|
||
*/
|
||
CommandMove.prototype.undo = function () {
|
||
var i,
|
||
delta,
|
||
shape,
|
||
connection,
|
||
j, max;
|
||
PMUI.getActiveCanvas().refreshArray.clear();
|
||
PMUI.getActiveCanvas().connToRefresh.clear();
|
||
for (i = 0; i < this.relatedShapes.length; i += 1) {
|
||
shape = this.relatedShapes[i];
|
||
delta = {
|
||
dx: this.before.shapes[i].x - this.after.shapes[i].x,
|
||
dy: this.before.shapes[i].y - this.after.shapes[i].y
|
||
};
|
||
shape.setPosition(this.before.shapes[i].x, this.before.shapes[i].y)
|
||
.refreshChildrenPositions(true, delta);
|
||
|
||
for (j = 0, max = this.canvas.connToRefresh.getSize(); j < max; j += 1) {
|
||
connection = this.canvas.connToRefresh.get(j);
|
||
connection.reconectSwitcher(delta, false);
|
||
}
|
||
shape.refreshConnections(false, this.relatedShapes, delta);
|
||
|
||
}
|
||
this.canvas.triggerPositionChangeEvent(this.relatedShapes,
|
||
this.after.shapes, this.before.shapes);
|
||
|
||
for (j = 0; j < PMUI.getActiveCanvas().refreshArray.getSize(); j += 1) {
|
||
connection = PMUI.getActiveCanvas().refreshArray.get(j);
|
||
connection.reconnectUser(delta, false);
|
||
connection.setSegmentMoveHandlers()
|
||
.checkAndCreateIntersectionsWithAll();
|
||
PMUI.getActiveCanvas()
|
||
.triggerConnectionStateChangeEvent(connection);
|
||
}
|
||
this.moveUndo = true;
|
||
};
|
||
|
||
/**
|
||
* Executes the command again after an undo action has been done
|
||
*/
|
||
CommandMove.prototype.redo = function () {
|
||
this.execute();
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.command.CommandMove', CommandMove);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.command.CommandPaste
|
||
* Class CommandPaste determines the actions executed when some shapes are pasted (redo) and the actions
|
||
* executed when they're removed (undo).
|
||
*
|
||
* Instances of this class are created in {@link PMUI.draw.Canvas#paste}.
|
||
* @extends PMUI.command.Command
|
||
*
|
||
* @constructor Creates an instance of the class CommandPaste
|
||
* @param {Object} receiver The object that will execute the command
|
||
* @param {Object} options Initialization options
|
||
* @cfg {Array} [stackCommandConnect=[]] Array of commands connect
|
||
* @cfg {Array} [stackCommandCreate=[]] Array of commands create
|
||
*/
|
||
var CommandPaste = function (receiver, options) {
|
||
|
||
CommandPaste.superclass.call(this, receiver);
|
||
|
||
/**
|
||
* A stack of commandsConnect (for connections)
|
||
* @property {Array}
|
||
*/
|
||
this.stackCommandConnect = [];
|
||
|
||
/**
|
||
* A stack of commandsCreate (for shapes)
|
||
* @property {Array}
|
||
*/
|
||
this.stackCommandCreate = [];
|
||
|
||
CommandPaste.prototype.initObject.call(this, receiver, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.command.Command', CommandPaste);
|
||
|
||
/**
|
||
* Type of command
|
||
* @property {String}
|
||
*/
|
||
CommandPaste.prototype.type = "CommandPaste";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance
|
||
* @param {Object} receiver The object that will execute the command
|
||
* @private
|
||
*/
|
||
CommandPaste.prototype.initObject = function (receiver, options) {
|
||
var i,
|
||
shape,
|
||
defaults = {
|
||
stackCommandConnect: [],
|
||
stackCommandCreate: []
|
||
};
|
||
|
||
$.extend(true, defaults, options);
|
||
|
||
this.stackCommandConnect = defaults.stackCommandConnect;
|
||
this.stackCommandCreate = defaults.stackCommandCreate;
|
||
|
||
};
|
||
|
||
/**
|
||
* Executes the command.
|
||
* The steps are:
|
||
*
|
||
* 1. Execute the redo operation for each command create
|
||
* 2. Execute the redo operation for each command connect
|
||
*
|
||
* @chainable
|
||
*/
|
||
CommandPaste.prototype.execute = function () {
|
||
var i,
|
||
command;
|
||
for (i = 0; i < this.stackCommandCreate.length; i += 1) {
|
||
command = this.stackCommandCreate[i];
|
||
command.redo();
|
||
}
|
||
for (i = 0; i < this.stackCommandConnect.length; i += 1) {
|
||
command = this.stackCommandConnect[i];
|
||
command.redo();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Inverse executes the command a.k.a. undo.
|
||
* The steps are:
|
||
*
|
||
* 1. Execute the undo operation for each command create
|
||
* 2. Execute the undo operation for each command connect
|
||
*
|
||
* @chainable
|
||
*/
|
||
CommandPaste.prototype.undo = function () {
|
||
var i,
|
||
command;
|
||
for (i = 0; i < this.stackCommandCreate.length; i += 1) {
|
||
command = this.stackCommandCreate[i];
|
||
command.undo();
|
||
}
|
||
for (i = 0; i < this.stackCommandConnect.length; i += 1) {
|
||
command = this.stackCommandConnect[i];
|
||
command.undo();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Executes the command a.k.a redo
|
||
* @chainable
|
||
*/
|
||
CommandPaste.prototype.redo = function () {
|
||
this.execute();
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.command.CommandPaste', CommandPaste);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.command.CommandReconnect
|
||
* Class CommandReconnect determines the actions executed when a connection is reconnected, e.g. when a connection
|
||
* source port or end port are dragged to another shape or another position in the same shape (redo)
|
||
* and the actions executed to revert the last drag to another shape or another position in the same shape (undo).
|
||
*
|
||
* Instances of this class are created in {@link PMUI.behavior.ConnectionDropBehavior#onDrop}.
|
||
* @extends PMUI.command.Command
|
||
*
|
||
* @constructor Creates an instance of the class CommandReconnect
|
||
* @param {Object} receiver The object that will execute the command
|
||
*/
|
||
var CommandReconnect = function (receiver) {
|
||
CommandReconnect.superclass.call(this, receiver);
|
||
|
||
/**
|
||
* Object that represents the state of the shape before changing
|
||
* its dimension
|
||
* @property {Object}
|
||
*/
|
||
this.before = {
|
||
x: this.receiver.getOldX(),
|
||
y: this.receiver.getOldY(),
|
||
parent: this.receiver.getOldParent()
|
||
};
|
||
|
||
/**
|
||
* Object that represents the state of the shape after changing
|
||
* its dimension
|
||
* @property {Object}
|
||
*/
|
||
this.after = {
|
||
x: this.receiver.getX(),
|
||
y: this.receiver.getY(),
|
||
parent: this.receiver.getParent()
|
||
};
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.command.Command', CommandReconnect);
|
||
|
||
/**
|
||
* Type of command.
|
||
* @property {String}
|
||
*/
|
||
CommandReconnect.prototype.type = "CommandReconnect";
|
||
|
||
/**
|
||
* Executes the command
|
||
* The steps are:
|
||
*
|
||
* 1. Hide the currentConnection of the canvas if there's one
|
||
* 2. If the new parent of the dragged port is different than the old parent
|
||
* - Remove the port from its old parent
|
||
* - Add the port to the new parent
|
||
* 3. If the new parent of the dragged port is equal to the old parent
|
||
* - Redefine its position in the shape
|
||
* 4. Reconnect the connection (using the new ports) and check for intersections
|
||
* 4. Trigger the port change event
|
||
*
|
||
* @chainable
|
||
*/
|
||
CommandReconnect.prototype.execute = function () {
|
||
|
||
var port = this.receiver,
|
||
parent = this.after.parent,
|
||
oldParent = this.before.parent;
|
||
|
||
// hide the connection if its visible
|
||
if (parent.canvas.currentConnection) {
|
||
parent.canvas.currentConnection.hidePortsAndHandlers();
|
||
parent.canvas.currentConnection = null;
|
||
}
|
||
|
||
if (parent.getID() !== oldParent.getID()) {
|
||
oldParent.removePort(port);
|
||
parent.addPort(port, this.after.x, this.after.y, true);
|
||
port.oldParent = oldParent;
|
||
} else {
|
||
parent.definePortPosition(port,
|
||
new PMUI.util.Point(this.after.x, this.after.y));
|
||
}
|
||
|
||
port.connection
|
||
.disconnect()
|
||
.connect()
|
||
.setSegmentMoveHandlers()
|
||
.checkAndCreateIntersectionsWithAll();
|
||
|
||
// custom trigger
|
||
this.receiver.canvas.triggerPortChangeEvent(port);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Inverse executes a command e.g. undo.
|
||
* The steps are:
|
||
*
|
||
* 1. Hide the currentConnection of the canvas if there's one
|
||
* 2. If the old parent of the port is different than the new parent
|
||
* - Remove the port from its new parent
|
||
* - Add the port to the old parent
|
||
* 3. If the old parent of the port is equal to the new parent
|
||
* - Redefine its position in the shape
|
||
* 4. Reconnect the connection (using the new ports) and check for intersections
|
||
* 4. Trigger the port change event
|
||
*
|
||
* @chainable
|
||
*/
|
||
CommandReconnect.prototype.undo = function () {
|
||
var port = this.receiver,
|
||
parent = this.after.parent,
|
||
oldParent = this.before.parent;
|
||
|
||
// hide the connection if its visible
|
||
if (parent.canvas.currentConnection) {
|
||
parent.canvas.currentConnection.hidePortsAndHandlers();
|
||
parent.canvas.currentConnection = null;
|
||
}
|
||
|
||
if (parent.getID() !== oldParent.getID()) {
|
||
parent.removePort(port);
|
||
oldParent.addPort(port, this.before.x, this.before.y, true);
|
||
port.canvas.regularShapes.insert(port);
|
||
port.oldParent = parent;
|
||
} else {
|
||
parent.definePortPosition(port,
|
||
new PMUI.util.Point(this.before.x, this.before.y));
|
||
}
|
||
|
||
port.connection
|
||
.disconnect()
|
||
.connect()
|
||
.setSegmentMoveHandlers()
|
||
.checkAndCreateIntersectionsWithAll();
|
||
|
||
// custom trigger
|
||
this.receiver.canvas.triggerPortChangeEvent(port);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Inverse executes a command e.g. undo
|
||
* @chainable
|
||
*/
|
||
CommandReconnect.prototype.redo = function () {
|
||
this.execute();
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.command.CommandReconnect', CommandReconnect);
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.command.CommandResize
|
||
* Class CommandResize determines the actions executed when some shapes are resized (redo) and the actions
|
||
* executed when they're resized back (undo).
|
||
*
|
||
* Instances of this class are created in {@link PMUI.behavior.RegularResizeBehavior#event-resizeEnd}.
|
||
* @extends PMUI.command.Command
|
||
*
|
||
* @constructor Creates an instance of the class CommandResize
|
||
* @param {Object} receiver The object that will execute the command
|
||
*/
|
||
var CommandResize = function (receiver) {
|
||
CommandResize.superclass.call(this, receiver);
|
||
|
||
/**
|
||
* Object that represents the state of the shape before changing
|
||
* its dimension
|
||
* @property {Object}
|
||
*/
|
||
this.before = {
|
||
x: this.receiver.getOldX(),
|
||
y: this.receiver.getOldY(),
|
||
width: this.receiver.getOldWidth(),
|
||
height: this.receiver.getOldHeight()
|
||
};
|
||
|
||
/**
|
||
* Object that represents the state of the shape after changing
|
||
* its dimension
|
||
* @property {Object}
|
||
*/
|
||
this.after = {
|
||
x: this.receiver.getX(),
|
||
y: this.receiver.getY(),
|
||
width: this.receiver.getWidth(),
|
||
height: this.receiver.getHeight()
|
||
};
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.command.Command', CommandResize);
|
||
|
||
/**
|
||
* Type of command of this object
|
||
* @property {String}
|
||
*/
|
||
CommandResize.prototype.type = "CommandResize";
|
||
|
||
/**
|
||
* Executes the command.
|
||
* The steps are:
|
||
*
|
||
* 1. Set the new position and dimension of the shape (using `this.after`)
|
||
* 2. Fix its connections on resize
|
||
* 3. Trigger the dimension change event
|
||
* 4. Trigger the position change event
|
||
*
|
||
* @chainable
|
||
*/
|
||
CommandResize.prototype.execute = function () {
|
||
var shape = this.receiver,
|
||
canvas = shape.getCanvas();
|
||
shape.setPosition(this.after.x, this.after.y)
|
||
.setDimension(this.after.width, this.after.height);
|
||
canvas.triggerDimensionChangeEvent(shape, this.before.width,
|
||
this.before.height, this.after.width, this.after.height);
|
||
if ((this.after.x !== this.before.x) || (this.after.y !== this.before.y)) {
|
||
canvas.triggerPositionChangeEvent(
|
||
[shape],
|
||
[
|
||
{
|
||
x: this.before.x,
|
||
y: this.before.y
|
||
}
|
||
],
|
||
[
|
||
{
|
||
x: this.after.x,
|
||
y: this.after.y
|
||
}
|
||
]
|
||
);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Inverse executes a command a.k.a undo.
|
||
* The steps are:
|
||
*
|
||
* 1. Set the new position and dimension of the shape (using `this.before`)
|
||
* 2. Fix its connections on resize
|
||
* 3. Trigger the dimension change event
|
||
* 4. Trigger the position change event
|
||
*
|
||
* @chainable
|
||
*/
|
||
CommandResize.prototype.undo = function () {
|
||
var shape = this.receiver,
|
||
canvas = shape.getCanvas();
|
||
shape.setPosition(this.before.x, this.before.y)
|
||
.setDimension(this.before.width, this.before.height);
|
||
shape.fixConnectionsOnResize(shape.resizing, true);
|
||
canvas.triggerDimensionChangeEvent(shape, this.after.width,
|
||
this.after.height, this.before.width, this.before.height);
|
||
if ((this.after.x !== this.before.x) || (this.after.y !== this.before.y)) {
|
||
canvas.triggerPositionChangeEvent(
|
||
[shape],
|
||
[
|
||
{
|
||
x: this.after.x,
|
||
y: this.after.y
|
||
}
|
||
],
|
||
[
|
||
{
|
||
x: this.before.x,
|
||
y: this.before.y
|
||
}
|
||
]
|
||
);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Executes the command a.k.a redo.
|
||
* @chainable
|
||
*/
|
||
CommandResize.prototype.redo = function () {
|
||
this.execute();
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.command.CommandResize', CommandResize);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.command.CommandSegmentMove
|
||
* Class CommandSegmentMove determines the actions executed when a segment is moved through its move handler (redo)
|
||
* and the actions executed when the segment is moved back (undo).
|
||
*
|
||
* Instances of this class are created in {@link PMUI.draw.SegmentMoveHandler#event-dragEnd}.
|
||
* @extends PMUI.command.Command
|
||
*
|
||
* @constructor Creates an instance of the class CommandSegmentMove
|
||
* @param {PMUI.draw.Connection} receiver The object that will execute the command
|
||
* @param {Object} options Initialization options
|
||
* @cfg {Array} [oldPoints=[]] Array of old points of the connection
|
||
* @cfg {Array} [newPoints=[]] Array of new points of the connection
|
||
*/
|
||
var CommandSegmentMove = function (receiver, options) {
|
||
CommandSegmentMove.superclass.call(this, receiver);
|
||
|
||
/**
|
||
* Array of points that represent the state of the connection before moving the segment move handler
|
||
* @property {Array}
|
||
*/
|
||
this.oldPoints = [];
|
||
|
||
/**
|
||
* Array of points that represent the state of the connection after moving the segment move handler
|
||
* @property {Array}
|
||
*/
|
||
this.newPoints = [];
|
||
|
||
CommandSegmentMove.prototype.initObject.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.command.Command', CommandSegmentMove);
|
||
|
||
/**
|
||
* Type of command of this object
|
||
* @property {String}
|
||
*/
|
||
CommandSegmentMove.prototype.type = "CommandResize";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance
|
||
* @param {Object} options The object that contains old points and new points
|
||
* @private
|
||
*/
|
||
CommandSegmentMove.prototype.initObject = function (options) {
|
||
var defaults = {
|
||
oldPoints: [],
|
||
newPoints: []
|
||
},
|
||
i,
|
||
point;
|
||
$.extend(true, defaults, options);
|
||
this.oldPoints = [];
|
||
for (i = 0; i < defaults.oldPoints.length; i += 1) {
|
||
point = defaults.oldPoints[i];
|
||
this.oldPoints.push(new PMUI.util.Point(point.x, point.y));
|
||
}
|
||
this.newPoints = [];
|
||
for (i = 0; i < defaults.newPoints.length; i += 1) {
|
||
point = defaults.newPoints[i];
|
||
this.newPoints.push(new PMUI.util.Point(point.x, point.y));
|
||
}
|
||
};
|
||
|
||
/**
|
||
* There's a common behavior between execute and inverseExecute in
|
||
* this command so merge both files and use a parameter to choose
|
||
* between execute and inverseExecute.
|
||
* The steps are:
|
||
*
|
||
* 1. Select the connection by triggering a click in its destination decorator
|
||
* 2. Hide the ports and handlers of the connection and reconnect the connection using points
|
||
* 3. Check and create the intersections and show the ports of the connection
|
||
* 4. Trigger the segment move event
|
||
*
|
||
* @private
|
||
* @chainable
|
||
*/
|
||
CommandSegmentMove.prototype.common = function (action) {
|
||
var connection = this.receiver;
|
||
// trigger targetSpriteDecorator onClick
|
||
$(connection.destDecorator.getHTML()).trigger('click');
|
||
|
||
connection.hidePortsAndHandlers();
|
||
connection.disconnect(true).connect({
|
||
algorithm: 'user',
|
||
points: this[action]
|
||
});
|
||
|
||
connection.setSegmentMoveHandlers();
|
||
|
||
// create intersections with all other connections
|
||
connection.checkAndCreateIntersectionsWithAll();
|
||
|
||
// show the ports and handlers again
|
||
connection.showPortsAndHandlers();
|
||
|
||
// trigger event
|
||
connection.canvas.triggerConnectionStateChangeEvent(connection);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Executes a command
|
||
* @chainable
|
||
*/
|
||
CommandSegmentMove.prototype.execute = function () {
|
||
this.common("newPoints");
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Inverse executes the command a.k.a. undo
|
||
* @chainable
|
||
*/
|
||
CommandSegmentMove.prototype.undo = function () {
|
||
this.common("oldPoints");
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Executes the command a.k.a. redo
|
||
* @chainable
|
||
*/
|
||
CommandSegmentMove.prototype.redo = function () {
|
||
this.execute();
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.command.CommandSegmentMove', CommandSegmentMove);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.command.CommandStack
|
||
* Command stack stores the commands executed to perform undos and redos, it consists of 2 stacks:
|
||
*
|
||
* - undoStack (represented as an array)
|
||
* - redoStack (represented as an array)
|
||
*
|
||
* Every time an undo or redo action is executed the stacks automatically get updated and the function passed
|
||
* during the instantiation is called.
|
||
*
|
||
* // e.g.
|
||
* // let's assume that commandCreateInstance is an instance of CommandCreate
|
||
* // let's assume that commandResizeInstance is an instance of CommandResize
|
||
*
|
||
* // first let's create the stacks (max size of the redo stack is 5)
|
||
* var commandStack = new PMUI.command.CommandStack(5);
|
||
*
|
||
* // commandStack.add() inserts the command to the undoStack (emptying the redo stack too)
|
||
* commandStack.add(commandCreateInstance);
|
||
* commandStack.add(commandResizeInstance);
|
||
* commandStack.add(commandResizeInstance);
|
||
* commandStack.add(commandResizeInstance);
|
||
* commandStack.add(commandResizeInstance);
|
||
*
|
||
* // at this point the redo stack is full (we defined a max size of 5), so the following add will remove the
|
||
* // last element of the stack (which is commandCreateInstance) and the undoStack will only consist of
|
||
* // command resize instances
|
||
* commandStack.add(commandResizeInstance);
|
||
*
|
||
* // whenever an undo operation is executed in the commandStack, the first command (which is the last command
|
||
* // in the undoStack) executes its undo operation and the command is removed from the undoStack and pushed to
|
||
* // the redoStack, graphically:
|
||
*
|
||
* // Let's define an stack graphically as '[['
|
||
* // if an element (e1) is pushed to the stack the stack becomes: [[e1
|
||
* // if an element (e2) is pushed to the stack the stack becomes: [[e1, e2
|
||
* // if an element (e3) is pushed to the stack the stack becomes: [[e1, e2, e3
|
||
* // if an element is removed from the stack the stack becomes: [[e1, e2
|
||
* // Note the direction of the stack, if it's defined as ']]'
|
||
* // the operations executed above turn the stack into:
|
||
* // e1]]; e2, e1]]; e3, e2, e1]]; e2, e1]]
|
||
*
|
||
* // Let's alias commandResizeInstance as cRI and commandCreateInstance cCI.
|
||
* // With the example defined above of commandResizeInstance, the following line does:
|
||
* // pre state:
|
||
* // undoStack = [[cRI_1, cRI_2, cRI_3, cRI_4, cRI_5
|
||
* // redoStack = ]]
|
||
* // post state:
|
||
* // undoStack = [[cRI_1, cRI_2, cRI_3, cRI_4
|
||
* // redoStack = cRI_5]]
|
||
* commandStack.undo();
|
||
*
|
||
* // executing undo again leads to:
|
||
* // pre state:
|
||
* // undoStack = [[cRI_1, cRI_2, cRI_3, cRI_4
|
||
* // redoStack = cRI_5]]
|
||
* // post state:
|
||
* // undoStack = [[cRI_1, cRI_2, cRI_3
|
||
* // redoStack = cRI_4, cRI_5]]
|
||
* commandStack.undo();
|
||
*
|
||
* // executing redo leads to:
|
||
* // pre state:
|
||
* // undoStack = [[cRI_1, cRI_2, cRI_3
|
||
* // redoStack = cRI_4, cRI_5]]
|
||
* // post state:
|
||
* // undoStack = [[cRI_1, cRI_2, cRI_3, cRI_4
|
||
* // redoStack = cRI_5]]
|
||
* commandStack.redo();
|
||
*
|
||
* // adding a new command to the stack empties the redo stack so:
|
||
* // pre state:
|
||
* // undoStack = [[cRI_1, cRI_2, cRI_3, cRI_4
|
||
* // redoStack = cRI_5]]
|
||
* // post state:
|
||
* // undoStack = [[cRI_1, cRI_2, cRI_3, cRI_4, cCI_1
|
||
* // redoStack = ]]
|
||
* commandStack.add(commandCreateInstance);
|
||
*
|
||
* @constructor Creates an instance of the class CommandStack
|
||
* @param {number} stackSize The maximum number of operations to be saved
|
||
* @param {Function} successCallback Function to be executed after add, undo or redo,
|
||
* `this` will refer to the object itself, not the constructor
|
||
*/
|
||
var CommandStack = function (stackSize, successCallback) {
|
||
var undoStack,
|
||
redoStack,
|
||
maxSize;
|
||
/**
|
||
* Stacks that contains commands (when pushed to the undoStack)
|
||
* @property {Array} [undoStack=[]]
|
||
* @private
|
||
*/
|
||
undoStack = [];
|
||
/**
|
||
* Stacks that contains commands (when pushed to the redoStack)
|
||
* @property {Array} [redoStack=[]]
|
||
* @private
|
||
*/
|
||
redoStack = [];
|
||
/**
|
||
* Maximum size of the undo stack
|
||
* @property {number} [maxSize=20]
|
||
* @private
|
||
*/
|
||
maxSize = stackSize || 20;
|
||
/**
|
||
* Empties the redo stack (when a new event is added to the undoStack)
|
||
* @private
|
||
*/
|
||
function emptyRedoStack() {
|
||
redoStack = [];
|
||
}
|
||
|
||
/**
|
||
* Handler to be called when a special action occurs
|
||
*/
|
||
function onSuccess() {
|
||
}
|
||
|
||
if (successCallback && {}.toString.call(successCallback) === '[object Function]') {
|
||
onSuccess = successCallback;
|
||
}
|
||
|
||
return {
|
||
/**
|
||
* Adds an action (command) to the undoStack
|
||
* @param {PMUI.command.Command} action
|
||
*/
|
||
add: function (action) {
|
||
emptyRedoStack();
|
||
undoStack.push(action);
|
||
if (undoStack.length > maxSize) {
|
||
// got to the max size of the stack
|
||
undoStack.shift();
|
||
}
|
||
onSuccess();
|
||
},
|
||
/**
|
||
* Adds an action (command) to the redoStack
|
||
* @param {PMUI.command.Command} action
|
||
*/
|
||
addToRedo: function (action) {
|
||
redoStack.push(action);
|
||
},
|
||
/**
|
||
* Undoes the last action executing undoStack's first item undo
|
||
* @return {boolean}
|
||
*/
|
||
undo: function () {
|
||
var action; // action to be inverse executed
|
||
if (undoStack.length === 0) {
|
||
//console.log("undo(): can't undo because there are no " +
|
||
// "actions to undo");
|
||
return false;
|
||
}
|
||
action = undoStack.pop();
|
||
// inverse execute the action
|
||
action.undo();
|
||
redoStack.unshift(action);
|
||
|
||
// execute on success handler
|
||
onSuccess();
|
||
return true;
|
||
},
|
||
/**
|
||
* Redoes the last action executing redoStack's first item redo
|
||
* @return {boolean}
|
||
*/
|
||
redo: function () {
|
||
var action; // action to be inverse executed
|
||
if (redoStack.length === 0) {
|
||
return false;
|
||
}
|
||
action = redoStack.shift();
|
||
// execute the action
|
||
action.redo();
|
||
undoStack.push(action);
|
||
|
||
// execute on success handler
|
||
onSuccess();
|
||
return true;
|
||
},
|
||
/**
|
||
* Clear both stacks
|
||
*/
|
||
clearStack: function () {
|
||
redoStack = [];
|
||
undoStack = [];
|
||
},
|
||
/**
|
||
* Debugging method to show the state of each stack
|
||
* @param {boolean} showDetailed
|
||
*/
|
||
debug: function (showDetailed) {
|
||
var i;
|
||
if (showDetailed) {
|
||
for (i = 0; i < undoStack.length; i += 1) {
|
||
console.log((i + 1) + ") " + undoStack[i].type);
|
||
}
|
||
}
|
||
if (showDetailed) {
|
||
for (i = 0; i < redoStack.length; i += 1) {
|
||
console.log((i + 1) + ") " + redoStack[i].type);
|
||
}
|
||
}
|
||
},
|
||
/**
|
||
* Gets the size of the redo stack
|
||
* @return {Number}
|
||
*/
|
||
getRedoSize: function () {
|
||
return redoStack.length;
|
||
},
|
||
/**
|
||
* Gets the size of the redo stack
|
||
* @return {Number}
|
||
*/
|
||
getUndoSize: function () {
|
||
return undoStack.length;
|
||
},
|
||
/**
|
||
* Sets the onSuccess handler of this object
|
||
* @param successCallback
|
||
* @chainable
|
||
*/
|
||
setHandler: function (successCallback) {
|
||
if (successCallback && {}.toString.call(successCallback) === '[object Function]') {
|
||
onSuccess = successCallback;
|
||
}
|
||
return this;
|
||
}
|
||
};
|
||
};
|
||
|
||
// extend the namespace
|
||
PMUI.extendNamespace('PMUI.command.CommandStack', CommandStack);
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.command.CommandSwitchContainer
|
||
* Class that encapsulates the action of switching containers
|
||
*
|
||
* //e.g.
|
||
* var command = new PMUI.command.CommandSwitchContainer(arrayOfShapes);
|
||
* @extends PMUI.command.Command
|
||
*
|
||
* @constructor
|
||
* Creates an instance of this command
|
||
* @param {Array} shapesAdded array of shapes that are going to switch container
|
||
*/
|
||
var CommandSwitchContainer = function (shapesAdded) {
|
||
CommandSwitchContainer.superclass.call(this, shapesAdded[0].shape);
|
||
/**
|
||
* Properties of the object before the command is executed
|
||
* @property {Object}
|
||
*/
|
||
this.before = null;
|
||
/**
|
||
* Properties of the object after the command is executed
|
||
* @property {Object}
|
||
*/
|
||
this.after = null;
|
||
/**
|
||
* Reference to all objects involved in this command
|
||
* @type {Array}
|
||
*/
|
||
this.relatedShapes = [];
|
||
CommandSwitchContainer.prototype.initObject.call(this, shapesAdded);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.command.Command', CommandSwitchContainer);
|
||
|
||
/**
|
||
* Type of the instances of this command
|
||
* @property {String}
|
||
*/
|
||
CommandSwitchContainer.prototype.type = "CommandSwitchContainer";
|
||
|
||
/**
|
||
* Initializer of the command
|
||
* @param {Array} shapesAdded array of shapes that are going to switch container
|
||
*/
|
||
CommandSwitchContainer.prototype.initObject = function (shapesAdded) {
|
||
var i,
|
||
shape,
|
||
beforeShapes = [],
|
||
afterShapes = [];
|
||
|
||
for (i = 0; i < shapesAdded.length; i += 1) {
|
||
shape = shapesAdded[i];
|
||
this.relatedShapes.push(shape.shape);
|
||
beforeShapes.push({
|
||
parent: shape.shape.parent,
|
||
x: shape.shape.getOldX() * shape.shape.canvas.getZoomFactor(),
|
||
y: shape.shape.getOldY() * shape.shape.canvas.getZoomFactor(),
|
||
topLeft: true
|
||
});
|
||
afterShapes.push({
|
||
parent: shape.container,
|
||
x: shape.x,
|
||
y: shape.y,
|
||
topLeft: shape.topLeft
|
||
});
|
||
}
|
||
|
||
this.before = {
|
||
shapes: beforeShapes
|
||
};
|
||
|
||
this.after = {
|
||
shapes: afterShapes
|
||
};
|
||
this.containerUndo = false;
|
||
};
|
||
|
||
/**
|
||
* The command execution implementation, updates the parents, and if necessary,
|
||
* updates the children positions and connections.
|
||
*/
|
||
CommandSwitchContainer.prototype.execute = function () {
|
||
var i,
|
||
j,
|
||
max,
|
||
connection,
|
||
shape,
|
||
delta;
|
||
|
||
for (i = 0; i < this.relatedShapes.length; i += 1) {
|
||
shape = this.relatedShapes[i];
|
||
delta = {
|
||
dx: this.before.shapes[i].x - this.after.shapes[i].x,
|
||
dy: this.before.shapes[i].y - this.after.shapes[i].y
|
||
};
|
||
this.before.shapes[i].parent.swapElementContainer(
|
||
shape,
|
||
this.after.shapes[i].parent,
|
||
this.after.shapes[i].x,
|
||
this.after.shapes[i].y,
|
||
this.after.shapes[i].topLeft
|
||
);
|
||
shape.refreshChildrenPositions(true, delta);
|
||
shape.refreshConnections(false, this.relatedShapes, delta);
|
||
}
|
||
this.canvas.triggerParentChangeEvent(this.relatedShapes,
|
||
this.before.shapes, this.after.shapes);
|
||
if (this.containerUndo) {
|
||
for (j = 0; j < PMUI.getActiveCanvas().refreshArray.getSize(); j += 1) {
|
||
connection = PMUI.getActiveCanvas().refreshArray.get(j);
|
||
connection.reconnectManhattah(false);
|
||
connection.setSegmentMoveHandlers()
|
||
.checkAndCreateIntersectionsWithAll();
|
||
PMUI.getActiveCanvas()
|
||
.triggerConnectionStateChangeEvent(connection);
|
||
}
|
||
this.containerUndo = false;
|
||
}
|
||
|
||
};
|
||
|
||
/**
|
||
* Returns to the state before this command was executed
|
||
*/
|
||
CommandSwitchContainer.prototype.undo = function () {
|
||
var i,
|
||
delta,
|
||
shape,
|
||
connection,
|
||
j,
|
||
max;
|
||
for (i = 0; i < this.relatedShapes.length; i += 1) {
|
||
shape = this.relatedShapes[i];
|
||
delta = {
|
||
dx: this.before.shapes[i].x - this.after.shapes[i].x,
|
||
dy: this.before.shapes[i].y - this.after.shapes[i].y
|
||
};
|
||
this.before.shapes[i].parent.swapElementContainer(
|
||
shape,
|
||
this.before.shapes[i].parent,
|
||
this.before.shapes[i].x,
|
||
this.before.shapes[i].y,
|
||
this.before.shapes[i].topLeft
|
||
);
|
||
shape.refreshChildrenPositions(true, delta);
|
||
shape.refreshConnections(false, this.relatedShapes, delta);
|
||
}
|
||
|
||
this.canvas.triggerParentChangeEvent(this.relatedShapes,
|
||
this.after.shapes, this.before.shapes);
|
||
|
||
|
||
for (j = 0; j < PMUI.getActiveCanvas().refreshArray.getSize(); j += 1) {
|
||
connection = PMUI.getActiveCanvas().refreshArray.get(j);
|
||
connection.reconnectManhattah(false);
|
||
connection.setSegmentMoveHandlers()
|
||
.checkAndCreateIntersectionsWithAll();
|
||
PMUI.getActiveCanvas()
|
||
.triggerConnectionStateChangeEvent(connection);
|
||
}
|
||
this.containerUndo = true;
|
||
|
||
};
|
||
|
||
|
||
/**
|
||
* Executes the command again after an undo action has been done
|
||
*/
|
||
CommandSwitchContainer.prototype.redo = function () {
|
||
this.execute();
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.command.CommandSwitchContainer', CommandSwitchContainer);
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Canvas
|
||
* Is the object where all the shapes and drawings will be placed on, in addition it handles zoom operations
|
||
* and also the triggering of events.
|
||
*
|
||
* Below are some unique characteristics of the instances of this class:
|
||
*
|
||
* - Each instance of this class has an instance of the following:
|
||
* - {@link PMUI.command.CommandStack Command stack}
|
||
* - {@link PMUI.draw.Snapper Two snappers} (one horizontal snapper and one vertical snapper).
|
||
* - {@link PMUI.draw.MultipleSelectionContainer} to select multiple shapes.
|
||
* - {@link PMUI.draw.Segment}. To create connections between shapes.
|
||
* - {@link PMUI.draw.Canvas#property-customShapes CustomShapes arrayList}. To save all the custom shapes
|
||
* created in this canvas.
|
||
* - {@link PMUI.draw.Canvas#property-connections Connections arrayList}. To save all the connections
|
||
* created in this canvas.
|
||
* - {@link PMUI.draw.Canvas#property-currentSelection Current selection arrayList}.
|
||
To save all the custom shapes
|
||
* that are select (by clicking, ctrl clicking them or selecting them using the
|
||
* multipleSelectionContainer instance).
|
||
* - {@link PMUI.draw.Canvas#property-currentConnection Current connection}. A pointer to the selected
|
||
* connection.
|
||
* - {@link PMUI.draw.Canvas#property-currentLabel Current label}. A pointer to the active label.
|
||
*
|
||
* Besides this class does the following:
|
||
*
|
||
* - Parses the JSON retrieved from the database (through {@link PMUI.draw.Canvas#parse})
|
||
* - Creates some custom events (defined in {@link PMUI.draw.Canvas#attachListeners})
|
||
* - Creates, stores and executes the commands (through its {@link PMUI.draw.Canvas#property-commandStack}) property
|
||
*
|
||
* Below is an example of instantiation of this class:
|
||
*
|
||
* // The canvas needs an object containing the reference to existing classes outside the library
|
||
* // e.g. let's define two classes
|
||
* var BpmnActivity = function (options) {
|
||
* ...
|
||
* };
|
||
* var BpmnEvent = function (options) {
|
||
* ...
|
||
* };
|
||
*
|
||
* // Next, the canvas needs a factory function to create custom shapes dragged from a toolbar
|
||
* // this function needs an ID to create the shape
|
||
* function toolbarFactory (id) {
|
||
* var customShape = null;
|
||
* switch(id) {
|
||
* case: 'BpmnActivity':
|
||
* customShape = new PMUI.draw.BpmnActivity({
|
||
* ....
|
||
* });
|
||
* break;
|
||
* case: 'BpmnEvent':
|
||
* customShape = new PMUI.draw.BpmnEvent({
|
||
* ....
|
||
* });
|
||
* break;
|
||
* }
|
||
* return customShape;
|
||
* }
|
||
*
|
||
* // finally an instance of this class can be defined
|
||
* var canvas = new PMUI.draw.Canvas({
|
||
* width: 4000,
|
||
* height: 4000,
|
||
* toolbarFactory: toolbarFactory,
|
||
* copyAndPasteReferences: {
|
||
* bpmnActivity: BpmnActivity,
|
||
* bpmnEvent: BpmnEvent
|
||
* }
|
||
* });
|
||
*
|
||
* @extends PMUI.draw.BehavioralElement
|
||
*
|
||
* @constructor
|
||
* Creates an instance of the class
|
||
* @param {Object} options configuration options of the canvas
|
||
* @cfg {number} [width=4000] Width of this canvas.
|
||
* @cfg {number} [height=4000] Height of this canvas.
|
||
* @cfg {Function} toolbarFactory Function that will handle object creation
|
||
* from a custom toolbar
|
||
* @cfg {Object} [copyAndPasteReferences={}] References to the constructors of the classes
|
||
* (so that a shape is easily created from the canvas)
|
||
* @cfg {boolean} [readOnly=false] Property that determines the permission a
|
||
* user has over the canvas
|
||
*/
|
||
var Canvas = function (options) {
|
||
Canvas.superclass.call(this, options);
|
||
/**
|
||
* Variable that points to the HTML in the DOM of this object.
|
||
* @property {HTMLElement} [html=null]
|
||
*/
|
||
this.html = null;
|
||
/**
|
||
* A list of all the custom shapes in the canvas.
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.customShapes = null;
|
||
/**
|
||
* A list of all the regular shapes in the canvas.
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.regularShapes = null;
|
||
/**
|
||
* A list of all the connections in the canvas.
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.connections = null;
|
||
/**
|
||
* A list of all the shapes that are currently selected.
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.currentSelection = null;
|
||
/**
|
||
* A list of all the connections that will not be repainted (using the ManhattanRouter algorithm),
|
||
* but will be moved only.
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.sharedConnections = null;
|
||
/**
|
||
* Left Scroll coordinate of the canvas
|
||
* @property {number} [leftScroll=0]
|
||
*/
|
||
this.leftScroll = 0;
|
||
/**
|
||
* Top scroll coordinate of the canvas
|
||
* @property {number} [topScroll=0]
|
||
*/
|
||
this.topScroll = 0;
|
||
/**
|
||
* Reference to the current selected connection in the canvas
|
||
* @property {PMUI.draw.Connection}
|
||
*/
|
||
this.currentConnection = null;
|
||
/**
|
||
* Pointer to the last connection selected in the canvas
|
||
* (this variable is set from the commandDelete)
|
||
* @property {PMUI.draw.Connection}
|
||
*/
|
||
this.oldCurrentConnection = null;
|
||
/**
|
||
* Instance of the class {@link PMUI.draw.Segment} used to make connections in the canvas.
|
||
* @property {PMUI.draw.Segment}
|
||
*/
|
||
this.connectionSegment = null;
|
||
/**
|
||
* Instance of the class {@link PMUI.draw.MultipleSelectionContainer} created to do multiple selection
|
||
* @property {PMUI.draw.MultipleSelectionContainer}
|
||
*/
|
||
this.multipleSelectionHelper = null;
|
||
/**
|
||
* Instance of the class {@link PMUI.draw.Snapper} which represents the horizontal line used for snapping
|
||
* @property {PMUI.draw.Snapper}
|
||
*/
|
||
this.horizontalSnapper = null;
|
||
/**
|
||
* Instance of the class {@link PMUI.draw.Snapper} which represents the vertical line used for snapping
|
||
* @property {PMUI.draw.Snapper}
|
||
*/
|
||
this.verticalSnapper = null;
|
||
/**
|
||
* Current zoom Factor of the diagram
|
||
* @property {number} [zoomFactor=1]
|
||
*/
|
||
this.zoomFactor = 1;
|
||
/**
|
||
* Index for the zoom properties for shapes corresponding to the current
|
||
* zoom factor
|
||
* @property {number} [zoomPropertiesIndex=2]
|
||
*/
|
||
this.zoomPropertiesIndex = 2;
|
||
/**
|
||
* zOrder of the HTML Representation
|
||
* @property {number} [zOrder=0]
|
||
*/
|
||
this.zOrder = 0;
|
||
/**
|
||
* Boolean set true if the {@link PMUI.draw.Canvas#event-mousedown} event of the canvas is fired,
|
||
* it's set to false in the {@link PMUI.draw.Canvas#event-mouseup} event.
|
||
* @property {boolean} [isMouseDown=false]
|
||
*/
|
||
this.isMouseDown = false;
|
||
/**
|
||
* Current selected shape
|
||
* @property {PMUI.draw.Shape}
|
||
*/
|
||
this.currentShape = null;
|
||
/**
|
||
* True if the {@link PMUI.draw.Canvas#event-mousedown} event of the canvas is triggered and
|
||
* the {@link PMUI.draw.Canvas#event-mousemove} event is triggered, it's set to false in mouseUp event.
|
||
* @property {boolean} [isMouseDownAndMove=false]
|
||
*/
|
||
this.isMouseDownAndMove = false;
|
||
/**
|
||
* Denotes if there's been a multiple drop prior to a drag end.
|
||
* @property {boolean} [multipleDrop=false]
|
||
*/
|
||
this.multipleDrop = false;
|
||
/**
|
||
* Denotes if a segment move handler is being dragged. in order not to
|
||
* trigger events in the canvas [draggingASegmentHandler=false]
|
||
* @property {boolean}
|
||
*/
|
||
this.draggingASegmentHandler = false;
|
||
/**
|
||
* Elements that was added, changed or deleted in the canvas.
|
||
* @property {Object}
|
||
*/
|
||
this.updatedElement = null;
|
||
/**
|
||
* Determines if the canvas has been right clicked at {@link PMUI.draw.Canvas#event-mousedown}
|
||
* @property {boolean} [rightClick=false]
|
||
*/
|
||
this.rightClick = false;
|
||
/**
|
||
* Each time a shape is moved using the cursors, the following code is executed:
|
||
*
|
||
* // for each 'connection' that is not in this.sharedConnection and that it's being
|
||
* // recalculated (using ManhattanRouter algorithm)
|
||
* connection.disconnect().connect()
|
||
* .setSegmentMoveHandlers()
|
||
* .checkAndCreateIntersectionsWithAll();
|
||
*
|
||
* So to avoid these operations for each key press of the cursors, let's create a timeout,
|
||
* so that only after that timeout has expired the code above will run.
|
||
* This variable is a reference to that timeout.
|
||
* @property {Object}
|
||
*/
|
||
this.intersectionTimeout = null;
|
||
/**
|
||
* Point to the current label that is being edited
|
||
* @property {Object}
|
||
*/
|
||
this.currentLabel = null;
|
||
/**
|
||
* Instance of the class {@link PMUI.command.CommandStack} to be used in this canvas
|
||
* @property {PMUI.command.CommandStack}
|
||
*/
|
||
this.commandStack = null;
|
||
/**
|
||
* Array which contains a list of all the objects that were duplicated
|
||
* (during copy)
|
||
* @property {Array} [shapesToCopy=[]]
|
||
*/
|
||
this.shapesToCopy = [];
|
||
/**
|
||
* Array which contains a list of all the connections that were duplicated
|
||
* (during copy)
|
||
* @property {Array} [connectionsToCopy=[]]
|
||
*/
|
||
this.connectionsToCopy = [];
|
||
/**
|
||
* Property that determines the permissions a user has over the canvas
|
||
* @property {boolean} [readOnly=false]
|
||
*/
|
||
this.readOnly = false;
|
||
/**
|
||
* Layer that prevents the canvas to be altered
|
||
* @property {PMUI.draw.ReadOnlyLayer}
|
||
*/
|
||
this.readOnlyLayer = null;
|
||
/**
|
||
* Object which holds references to the constructors of the classes
|
||
* (so that a shape is easily created from the canvas)
|
||
* @property {Object} [copyAndPasteReferences={}]
|
||
*/
|
||
this.copyAndPasteReferences = {};
|
||
/**
|
||
* Previous zoom properties index
|
||
* @property {number} [prevZoom=1]
|
||
*/
|
||
this.prevZoom = 1;
|
||
/**
|
||
* Initializer for labels, so that jQuery can measure the width of a message
|
||
* in the first time its created
|
||
* @type {HTMLElement}
|
||
*/
|
||
this.dummyLabelInitializer = null;
|
||
this.isDragging = false;
|
||
this.isResizing = false;
|
||
this.refreshArray = new PMUI.util.ArrayList();
|
||
this.connToRefresh = new PMUI.util.ArrayList();
|
||
Canvas.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.BehavioralElement', Canvas);
|
||
|
||
/**
|
||
* Type of the instances
|
||
* @property {String}
|
||
*/
|
||
Canvas.prototype.type = "Canvas";
|
||
/**
|
||
* Family of the instances, this attribute must not be overridden
|
||
* @property {String}
|
||
* @readonly
|
||
*/
|
||
Canvas.prototype.family = "Canvas";
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance.
|
||
* The following properties are instantiated in this method:
|
||
*
|
||
* this.children = new PMUI.util.ArrayList();
|
||
* this.customShapes = new PMUI.util.ArrayList();
|
||
* this.regularShapes = new PMUI.util.ArrayList();
|
||
* this.connections = new PMUI.util.ArrayList();
|
||
* this.currentSelection = new PMUI.util.ArrayList();
|
||
* this.sharedConnections = new PMUI.util.ArrayList();
|
||
* this.commandStack = new PMUI.command.CommandStack(20);
|
||
* this.multipleSelectionHelper = new PMUI.draw.MultipleSelectionContainer(this);
|
||
* this.horizontalSnapper = new PMUI.draw.Snapper({orientation: 'horizontal', canvas: this});
|
||
* this.verticalSnapper = new PMUI.draw.Snapper({orientation: 'vertical', canvas: this});
|
||
*
|
||
* @param {Object} options The object that contains the config
|
||
* @private
|
||
*/
|
||
Canvas.prototype.init = function (options) {
|
||
var canvasPosition,
|
||
defaults;
|
||
defaults = {
|
||
left: 0,
|
||
top: 0,
|
||
width: 4000,
|
||
height: 4000,
|
||
copyAndPasteReferences: (options && options.copyAndPasteReferences) || {},
|
||
readOnly: false
|
||
};
|
||
jQuery.extend(true, defaults, options);
|
||
if (options) {
|
||
this.children = new PMUI.util.ArrayList();
|
||
this.customShapes = new PMUI.util.ArrayList();
|
||
this.regularShapes = new PMUI.util.ArrayList();
|
||
this.connections = new PMUI.util.ArrayList();
|
||
this.currentSelection = new PMUI.util.ArrayList();
|
||
this.sharedConnections = new PMUI.util.ArrayList();
|
||
this.commandStack = new PMUI.command.CommandStack(20);
|
||
this.multipleSelectionHelper = new PMUI.draw.MultipleSelectionContainer({
|
||
canvas: this
|
||
});
|
||
this.copyAndPaste = false;
|
||
this.copyAndPasteReferences = defaults.copyAndPasteReferences;
|
||
this.setShapeFactory(defaults.shapeFactory);
|
||
this.setPosition(defaults.left, defaults.top)
|
||
.setDimension(defaults.width, defaults.height)
|
||
.setCanvas(this)
|
||
.setReadOnly(defaults.readOnly);
|
||
// create snappers
|
||
this.horizontalSnapper = new PMUI.draw.Snapper({
|
||
orientation: 'horizontal',
|
||
canvas: this
|
||
});
|
||
this.verticalSnapper = new PMUI.draw.Snapper({
|
||
orientation: 'vertical',
|
||
canvas: this
|
||
});
|
||
|
||
if (defaults.absoluteX) {
|
||
this.absoluteX = defaults.absoluteX;
|
||
}
|
||
if (defaults.absoluteY) {
|
||
this.absoluteY = defaults.absoluteY;
|
||
}
|
||
if (defaults.readOnly) {
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Overwrite createHTML method
|
||
* @return {HTMLElement}
|
||
*/
|
||
Canvas.prototype.createHTML = function () {
|
||
Canvas.superclass.prototype.createHTML.call(this);
|
||
this.addElement(this.multipleSelectionHelper, 0, 0, true);
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Sets the read and write permissions of the canvas.
|
||
* @param {boolean} readOnly Determines if the canvas will be set to read only
|
||
* or if it will be editable
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.setReadOnly = function (readOnly) {
|
||
if (readOnly) {
|
||
this.readOnly = readOnly;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the canvas to readOnly mode by creating a ReadOnlyLayer instance and appending its html to
|
||
* this html
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.setToReadOnly = function () {
|
||
var readOnlyLayer = this.readOnlyLayer;
|
||
if (readOnlyLayer && readOnlyLayer.html) {
|
||
this.html.appendChild(this.readOnlyLayer.html);
|
||
} else {
|
||
this.readOnlyLayer = new PMUI.draw.ReadOnlyLayer({
|
||
width: this.width,
|
||
height: this.height
|
||
});
|
||
this.html.appendChild(this.readOnlyLayer.html);
|
||
}
|
||
this.readOnly = true;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the canvas to read and write mode.
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.unsetReadOnly = function () {
|
||
var readOnlyLayer = this.readOnlyLayer;
|
||
this.html.removeChild(readOnlyLayer.getHTML());
|
||
this.readOnly = false;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the position of the canvas.
|
||
* @param {number} x x coordinate relative to where the canvas is contained
|
||
* @param {number} y y coordinate relative to where the canvas is contained
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.setPosition = function (x, y) {
|
||
this.setX(x);
|
||
this.setY(y);
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the x coordinate of the canvas, its zoomX and absoluteX to an equal value.
|
||
* @param {number} newX new x coordinate to be applied in the canvas
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.setX = function (newX) {
|
||
this.x = this.zoomX = newX;
|
||
this.absoluteX = 0;
|
||
return this;
|
||
};
|
||
/**
|
||
* Set the y coordinate of the canvas, its zoomY and absoluteY to an equal value
|
||
* @param {number} newY new y coordinate to be applied in the canvas
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.setY = function (newY) {
|
||
this.y = this.zoomY = newY;
|
||
this.absoluteY = 0;
|
||
return this;
|
||
};
|
||
/**
|
||
* Retrieves the div element that has this canvas id
|
||
* @return {HTMLElement}
|
||
*/
|
||
Canvas.prototype.createHTMLDiv = function () {
|
||
return document.getElementById(this.id);
|
||
};
|
||
/**
|
||
* Default shape factory for creating shapes.
|
||
* @param {String} id
|
||
* @return {PMUI.draw.CustomShape}
|
||
* @template
|
||
*/
|
||
Canvas.prototype.shapeFactory = function (id) {
|
||
var customShape = null;
|
||
return customShape;
|
||
};
|
||
/**
|
||
* Identifies the family of the shape (which might be *"CustomShape"* or *"RegularShape"*)
|
||
* and adds `shape` to either `this.customShapes` or `this.regularShapes`.
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.addToList = function (shape) {
|
||
switch (shape.family) {
|
||
case "CustomShape":
|
||
if (!this.customShapes.contains(shape)) {
|
||
this.customShapes.insert(shape);
|
||
}
|
||
break;
|
||
case "RegularShape":
|
||
if (!this.regularShapes.contains(shape)) {
|
||
this.regularShapes.insert(shape);
|
||
}
|
||
break;
|
||
default:
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Hides `this.currentConnection` if there is one.
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.hideCurrentConnection = function () {
|
||
// hide the current connection if there was one
|
||
if (this.currentConnection) {
|
||
this.currentConnection.hidePortsAndHandlers();
|
||
this.currentConnection = null;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Applies a zoom scale to the canvas and all its elements
|
||
* @param {number} scale numbered from 1 to n
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.applyZoom = function (scale) {
|
||
// TODO Implement Zoom Constants in utils
|
||
var i,
|
||
shape,
|
||
max,
|
||
conn;
|
||
|
||
if (scale > 0) {
|
||
scale -= 1;
|
||
this.prevZoom = this.zoomPropertiesIndex;
|
||
this.zoomPropertiesIndex = scale;
|
||
this.zoomFactor = (scale * 25 + 50) / 100;
|
||
}
|
||
for (i = 0; i < this.customShapes.getSize(); i += 1) {
|
||
shape = this.customShapes.get(i);
|
||
shape.applyZoom();
|
||
shape.paint();
|
||
}
|
||
//connection zoom
|
||
this.canvas.refreshArray.clear();
|
||
for (i = 0, max = this.connections.getSize(); i < max; i += 1) {
|
||
conn = this.connections.get(i);
|
||
conn.applyZoom();
|
||
conn.savePoints();
|
||
}
|
||
for (i = 0; i < this.regularShapes.getSize(); i += 1) {
|
||
shape = this.regularShapes.get(i);
|
||
shape.applyZoom();
|
||
shape.paint();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds a connection to the canvas, appending its html to the DOM and inserting
|
||
* it in the list of connections
|
||
* @param {PMUI.draw.Connection} conn
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.addConnection = function (conn) {
|
||
this.html.appendChild(conn.getHTML());
|
||
this.connections.insert(conn);
|
||
this.updatedElement = conn;
|
||
return this;
|
||
};
|
||
/**
|
||
* Remove all selected elements, it destroy the shapes and all references to them.
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.removeElements = function () {
|
||
// destroy the shapes (also destroy all the references to them)
|
||
var shape,
|
||
command;
|
||
command = new PMUI.command.CommandDelete(this);
|
||
this.commandStack.add(command);
|
||
command.execute();
|
||
return this;
|
||
};
|
||
/**
|
||
* Moves all the connections of the children of this shape (shape was moved using the cursors but the children
|
||
* connections don't know that so move those connections), this method is called from #moveElements.
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.moveAllChildConnections = function (shape) {
|
||
var i,
|
||
child,
|
||
j,
|
||
port;
|
||
if (shape.child !== null) {
|
||
for (i = 0; i < shape.children.getSize(); i += 1) {
|
||
child = shape.children.get(i);
|
||
child.setPosition(child.x, child.y);
|
||
for (j = 0; j < child.getPorts().getSize(); j += 1) {
|
||
port = child.getPorts().get(j);
|
||
port.setPosition(port.x, port.y);
|
||
port.connection.disconnect();
|
||
port.connection.connect();
|
||
port.connection.savePoints();
|
||
}
|
||
this.moveAllChildConnections(child);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Move all selected elements in one direction, used mainly for keyboard events
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
* @param {string} direction The direction to move the shapes to
|
||
* @param {Function} [hook] Hook used to determine which shapes can be moved with the keyboard,
|
||
* the function must receive a shape as its parameter and return true if the shape can be moved, false
|
||
* otherwise (if this function is not defined then it's assumed that all shapes are valid
|
||
* to be moved).
|
||
* // e.g.
|
||
* hook = function(shape) {
|
||
* return shape.isValidToMove();
|
||
* }
|
||
*
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.moveElements = function (canvas, direction, hook) {
|
||
var i, j,
|
||
shape,
|
||
hfactor = 0,
|
||
vfactor = 0,
|
||
port,
|
||
currentSelection = [],
|
||
canMove = true,
|
||
selection;
|
||
switch (direction) {
|
||
case 'LEFT':
|
||
hfactor = -1;
|
||
break;
|
||
case 'RIGHT':
|
||
hfactor = 1;
|
||
break;
|
||
case 'TOP':
|
||
vfactor = -1;
|
||
break;
|
||
case 'BOTTOM':
|
||
vfactor = 1;
|
||
break;
|
||
}
|
||
selection = canvas.getCurrentSelection();
|
||
if (selection.getSize() > 0) {
|
||
selection.sort(function (shape1, shape2) {
|
||
return shape1.y > shape2.y;
|
||
});
|
||
if (selection.get(0).y - 4 + vfactor < 0) {
|
||
canMove = false;
|
||
}
|
||
|
||
selection.sort(function (shape1, shape2) {
|
||
return shape1.x > shape2.x;
|
||
});
|
||
if (selection.get(0).x - 3 + hfactor < 0) {
|
||
canMove = false;
|
||
}
|
||
|
||
for (i = 0; i < selection.getSize(); i += 1) {
|
||
shape = selection.get(i);
|
||
currentSelection.push(shape);
|
||
if (hook && typeof hook === "function" && !hook(shape)) {
|
||
canMove = false;
|
||
}
|
||
if (canMove) {
|
||
shape.oldX = shape.x;
|
||
shape.oldY = shape.y;
|
||
shape.oldAbsoluteX = shape.absoluteX;
|
||
shape.oldAbsoluteY = shape.absoluteY;
|
||
|
||
shape.setPosition(shape.getX() + hfactor, shape.getY() + vfactor);
|
||
shape.changePosition(shape.oldX, shape.oldY, shape.oldAbsoluteX,
|
||
shape.oldAbsoluteY);
|
||
for (j = 0; j < shape.ports.getSize(); j += 1) {
|
||
// for each port update its absolute position and repaint its
|
||
port = shape.ports.get(j);
|
||
port.setPosition(port.x, port.y);
|
||
port.connection.disconnect().connect();
|
||
port.connection.savePoints();
|
||
}
|
||
this.moveAllChildConnections(shape);
|
||
}
|
||
}
|
||
clearTimeout(this.intersectionTimeout);
|
||
this.intersectionTimeout = window.setTimeout(function (currentSelection) {
|
||
var stack = [],
|
||
selection = currentSelection || [];
|
||
for (i = 0; i < selection.length; i += 1) {
|
||
shape = selection[i];
|
||
stack.push(shape);
|
||
}
|
||
while (stack.length > 0) {
|
||
shape = stack.pop();
|
||
// add the children to the stack
|
||
for (i = 0; i < shape.getChildren().getSize(); i += 1) {
|
||
stack.push(shape.getChildren().get(i));
|
||
}
|
||
for (j = 0; j < shape.ports.getSize(); j += 1) {
|
||
// for each port update its absolute position and repaint its
|
||
port = shape.ports.get(j);
|
||
port.connection.disconnect().connect();
|
||
port.connection.setSegmentMoveHandlers();
|
||
port.connection.checkAndCreateIntersectionsWithAll();
|
||
}
|
||
}
|
||
}, 1000, currentSelection);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes `shape` from the its corresponding list in the canvas (the shape has a reference either in
|
||
* `this.customShapes` or `this.regularShapes`).
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.removeFromList = function (shape) {
|
||
// remove from the current selection
|
||
this.currentSelection.remove(shape);
|
||
if (shape.family === "CustomShape") {
|
||
this.customShapes.remove(shape);
|
||
} else if (shape.family === "RegularShape") {
|
||
this.regularShapes.remove(shape);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Fixes the data of the snappers recreating the arrays and sorting them,
|
||
* this method is called from {@link PMUI.behavior.RegularDragBehavior#onDragStart} (it might
|
||
* be an overrided method `onDragStart` if the instance of {@link PMUI.behavior.RegularDragBehavior} was changed).
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.fixSnapData = function () {
|
||
this.horizontalSnapper.createSnapData();
|
||
this.verticalSnapper.createSnapData();
|
||
this.horizontalSnapper.sortData();
|
||
this.verticalSnapper.sortData();
|
||
return this;
|
||
};
|
||
/**
|
||
* Shows or hides the snappers according to this criteria:
|
||
*
|
||
* - To show the vertical snapper
|
||
* - `shape.absoluteX` must equal a value in the data of `this.verticalSnapper`
|
||
* - `shape.absoluteX + shape.width` must equal a value in the data of `this.verticalSnapper`
|
||
*
|
||
* - To show the horizontal snapper
|
||
* - `shape.absoluteY` must equal a value in the data of `this.horizontalSnapper`
|
||
* - `shape.absoluteY + shape.height` must equal a value in the data of `this.horizontalSnapper`
|
||
*
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.showOrHideSnappers = function (shape) {
|
||
var hSnapper = this.horizontalSnapper,
|
||
vSnapper = this.verticalSnapper,
|
||
x = shape.getAbsoluteX(),
|
||
y = shape.getAbsoluteY(),
|
||
width = shape.getZoomWidth(),
|
||
height = shape.getZoomHeight();
|
||
if (hSnapper.binarySearch(y)) {
|
||
hSnapper.setPosition(
|
||
this.getLeftScroll() / this.zoomFactor,
|
||
y / this.zoomFactor
|
||
);
|
||
hSnapper.show();
|
||
} else if (hSnapper.binarySearch(y + height)) {
|
||
hSnapper.setPosition(
|
||
this.getLeftScroll() / this.zoomFactor,
|
||
(y + height) / this.zoomFactor
|
||
);
|
||
hSnapper.show();
|
||
} else {
|
||
hSnapper.hide();
|
||
}
|
||
if (vSnapper.binarySearch(x)) {
|
||
vSnapper.setPosition(
|
||
x / this.zoomFactor - this.absoluteX,
|
||
this.getTopScroll() / this.zoomFactor
|
||
);
|
||
vSnapper.show();
|
||
} else if (vSnapper.binarySearch(x + width)) {
|
||
vSnapper.setPosition(
|
||
(x + width) / this.zoomFactor,
|
||
this.getTopScroll() / this.zoomFactor
|
||
);
|
||
vSnapper.show();
|
||
} else {
|
||
vSnapper.hide();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Empties `this.currentSelection` arrayList, thus hiding the resize handlers
|
||
* of each shape that was in it, it also clears `this.sharedConnections` array
|
||
* (there's a direct relationship between them).
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.emptyCurrentSelection = function () {
|
||
var i,
|
||
shape;
|
||
while (this.currentSelection.getSize() > 0) {
|
||
shape = this.currentSelection.get(0);
|
||
this.removeFromSelection(shape);
|
||
}
|
||
// also clear the sharedConnections
|
||
this.sharedConnections.clear();
|
||
return this;
|
||
};
|
||
/**
|
||
* Determines if it's possible to select `newShape` using `referenceShape` as a reference (`newShape` is a valid
|
||
* shape to be added to the selection if it has the same parent as `referenceShape`).
|
||
* @param {PMUI.draw.Shape} referenceShape shape which parent will be taken as reference
|
||
* @param {PMUI.draw.Shape} newShape new selected shape
|
||
* @return {boolean}
|
||
*/
|
||
Canvas.prototype.isValidSelection = function (referenceShape, newShape) {
|
||
if (referenceShape.parent === null) {
|
||
return newShape.parent === null;
|
||
}
|
||
if (newShape.parent === null) {
|
||
return false;
|
||
}
|
||
return newShape.parent.id === referenceShape.parent.id;
|
||
};
|
||
/**
|
||
* Adds `shape` to `this.currentSelection` if it meets one of the following rules:
|
||
*
|
||
* - If `this.currentSelection` is empty then add it to the arrayList
|
||
* - If `this.currentSelection` is not empty then check if this candidate shape
|
||
* has the same parent as any element in `this.currentSelection`, if so then add it to
|
||
* the arrayList.
|
||
*
|
||
* This method also shows the resize handlers of the shape and adds its connections
|
||
* to `this.sharedConnections` if possible.
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.addToSelection = function (shape) {
|
||
var currentSelection = this.currentSelection,
|
||
firstSelected,
|
||
valid,
|
||
isEmpty = currentSelection.isEmpty();
|
||
if (!isEmpty) {
|
||
firstSelected = currentSelection.get(0);
|
||
valid = this.isValidSelection(firstSelected, shape);
|
||
} else {
|
||
valid = true;
|
||
}
|
||
if (!currentSelection.contains(shape) && valid) {
|
||
// increase this shape zIndex
|
||
shape.increaseZIndex();
|
||
currentSelection.insert(shape);
|
||
// add the connections from this shape that are connected
|
||
// to another shape in the currentSelection to the
|
||
// canvas sharedConnections array
|
||
// NOTE: the shape is passed as an argument but its
|
||
// connections are stored
|
||
if (shape.family === "CustomShape") {
|
||
this.addToSharedConnections(shape);
|
||
}
|
||
shape.selected = true;
|
||
shape.showOrHideResizeHandlers(true);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes `shape` from `this.currentSelection` (also hiding its resize handlers).
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.removeFromSelection = function (shape) {
|
||
shape.decreaseZIndex();
|
||
this.removeFromSharedConnections(shape);
|
||
this.currentSelection.remove(shape);
|
||
shape.selected = false;
|
||
shape.showOrHideResizeHandlers(false);
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes all the shared connections between `customShape` and every shape
|
||
* found in `this.currentSelection`, also the connections inside `customShape` are removed from
|
||
* `this.sharedConnections` array.
|
||
* @param {PMUI.draw.CustomShape} customShape
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.removeFromSharedConnections = function (customShape) {
|
||
var i,
|
||
child,
|
||
connection,
|
||
sharedConnections = this.sharedConnections;
|
||
for (i = 0; i < customShape.getChildren().getSize(); i += 1) {
|
||
child = customShape.getChildren().get(i);
|
||
this.removeFromSharedConnections(child);
|
||
}
|
||
if (customShape.ports) {
|
||
for (i = 0; i < customShape.ports.getSize(); i += 1) {
|
||
connection = customShape.ports.get(i).connection;
|
||
if (sharedConnections.find('id', connection.getID())) {
|
||
this.sharedConnections.remove(connection);
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Checks if an ancestor of `shape` is in `this.currentSelection`.
|
||
* @return {boolean}
|
||
*/
|
||
Canvas.prototype.findAncestorInCurrentSelection = function (shape) {
|
||
if (this.currentSelection.find('id', shape.getID())) {
|
||
return true;
|
||
}
|
||
if (!shape.parent) {
|
||
return false;
|
||
}
|
||
return this.findAncestorInCurrentSelection(shape.parent);
|
||
};
|
||
/**
|
||
* Adds all the connections between `customShape` and another shape in the
|
||
* currentSelection to the `sharedConnections` arrayList, also the connections inside
|
||
* `customShape` are added to `this.sharedConnections` array.
|
||
* @param {PMUI.draw.CustomShape} customShape
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.addToSharedConnections = function (customShape) {
|
||
var i,
|
||
child,
|
||
connection,
|
||
sourceShape,
|
||
destShape,
|
||
sharedConnections = this.sharedConnections;
|
||
for (i = 0; i < customShape.getChildren().getSize(); i += 1) {
|
||
child = customShape.getChildren().get(i);
|
||
this.addToSharedConnections(child);
|
||
}
|
||
if (customShape.ports) {
|
||
for (i = 0; i < customShape.ports.getSize(); i += 1) {
|
||
connection = customShape.ports.get(i).connection;
|
||
sourceShape = connection.srcPort.parent;
|
||
destShape = connection.destPort.parent;
|
||
if (this.findAncestorInCurrentSelection(sourceShape) &&
|
||
this.findAncestorInCurrentSelection(destShape) && !sharedConnections.find('id', connection.getID())) {
|
||
sharedConnections.insert(connection);
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes a connection from `this.connections`.
|
||
* @param {PMUI.draw.Connection} conn
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.removeConnection = function (conn) {
|
||
//this.currentSelection.remove(conn);
|
||
this.connections.remove(conn);
|
||
return this;
|
||
};
|
||
/**
|
||
* Attaches event listeners to this canvas, it also creates some custom triggers
|
||
* used to save the data (to send it to the database later).
|
||
*
|
||
* The events attached to this canvas are:
|
||
*
|
||
* - {@link PMUI.draw.Canvas#event-mousedown Mouse down event}
|
||
* - {@link PMUI.draw.Canvas#event-mousemove Mouse move event}
|
||
* - {@link PMUI.draw.Canvas#event-mouseup Mouse up event}
|
||
* - {@link PMUI.draw.Canvas#event-click Click event}
|
||
* - {@link PMUI.draw.Canvas#event-scroll Scroll event}
|
||
*
|
||
* The custom events are:
|
||
*
|
||
* - {@link PMUI.draw.Canvas#event-createelement Create element event}
|
||
* - {@link PMUI.draw.Canvas#event-removeelement Remove element event}
|
||
* - {@link PMUI.draw.Canvas#event-changeelement Change element event}
|
||
* - {@link PMUI.draw.Canvas#event-selectelement Select element event}
|
||
* - {@link PMUI.draw.Canvas#event-rightclick Right click event}
|
||
*
|
||
* This method also initializes jQueryUI's droppable plugin (instantiated as `this.dropBehavior`)
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.attachListeners = function () {
|
||
var $canvas = $(this.html).click(this.onClick(this)),
|
||
$canvasContainer = $canvas.parent();
|
||
$canvas.mousedown(this.onMouseDown(this));
|
||
$canvasContainer.scroll(this.onScroll(this, $canvasContainer));
|
||
$canvas.mousemove(this.onMouseMove(this));
|
||
$canvas.mouseup(this.onMouseUp(this));
|
||
$canvas.on("createelement", this.onCreateElement(this));
|
||
$canvas.on("removeelement", this.onRemoveElement(this));
|
||
$canvas.on("changeelement", this.onChangeElement(this));
|
||
$canvas.on("selectelement", this.onSelectElement(this));
|
||
$canvas.on("rightclick", this.onRightClick(this));
|
||
$canvas.on("contextmenu", function (e) {
|
||
e.preventDefault();
|
||
});
|
||
this.updateBehaviors();
|
||
return this;
|
||
};
|
||
/**
|
||
* This is a hook that will be executed after an element has been created in
|
||
* the canvas.
|
||
* This hook will be executed every time a shape, a connection, or an
|
||
* independent label is created.
|
||
* @param {Object} updatedElement
|
||
* @param {string} [updatedElement.id] ID of the updated element
|
||
* @param {string} [updatedElement.type] Type of the updated element
|
||
* @param {PMUI.draw.Shape} [updatedElement.relatedObject] The updated element
|
||
* @param {Array} [updatedElement.relatedElements] An array with all the other elements created
|
||
* e.g. When executing {@link PMUI.command.CommandDelete#undo CommandDelete.undo()}, multiple elements are created
|
||
* at once, so this property will contain all those shapes.
|
||
* @template
|
||
* @protected
|
||
*/
|
||
Canvas.prototype.onCreateElementHandler = function (updatedElement) {
|
||
};
|
||
/**
|
||
* @event createelement
|
||
* Handler for the custom event createelement, this event fires when an element
|
||
* has been created. It executes the hook #onCreateElementHandler
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
*/
|
||
Canvas.prototype.onCreateElement = function (canvas) {
|
||
return function (e, ui) {
|
||
canvas.onCreateElementHandler(canvas.updatedElement);
|
||
};
|
||
};
|
||
/**
|
||
* This is a hook that will be executed after an element has been deleted in
|
||
* the canvas.
|
||
* This hook will be executed every time a shape, a connection, or an
|
||
* independent label is deleted
|
||
* @param {Object} updatedElement
|
||
* @param {string} [updatedElement.id] ID of the removed element
|
||
* @param {string} [updatedElement.type] Type of the removed element
|
||
* @param {PMUI.draw.Shape} [updatedElement.relatedObject] The removed element
|
||
* @param {Array} [updatedElement.relatedElements] An array with all the other elements removed
|
||
* e.g. When executing {@link PMUI.command.CommandDelete#execute PMUI.command.CommandDelete.execute()},
|
||
multiple elements are created
|
||
* at once, so this property will contain all those shapes.
|
||
* @template
|
||
* @protected
|
||
*/
|
||
Canvas.prototype.onRemoveElementHandler = function (updatedElement) {
|
||
return true;
|
||
};
|
||
/**
|
||
* @event removeelement
|
||
* Handler for the custom event removeelement, this event fires when an element
|
||
* has been deleted. It executes the hook #onRemoveElementHandler
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
*/
|
||
Canvas.prototype.onRemoveElement = function (canvas) {
|
||
return function (e, ui) {
|
||
canvas.onRemoveElementHandler(canvas.updatedElement.relatedElements);
|
||
};
|
||
};
|
||
/**
|
||
* This is a hook that will be executed after an element has been changed in
|
||
* the canvas.
|
||
* This hook will be executed every time a shape, a connection, or an
|
||
* independent label is changed.
|
||
* `arguments[0]` is an array with all the elements that were updated,
|
||
* the structure of each element of the array is described below:
|
||
*
|
||
* {
|
||
* id: #, // the id of the updated element
|
||
* type: # // the type of the updated element
|
||
* fields: [
|
||
* {
|
||
* field: # // the field that was updated in this element
|
||
* oldVal: # // the old value of this shape
|
||
* newVal: # // the new value of this shape
|
||
* },
|
||
* ...
|
||
* ]
|
||
* }
|
||
*
|
||
* @param {Array} updatedElements Array with all the elements that were updated.
|
||
* @template
|
||
* @protected
|
||
*/
|
||
Canvas.prototype.onChangeElementHandler = function (updatedElements) {
|
||
};
|
||
/**
|
||
* @event changeelement
|
||
* Handler for the custom event changeeelement, this event fires when an element
|
||
* has been changed. It executes the hook #onChangeElementHandler
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
*/
|
||
Canvas.prototype.onChangeElement = function (canvas) {
|
||
return function (e, ui) {
|
||
canvas.onChangeElementHandler(canvas.updatedElement);
|
||
};
|
||
};
|
||
/**
|
||
* This is a hook that will be executed after an element has been selected in
|
||
* the canvas.
|
||
* This hook will be executed every time a shape, a connection, or an
|
||
* independent label is selected
|
||
* `arguments[0]` is an array with all the elements that were selected,
|
||
* the structure of each element of the array is described below:
|
||
*
|
||
* {
|
||
* id: #, // the id of the selected element
|
||
* type: # // the type of the selected element
|
||
* relatedObject // the selected element
|
||
* }
|
||
* @param {Array} updatedElements Array with the selected elements
|
||
* @protected
|
||
* @template
|
||
*/
|
||
Canvas.prototype.onSelectElementHandler = function (updatedElements) {
|
||
};
|
||
/**
|
||
* @event selectelement
|
||
* Handler for the custom event selectelement, this event fires when an element
|
||
* has been selected. It executes the hook #onSelectElementHandler
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
*/
|
||
Canvas.prototype.onSelectElement = function (canvas) {
|
||
return function (e, ui) {
|
||
canvas.onSelectElementHandler(canvas.updatedElement);
|
||
};
|
||
};
|
||
/**
|
||
* This is a hook that will be executed after an element has been right clicked
|
||
* in the canvas or the canvas's been right clicked itself.
|
||
* This hook will be executed every time a shape, a connection, an
|
||
* independent label or the canvas is right clicked
|
||
* @param {Object} updatedElement Reference to the last element that was
|
||
* right clicked in the canvas
|
||
* @param {Object} points x coordinate where the mouse was pressed
|
||
* @template
|
||
* @protected
|
||
*/
|
||
Canvas.prototype.onRightClickHandler = function (updatedElement, points) {
|
||
};
|
||
/**
|
||
* @event rightclick
|
||
* Handler for the custom event rightclick, this event fires when an element
|
||
* has been right clicked. It executes the hook #onRightClickHandler
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
*/
|
||
Canvas.prototype.onRightClick = function (canvas) {
|
||
return function (event, e, element) {
|
||
var realPoint = canvas.relativePoint(e);
|
||
canvas.updatedElement = element;
|
||
canvas.onRightClickHandler(canvas.updatedElement, {
|
||
canvas: realPoint,
|
||
page: {
|
||
x: e.pageX,
|
||
y: e.pageY
|
||
}
|
||
});
|
||
};
|
||
};
|
||
/**
|
||
* @event click
|
||
* Click event handler, which makes `this.currentLabel` lose its focus.
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
*/
|
||
Canvas.prototype.onClick = function (canvas) {
|
||
return function (e, ui) {
|
||
var currentLabel = canvas.currentLabel,
|
||
figure,
|
||
realPoint,
|
||
realPoint,
|
||
oldConnection;
|
||
|
||
if (currentLabel) {
|
||
currentLabel.loseFocus();
|
||
$(currentLabel.textField).focusout();
|
||
}
|
||
realPoint = canvas.relativePoint(e);
|
||
figure = canvas.getBestConnecion(realPoint);
|
||
|
||
if (figure !== null) {
|
||
oldConnection = canvas.currentConnection;
|
||
canvas.emptyCurrentSelection();
|
||
if (oldConnection) {
|
||
oldConnection.hidePortsAndHandlers();
|
||
}
|
||
figure.showPortsAndHandlers();
|
||
canvas.currentConnection = figure;
|
||
}
|
||
};
|
||
};
|
||
|
||
Canvas.prototype.getBestConnecion = function (point, lineToIgnore) {
|
||
var count = this.getConnections().asArray().length,
|
||
i,
|
||
line;
|
||
for (i = 0; i < count; i += 1) {
|
||
line = this.getConnections().get(i);
|
||
if (line.hitTest(point)) {
|
||
return line;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
/**
|
||
* @event mousedown
|
||
* MouseDown Handler of the canvas. It does the following:
|
||
*
|
||
* - Trigger the {@link PMUI.draw.Canvas#event-rightclick Right Click event} if it detects a right click
|
||
* - Empties `canvas.currentSelection`
|
||
* - Hides `canvas.currentConnection` if there's one
|
||
* - Resets the position of `canvas.multipleSelectionContainer` making it visible and setting its
|
||
* `[x, y]` to the point where the user did mouse down in the `canvas`.
|
||
*
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
*/
|
||
Canvas.prototype.onMouseDown = function (canvas) {
|
||
return function (e, ui) {
|
||
var x = e.pageX - canvas.getX() + canvas.getLeftScroll() - canvas.getAbsoluteX(),
|
||
y = e.pageY - canvas.getY() + canvas.getTopScroll() - canvas.getAbsoluteY();
|
||
|
||
e.preventDefault();
|
||
if (e.which === 3) {
|
||
canvas.rightClick = true;
|
||
$(canvas.html).trigger("rightclick", [e, canvas]);
|
||
}
|
||
canvas.isMouseDown = true;
|
||
canvas.isMouseDownAndMove = false;
|
||
// do not create the rectangle selection if a segment handler
|
||
// is being dragged
|
||
if (canvas.draggingASegmentHandler) {
|
||
return;
|
||
}
|
||
// clear old selection
|
||
canvas.emptyCurrentSelection();
|
||
// hide the currentConnection if there's one
|
||
canvas.hideCurrentConnection();
|
||
canvas.multipleSelectionHelper.reset();
|
||
canvas.multipleSelectionHelper.setPosition(x / canvas.zoomFactor,
|
||
y / canvas.zoomFactor);
|
||
canvas.multipleSelectionHelper.oldX = x;
|
||
canvas.multipleSelectionHelper.oldY = y;
|
||
canvas.multipleSelectionHelper.setVisible(true);
|
||
canvas.multipleSelectionHelper.changeOpacity(0.2);
|
||
};
|
||
};
|
||
/**
|
||
* @event mousemove
|
||
* MouseMove handler of the canvas, it does the following:
|
||
*
|
||
* - Updates the position and dimension of `canvas.multipleSelectionContainer`
|
||
*
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
*/
|
||
Canvas.prototype.onMouseMove = function (canvas) {
|
||
return function (e, ui) {
|
||
if (canvas.isMouseDown && !canvas.rightClick) {
|
||
canvas.isMouseDownAndMove = true;
|
||
var x = e.pageX - canvas.getX() + canvas.getLeftScroll() - canvas.getAbsoluteX(),
|
||
y = e.pageY - canvas.getY() + canvas.getTopScroll() - canvas.getAbsoluteY(),
|
||
topLeftX,
|
||
topLeftY,
|
||
bottomRightX,
|
||
bottomRightY;
|
||
topLeftX = Math.min(x, canvas.multipleSelectionHelper.oldX);
|
||
topLeftY = Math.min(y, canvas.multipleSelectionHelper.oldY);
|
||
bottomRightX = Math.max(x, canvas.multipleSelectionHelper.oldX);
|
||
bottomRightY = Math.max(y, canvas.multipleSelectionHelper.oldY);
|
||
canvas.multipleSelectionHelper.setPosition(
|
||
topLeftX / canvas.zoomFactor,
|
||
topLeftY / canvas.zoomFactor
|
||
);
|
||
canvas.multipleSelectionHelper.setDimension(
|
||
(bottomRightX - topLeftX) / canvas.zoomFactor,
|
||
(bottomRightY - topLeftY) / canvas.zoomFactor
|
||
);
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* @event mouseup
|
||
* MouseUp handler of the canvas. It does the following:
|
||
*
|
||
* - Wraps the elements that are inside `canvas.multipleSelectionContainer`
|
||
* - Resets the state of `canvas.multipleSelectionContainer`
|
||
(see {@link PMUI.draw.MultipleSelectionContainer#reset})
|
||
*
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
*/
|
||
Canvas.prototype.onMouseUp = function (canvas) {
|
||
return function (e, ui) {
|
||
var realPoint,
|
||
x,
|
||
y;
|
||
|
||
if (canvas.isMouseDownAndMove) {
|
||
realPoint = canvas.relativePoint(e);
|
||
x = realPoint.x;
|
||
y = realPoint.y;
|
||
canvas.multipleSelectionHelper.setPosition(
|
||
Math.min(x, canvas.multipleSelectionHelper.zoomX) / canvas.zoomFactor,
|
||
Math.min(y, canvas.multipleSelectionHelper.zoomY) / canvas.zoomFactor
|
||
);
|
||
if (canvas.multipleSelectionHelper) {
|
||
canvas.multipleSelectionHelper.wrapElements();
|
||
}
|
||
} else {
|
||
if (!canvas.multipleSelectionHelper.wasDragged) {
|
||
canvas.multipleSelectionHelper.reset().setVisible(false);
|
||
}
|
||
if (canvas.isMouseDown) {
|
||
canvas.onClickHandler(canvas, x, y);
|
||
}
|
||
}
|
||
canvas.isMouseDown = false;
|
||
canvas.isMouseDownAndMove = false;
|
||
canvas.rightClick = false;
|
||
};
|
||
};
|
||
/**
|
||
* click handler
|
||
* MouseClick handler of the canvas. It does the following:
|
||
*
|
||
* @param {Canvas} canvas
|
||
* @param {Number} x
|
||
* @param {Number} y
|
||
*/
|
||
Canvas.prototype.onClickHandler = function () {
|
||
};
|
||
/**
|
||
* @event scroll
|
||
* Handler for scrolling, sets the scroll values to the canvas
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
* @param {Object} $canvasContainer jQuery element that is the container of the `canvas`
|
||
*/
|
||
Canvas.prototype.onScroll = function (canvas, $canvasContainer) {
|
||
return function (e, ui) {
|
||
canvas.setLeftScroll($canvasContainer.scrollLeft())
|
||
.setTopScroll($canvasContainer.scrollTop());
|
||
};
|
||
};
|
||
/**
|
||
* Fires the {@link PMUI.draw.Canvas#event-selectelement} event,
|
||
and elaborates the structure of the object that will
|
||
* be passed to the handlers.
|
||
* @param {Array} selection The `currentSelection` ArrayList of some canvas
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.triggerSelectEvent = function (selection) {
|
||
var i,
|
||
elements = [],
|
||
current;
|
||
for (i = 0; i < selection.length; i += 1) {
|
||
current = selection[i];
|
||
elements.push({
|
||
id: current.id,
|
||
type: current.type,
|
||
relatedObject: current
|
||
});
|
||
}
|
||
this.updatedElement = elements;
|
||
$(this.html).trigger('selectelement');
|
||
return this;
|
||
};
|
||
/**
|
||
* Fires the {@link PMUI.draw.Canvas#event-rightclick} event and elaborates the structure
|
||
* of the object that will be passed to the event.
|
||
* @param {PMUI.draw.CustomShape} element The object that's been right clicked on.
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.triggerRightClickEvent = function (element) {
|
||
this.updatedElement = {
|
||
id: element.id,
|
||
type: element.type,
|
||
relatedObject: element
|
||
};
|
||
$(this.html).trigger('rightclick');
|
||
return this;
|
||
};
|
||
/**
|
||
* Fires the {@link PMUI.draw.Canvas#event-createelement}
|
||
event, and elaborates the structure of the object that will
|
||
* be passed to the handlers.
|
||
* @param {Object} shape The shape created
|
||
* @param {Array} relatedElements The array with the other elements created
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.triggerCreateEvent = function (shape, relatedElements) {
|
||
this.updatedElement = {
|
||
id: (shape && shape.id) || null,
|
||
type: (shape && shape.type) || null,
|
||
relatedObject: shape,
|
||
relatedElements: relatedElements
|
||
};
|
||
if (!this.items.find("id", shape.id)) {
|
||
$(this.html).trigger('createelement');
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Fires the {@link PMUI.draw.Canvas#event-removeelement} event,
|
||
and elaborates the structure of the object that will
|
||
* be passed to the handlers.
|
||
* @param {PMUI.draw.CustomShape} shape The shape created
|
||
* @param {Array} relatedElements The array with the other elements created
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.triggerRemoveEvent = function (shape, relatedElements) {
|
||
this.updatedElement = {
|
||
id: (shape && shape.id) || null,
|
||
type: (shape && shape.type) || null,
|
||
relatedObject: shape,
|
||
relatedElements: relatedElements
|
||
};
|
||
$(this.html).trigger('removeelement');
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Fires the {@link PMUI.draw.Canvas#event-changeelement} event,
|
||
and elaborates the structure of the object that will
|
||
* be passed to the handlers, the structure contains the following
|
||
fields (considering old values and new values):
|
||
*
|
||
* - width
|
||
* - height
|
||
*
|
||
* @param {PMUI.draw.CustomShape} shape The shape that updated its dimension
|
||
* @param {number} oldWidth The old width of `shape`
|
||
* @param {number} oldHeight The old height of `shape`
|
||
* @param {number} newWidth The new width of `shape`
|
||
* @param {number} newHeight The old height of `shape`
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.triggerDimensionChangeEvent = function (shape, oldWidth,
|
||
oldHeight, newWidth, newHeight) {
|
||
this.updatedElement = [{
|
||
id: shape.id,
|
||
type: shape.type,
|
||
fields: [
|
||
{
|
||
field: "width",
|
||
oldVal: oldWidth,
|
||
newVal: newWidth
|
||
},
|
||
{
|
||
field: "height",
|
||
oldVal: oldHeight,
|
||
newVal: newHeight
|
||
}
|
||
],
|
||
relatedObject: shape
|
||
}];
|
||
$(this.html).trigger('changeelement');
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Fires the {@link PMUI.draw.Canvas#event-changeelement} event,
|
||
and elaborates the structure of the object that will
|
||
* be passed to the handlers, the structure contains the following fields
|
||
(considering old values and new values):
|
||
*
|
||
* - x
|
||
* - y
|
||
* - parent (the shape that is parent of this shape)
|
||
* - state (of the connection)
|
||
*
|
||
* @param {PMUI.draw.Port} port The port updated
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.triggerPortChangeEvent = function (port) {
|
||
this.updatedElement = [{
|
||
id: port.getID(),
|
||
type: port.type,
|
||
fields: [
|
||
{
|
||
field: 'x',
|
||
oldVal: port.getOldX(),
|
||
newVal: port.getX()
|
||
},
|
||
{
|
||
field: 'y',
|
||
oldVal: port.getOldY(),
|
||
newVal: port.getY()
|
||
},
|
||
{
|
||
field: 'parent',
|
||
oldVal: port.getOldParent().getID(),
|
||
newVal: port.getParent().getID()
|
||
},
|
||
{
|
||
field: 'state',
|
||
oldVal: port.connection.getOldPoints(),
|
||
newVal: port.connection.savePoints() &&
|
||
port.connection.getPoints()
|
||
}
|
||
],
|
||
relatedObject: port
|
||
}];
|
||
|
||
$(this.html).trigger('changeelement');
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Fires the {@link PMUI.draw.Canvas#event-changeelement} event,
|
||
and elaborates the structure of the object that will
|
||
* be passed to the handlers, the structure contains the following
|
||
fields (considering old values and new values):
|
||
*
|
||
* - state (of the connection)
|
||
*
|
||
* @param {PMUI.draw.Connection} connection The connection updated
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.triggerConnectionStateChangeEvent = function (connection) {
|
||
var points = [],
|
||
Point = PMUI.util.Point,
|
||
point,
|
||
i;
|
||
connection.savePoints();
|
||
for (i = 0; i < connection.points.length; i += 1) {
|
||
point = connection.points[i];
|
||
points.push(new Point(point.x / this.zoomFactor, point.y / this.zoomFactor));
|
||
}
|
||
this.updatedElement = [{
|
||
id: connection.getID(),
|
||
type: connection.type,
|
||
fields: [
|
||
{
|
||
field: 'state',
|
||
oldVal: connection.getOldPoints(),
|
||
newVal: points
|
||
}
|
||
],
|
||
relatedObject: connection
|
||
}];
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Fires the {@link PMUI.draw.Canvas#event-changeelement} event,
|
||
and elaborates the structure of the object that will
|
||
* be passed to the handlers, the structure contains the following
|
||
fields (considering old values and new values):
|
||
*
|
||
* - x
|
||
* - y
|
||
*
|
||
* @param {Array} shapes The shapes that were updated
|
||
* @param {Array} before The state of the shapes before they were repositioned
|
||
* @param {Array} after The state of the shapes after they were repositioned
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.triggerPositionChangeEvent = function (shapes, before, after) {
|
||
var i,
|
||
elements = [];
|
||
for (i = 0; i < shapes.length; i += 1) {
|
||
elements.push({
|
||
id: shapes[i].getID(),
|
||
type: shapes[i].type,
|
||
fields: [
|
||
{
|
||
field: "x",
|
||
oldVal: before[i].x,
|
||
newVal: after[i].x
|
||
},
|
||
{
|
||
field: "y",
|
||
oldVal: before[i].y,
|
||
newVal: after[i].y
|
||
}
|
||
],
|
||
relatedObject: shapes[i]
|
||
});
|
||
}
|
||
this.updatedElement = elements;
|
||
$(this.html).trigger('changeelement');
|
||
return this;
|
||
};
|
||
/**
|
||
* Fires the {@link PMUI.draw.Canvas#event-changeelement} event,
|
||
and elaborates the structure of the object that will
|
||
* be passed to the handlers, the structure contains the following
|
||
fields (considering old values and new values):
|
||
*
|
||
* - message
|
||
*
|
||
* @param {PMUI.draw.CustomShape} element The shape that updated one of ots labels
|
||
* @param {string} oldText The old text of the label
|
||
* @param {string} newText The new text of the label
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.triggerTextChangeEvent = function (element, oldText, newText) {
|
||
this.updatedElement = [{
|
||
id: element.id,
|
||
type: element.type,
|
||
parent: element.parent,
|
||
fields: [
|
||
{
|
||
field: "message",
|
||
oldVal: oldText,
|
||
newVal: newText
|
||
}
|
||
],
|
||
relatedObject: element
|
||
}];
|
||
$(this.html).trigger('changeelement');
|
||
return this;
|
||
};
|
||
/**
|
||
* Fires the {@link PMUI.draw.Canvas#event-changeelement} event,
|
||
and elaborates the structure of the object that will
|
||
* be passed to the handlers, the structure contains the following
|
||
fields (considering old values and new values):
|
||
*
|
||
* - parent
|
||
* - x
|
||
* - y
|
||
*
|
||
* @param {Array} shapes The shapes that were updated
|
||
* @param {Array} before The state of the shapes before they were repositioned
|
||
* @param {Array} after The state of the shapes after they were repositioned
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.triggerParentChangeEvent = function (shapes, before, after) {
|
||
|
||
var i,
|
||
elements = [];
|
||
for (i = 0; i < shapes.length; i += 1) {
|
||
elements.push({
|
||
id: shapes[i].getID(),
|
||
type: shapes[i].type,
|
||
fields: [
|
||
{
|
||
field: "parent",
|
||
oldParent: before[i].parent,
|
||
newVal: after[i].parent
|
||
|
||
},
|
||
{
|
||
field: "x",
|
||
oldVal: before[i].x,
|
||
newVal: after[i].x
|
||
},
|
||
{
|
||
field: "y",
|
||
oldVal: before[i].y,
|
||
newVal: after[i].y
|
||
}
|
||
],
|
||
relatedObject: shapes[i]
|
||
});
|
||
}
|
||
|
||
this.updatedElement = elements;
|
||
$(this.html).trigger('changeelement');
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the top scroll of this canvas.
|
||
* @param {number} newScroll
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.setTopScroll = function (newScroll) {
|
||
this.topScroll = newScroll;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the left scroll of this canvas.
|
||
* @param {number} newScroll
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.setLeftScroll = function (newScroll) {
|
||
this.leftScroll = newScroll;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the zoom Factor applied in the canvas
|
||
* @param {number} newZoom
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.setZoomFactor = function (newZoom) {
|
||
if (typeof newZoom === "number" && newZoom % 25 === 0 && newZoom > 0) {
|
||
this.zoomFactor = newZoom;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the currentConnection of this canvas.
|
||
* @param {PMUI.draw.Connection} newConnection
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.setCurrentConnection = function (newConnection) {
|
||
if (newConnection.type === "Connection") {
|
||
this.currentConnection = newConnection;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Assigns `newFunction` as `Canvas.prototype.toolbarShapeFactory` so that
|
||
* the canvas has a reference to the shapes that will be created when they
|
||
* are dragged from the toolbar.
|
||
* @param {Function} newFunction
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.setShapeFactory = function (newFunction) {
|
||
Canvas.prototype.shapeFactory = newFunction;
|
||
return this;
|
||
};
|
||
/**
|
||
* Gets the current zoom factor applied in the canvas
|
||
* @return {number}
|
||
*/
|
||
Canvas.prototype.getZoomFactor = function () {
|
||
return this.zoomFactor;
|
||
};
|
||
/**
|
||
* Gets the index where the zoom properties are located for the current
|
||
* zoom factor.
|
||
* @return {number}
|
||
*/
|
||
Canvas.prototype.getZoomPropertiesIndex = function () {
|
||
return this.zoomPropertiesIndex;
|
||
};
|
||
/**
|
||
* Gets the segment used to make connections in the canvas.
|
||
* @return {PMUI.draw.Segment}
|
||
*/
|
||
Canvas.prototype.getConnectionSegment = function () {
|
||
return this.connectionSegment;
|
||
};
|
||
/**
|
||
* Gets the left scroll position of the canvas.
|
||
* @return {number}
|
||
*/
|
||
Canvas.prototype.getLeftScroll = function () {
|
||
return this.leftScroll;
|
||
};
|
||
/**
|
||
* Gets the top scroll position of the canvas.
|
||
* @return {number}
|
||
*/
|
||
Canvas.prototype.getTopScroll = function () {
|
||
return this.topScroll;
|
||
};
|
||
/**
|
||
* Gets the current connection stored in this canvas.
|
||
* @return {PMUI.draw.Connection}
|
||
*/
|
||
Canvas.prototype.getCurrentConnection = function () {
|
||
return this.currentConnection;
|
||
};
|
||
/**
|
||
* Gets the current selection of this canvas.
|
||
* @return {PMUI.util.ArrayList}
|
||
*/
|
||
Canvas.prototype.getCurrentSelection = function () {
|
||
return this.currentSelection;
|
||
};
|
||
/**
|
||
* Gets all the connections of this canvas.
|
||
* @return {PMUI.util.ArrayList}
|
||
*/
|
||
Canvas.prototype.getConnections = function () {
|
||
return this.connections;
|
||
};
|
||
/**
|
||
* Gets all the shared connections stored in this canvas.
|
||
* @return {PMUI.util.ArrayList}
|
||
*/
|
||
Canvas.prototype.getSharedConnections = function () {
|
||
return this.sharedConnections;
|
||
};
|
||
/**
|
||
* Gets all the custom shapes of the canvas.
|
||
* @return {PMUI.util.ArrayList}
|
||
*/
|
||
Canvas.prototype.getCustomShapes = function () {
|
||
return this.customShapes;
|
||
};
|
||
/**
|
||
* Gets all the regular shapes of the canvas.
|
||
* @return {PMUI.util.ArrayList}
|
||
*/
|
||
Canvas.prototype.getRegularShapes = function () {
|
||
return this.regularShapes;
|
||
};
|
||
/**
|
||
* Gets the multiple selection container instance.
|
||
* @return {PMUI.draw.MultipleSelectionContainer}
|
||
*/
|
||
Canvas.prototype.getMultipleSelectionHelper = function () {
|
||
return this.multipleSelectionHelper;
|
||
};
|
||
/**
|
||
* Gets the horizontal snapper of this canvas.
|
||
* @return {PMUI.draw.Snapper}
|
||
*/
|
||
Canvas.prototype.getHorizontalSnapper = function () {
|
||
return this.horizontalSnapper;
|
||
};
|
||
/**
|
||
* Gets the vertical snapper of this canvas.
|
||
* @return {PMUI.draw.Snapper}
|
||
*/
|
||
Canvas.prototype.getVerticalSnapper = function () {
|
||
return this.verticalSnapper;
|
||
};
|
||
/**
|
||
* Gets the last updated element in the canvas
|
||
* @return {Mixed}
|
||
*/
|
||
Canvas.prototype.getUpdatedElement = function () {
|
||
return this.updatedElement;
|
||
};
|
||
/**
|
||
* Any instance of the class Canvas is not resizable so this method
|
||
* will always return false.
|
||
* @return {boolean}
|
||
*/
|
||
Canvas.prototype.isResizable = function () {
|
||
return false;
|
||
};
|
||
/**
|
||
* Gets a reference to itself.
|
||
* @return {PMUI.draw.Canvas}
|
||
*/
|
||
Canvas.prototype.getCanvas = function () {
|
||
return this;
|
||
};
|
||
/**
|
||
* Undoes the last action in the canvas by calling `this.commandStack.undo`.
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.undo = function () {
|
||
this.commandStack.undo();
|
||
return this;
|
||
};
|
||
/**
|
||
* Redoes the last action in the canvas by calling `this.commandStack.redo`.
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.redo = function () {
|
||
this.commandStack.redo();
|
||
return this;
|
||
};
|
||
/**
|
||
* Serializes this canvas by serializing its customShapes, regularShapes and connections.
|
||
* @return {Object}
|
||
* @return {Object} return.customShapes See {@link PMUI.draw.CustomShape#stringify}
|
||
* @return {Object} return.regularShapes See {@link PMUI.draw.Shape#stringify}
|
||
* @return {Object} return.connections See {@link PMUI.draw.Connection#stringify}
|
||
*/
|
||
Canvas.prototype.stringify = function () {
|
||
var i,
|
||
customShapes = [],
|
||
regularShapes = [],
|
||
connections = [],
|
||
inheritedJSON,
|
||
thisJSON,
|
||
Shape;
|
||
// serialize custom shapes
|
||
for (i = 0; i < this.customShapes.getSize(); i += 1) {
|
||
customShapes.push(this.customShapes.get(i).stringify());
|
||
}
|
||
// serialize regular shapes
|
||
for (i = 0; i < this.regularShapes.getSize(); i += 1) {
|
||
regularShapes.push(this.regularShapes.get(i).stringify());
|
||
}
|
||
// serialize connections shapes
|
||
for (i = 0; i < this.connections.getSize(); i += 1) {
|
||
connections.push(this.connections.get(i).stringify());
|
||
}
|
||
inheritedJSON = Shape.prototype.stringify.call(this);
|
||
thisJSON = {
|
||
customShapes: customShapes,
|
||
regularShapes: regularShapes,
|
||
connections: connections
|
||
};
|
||
$.extend(true, inheritedJSON, thisJSON);
|
||
return inheritedJSON;
|
||
};
|
||
/**
|
||
* Adds shape and its children to `this.shapesToCopy` array so that later
|
||
* they can be pasted in the canvas.
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.addToShapesToCopy = function (shape) {
|
||
var i,
|
||
child,
|
||
shapeCustomized = shape.stringify();
|
||
shapeCustomized.extendedType = shape.extendedType;
|
||
this.shapesToCopy.push(shapeCustomized);
|
||
for (i = 0; i < shape.getChildren().getSize(); i += 1) {
|
||
child = shape.getChildren().get(i);
|
||
this.addToShapesToCopy(child);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Duplicates the `this.sharedConnection` array and the shapes stored in `this.currentSelection`
|
||
* array (saving them in `this.shapesToCopy` and `this.connectionsToCopy` respectively) so
|
||
* that they can be pasted later in the canvas.
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.copy = function () {
|
||
var i,
|
||
shape,
|
||
connection;
|
||
// duplicate shapes
|
||
this.shapesToCopy = [];
|
||
for (i = 0; i < this.getCurrentSelection().getSize(); i += 1) {
|
||
shape = this.getCurrentSelection().get(i);
|
||
this.addToShapesToCopy(shape);
|
||
}
|
||
// duplicate connections
|
||
this.connectionsToCopy = [];
|
||
for (i = 0; i < this.getSharedConnections().getSize(); i += 1) {
|
||
connection = this.getSharedConnections().get(i);
|
||
this.connectionsToCopy.push(connection.stringify());
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Pastes the shapes saved in `this.shapesToCopy` and the connections saved in `this.connectionsToCopy`
|
||
* by calling the #parse method.
|
||
*
|
||
* Currently the parser is called with these arguments:
|
||
*
|
||
* {
|
||
* shapes: this.shapesToCopy,
|
||
* connections: this.connectionsToCopy,
|
||
* createCommand: true,
|
||
* uniqueID: true,
|
||
* selectAfterFinish: true,
|
||
* prependMessage: "Copy of ",
|
||
* diffX: 100,
|
||
* diffY: 100
|
||
* }
|
||
*
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.paste = function () {
|
||
this.parse({
|
||
shapes: this.shapesToCopy,
|
||
connections: this.connectionsToCopy,
|
||
createCommand: true,
|
||
uniqueID: true,
|
||
selectAfterFinish: true,
|
||
prependMessage: "Copy of ",
|
||
diffX: 100,
|
||
diffY: 100
|
||
});
|
||
return this;
|
||
};
|
||
/**
|
||
* Default copy paste factory which creates new instances of {@link PMUI.draw.CustomShape}, its main purpose
|
||
* is to create instances using `this.copyAndPasteReferences` (passed through the config options of the canvas)
|
||
* which are reference variables to the constructor of some class (a class declared outside the library).
|
||
*
|
||
* // let's assume that there's a class declared outside the library called BpmnActivity
|
||
* var BpmnActivity = function (options) {
|
||
* ...
|
||
* };
|
||
*
|
||
* // in the config options of this canvas, we passed a reference to the constructor like this
|
||
* var canvas = new PMUI.draw.Canvas({
|
||
* ...
|
||
* copyAndPasteReferences: {
|
||
* bpmnActivity: BpmnActivity
|
||
* }
|
||
* ...
|
||
* });
|
||
*
|
||
* // so the copyAndPasteFactory will create an instance of the class BpmnActivity
|
||
* // using that reference
|
||
* // e.g.
|
||
* // let's assume that options are the correct configuration options for BpmnActivity
|
||
* var bpmnActivityInstance = Canvas.prototype.copyAndPasteFactory('bpmnActivity', options);
|
||
*
|
||
*
|
||
* @param {string} type The type of the shape to be created
|
||
* @param {Object} options The config options to be passed to the constructor of the shape
|
||
* @return {PMUI.draw.CustomShape} A custom shape or shape created using the reference created before.
|
||
*/
|
||
Canvas.prototype.shapeFactory = function (type, options) {
|
||
if (this.copyAndPasteReferences[type]) {
|
||
return new this.copyAndPasteReferences[type](options);
|
||
}
|
||
return new PMUI.draw.CustomShape(options);
|
||
};
|
||
/**
|
||
* Factory to create connections
|
||
* @param {string} type
|
||
* @param {Object} options
|
||
* @return {Object}
|
||
*/
|
||
Canvas.prototype.connectionFactory = function (type, options) {
|
||
if (type && this.copyAndPasteReferences[type]) {
|
||
return new this.copyAndPasteReferences[type](options);
|
||
}
|
||
return new PMUI.draw.Connection(options);
|
||
};
|
||
|
||
/**
|
||
* Transforms an array of objects, each of the form `{id: #, parent: #}` to a tree like object.
|
||
* The structure of the returned object (which represents a tree) is:
|
||
*
|
||
* {
|
||
* id_1: [child_1_of_id1, child_2_of_id1, ...],
|
||
* id_2: [child_1_of_id2, child_2_of_id2, ...],
|
||
* ...
|
||
* }
|
||
*
|
||
* @param {Array} nodes
|
||
* @return {Object}
|
||
*/
|
||
Canvas.prototype.transformToTree = function (nodes) {
|
||
var tree = {},
|
||
node,
|
||
i;
|
||
for (i = 0; i < nodes.length; i += 1) {
|
||
// node = {id: #, parent: #, order: #}
|
||
node = nodes[i];
|
||
// create the children of node.id
|
||
if (!tree[node.id]) {
|
||
tree[node.id] = [];
|
||
}
|
||
// insert to the children of its parent
|
||
if (node.parent) {
|
||
// check if the node exists
|
||
if (!tree[node.parent]) {
|
||
tree[node.parent] = [];
|
||
}
|
||
// add node to the children of node's parent
|
||
tree[node.parent][node.order] = node.id;
|
||
}
|
||
}
|
||
return tree;
|
||
};
|
||
/**
|
||
* Given a tree (with the structure proposed in #transformToTree)
|
||
* and a pointer to the root node, perform a levelOrder traversal (BFS)
|
||
* of the tree and returning an array with the IDs of each node.
|
||
* @param {Object} tree
|
||
* @param {String} [root=canvas.getID()] The ID of the root node (might be canvas)
|
||
* @return {Array} An array with the IDs of the nodes of the tree in level order traversal
|
||
*/
|
||
Canvas.prototype.levelOrderTraversal = function (tree, root) {
|
||
var queue = [],
|
||
processed = [],
|
||
top,
|
||
realRoot = root || this.getID(),
|
||
i;
|
||
queue.push(realRoot);
|
||
while (queue.length > 0) {
|
||
top = queue.shift();
|
||
// push the json of the node
|
||
processed.push(top);
|
||
// push to the queue
|
||
for (i = 0; i < tree[top].length; i += 1) {
|
||
queue.push(tree[top][i]);
|
||
}
|
||
}
|
||
// return the IDs
|
||
return processed;
|
||
};
|
||
/**
|
||
* Parses `options` creating shapes and connections and placing them in this canvas.
|
||
* It does the following:
|
||
*
|
||
* - Creates each shape (in the same order as it is in the array `options.shapes`)
|
||
* - Creates each connection (in the same order as it is in the array `options.connections`)
|
||
* - Creates the an instance of {@link PMUI.command.CommandPaste} (if possible)
|
||
*
|
||
* @param {Object} options
|
||
* @param {Array} [options.shapes=[]] The config options of each shape to be placed in this canvas.
|
||
* @param {Array} [options.connections=[]] The config options of each connection to be placed in this canvas.
|
||
* @param {boolean} [options.uniqueID=false] If set to true, it'll assign a unique ID to each shape created.
|
||
* @param {boolean} [options.selectAfterFinish=false] If set to true, it'll add the shapes that are
|
||
* direct children of this canvas to `this.currentSelection` arrayList.
|
||
* @param {string} [options.prependMessage=""] The message to be prepended to each shape's label.
|
||
* @param {boolean} [options.createCommand=true] If set to true it'll create a command for each creation
|
||
* of a shape and connection (see {@link PMUI.command.CommandCreate},
|
||
{@link PMUI.command.CommandConnect}) and save them in
|
||
* a {@link PMUI.command.CommandPaste} (for undo-redo purposes).
|
||
* @param {number} [options.diffX=0] The number of pixels on the x-coordinate to move the shape on creation
|
||
* @param {number} [options.diffY=0] The number of pixels on the y-coordinate to move the shape on creation
|
||
* @chainable
|
||
*/
|
||
Canvas.prototype.parse = function (options) {
|
||
var defaults = {
|
||
shapes: [],
|
||
connections: [],
|
||
uniqueID: false,
|
||
selectAfterFinish: false,
|
||
prependMessage: "",
|
||
createCommand: true,
|
||
diffX: 0,
|
||
diffY: 0
|
||
},
|
||
i,
|
||
j,
|
||
id,
|
||
oldID,
|
||
shape,
|
||
points,
|
||
shapeOptions,
|
||
connection,
|
||
connectionOptions,
|
||
sourcePort,
|
||
sourcePortOptions,
|
||
sourceShape,
|
||
sourceBorder,
|
||
destPort,
|
||
destPortOptions,
|
||
destShape,
|
||
destBorder,
|
||
command,
|
||
diffX,
|
||
diffY,
|
||
stackCommandCreate = [],
|
||
stackCommandConnect = [],
|
||
canvasID = this.getID(),
|
||
mapOldId = {},
|
||
map = {};
|
||
$.extend(true, defaults, options);
|
||
// set the differentials (if the shapes are pasted in the canvas)
|
||
diffX = defaults.diffX;
|
||
diffY = defaults.diffY;
|
||
// map the canvas
|
||
map[canvasID] = this;
|
||
mapOldId[canvasID] = canvasID;
|
||
// empty the current selection and sharedConnections as a consequence
|
||
// (so that the copy is selected after)
|
||
if (defaults.selectAfterFinish) {
|
||
this.emptyCurrentSelection();
|
||
}
|
||
for (i = 0; i < defaults.shapes.length; i += 1) {
|
||
shapeOptions = {};
|
||
$.extend(true, shapeOptions, defaults.shapes[i]);
|
||
|
||
// set the canvas of <shape>
|
||
shapeOptions.canvas = this;
|
||
|
||
// create a map of the current id with a new id
|
||
oldID = shapeOptions.id;
|
||
|
||
// generate a unique id on user request
|
||
if (defaults.uniqueID) {
|
||
shapeOptions.id = PMUI.generateUniqueId();
|
||
}
|
||
mapOldId[oldID] = shapeOptions.id;
|
||
|
||
// change labels' messages (using prependMessage)
|
||
if (shapeOptions.labels) {
|
||
for (j = 0; j < shapeOptions.labels.length; j += 1) {
|
||
shapeOptions.labels[j].message = defaults.prependMessage +
|
||
shapeOptions.labels[j].message;
|
||
}
|
||
}
|
||
|
||
// create an instance of the shape based on its type
|
||
shape = this.shapeFactory(shapeOptions.extendedType, shapeOptions);
|
||
|
||
// map the instance with its id
|
||
map[shapeOptions.id] = shape;
|
||
|
||
// if the shapes don't have a valid parent then set the parent
|
||
// to be equal to the canvas
|
||
// TODO: ADD shapeOptions.topLeftOnCreation TO EACH SHAPE
|
||
if (!mapOldId[shapeOptions.parent]) {
|
||
this.addElement(shape,
|
||
shapeOptions.x + diffX, shapeOptions.y + diffY, true);
|
||
} else if (shapeOptions.parent !== canvasID) {
|
||
// get the parent of this shape
|
||
map[mapOldId[shapeOptions.parent]].addElement(shape, shapeOptions.x,
|
||
shapeOptions.y, true);
|
||
} else {
|
||
// move the shapes a little (so it can be seen that
|
||
// they were duplicated)
|
||
map[mapOldId[shapeOptions.parent]].addElement(shape,
|
||
shapeOptions.x + diffX, shapeOptions.y + diffY, true);
|
||
}
|
||
|
||
// perform some extra actions defined for each shape
|
||
shape.parseHook();
|
||
|
||
shape.attachListeners();
|
||
// execute command create but don't add it to the canvas.commandStack
|
||
command = new PMUI.command.CommandCreate(shape);
|
||
command.execute();
|
||
stackCommandCreate.push(command);
|
||
}
|
||
for (i = 0; i < defaults.connections.length; i += 1) {
|
||
connectionOptions = {};
|
||
$.extend(true, connectionOptions, defaults.connections[i]);
|
||
|
||
// state of the connection
|
||
points = connectionOptions.state || [];
|
||
|
||
// determine the shapes
|
||
sourcePortOptions = connectionOptions.srcPort;
|
||
sourceShape = map[mapOldId[sourcePortOptions.parent]];
|
||
sourceBorder = sourceShape.getBorderConsideringLayers();
|
||
|
||
destPortOptions = connectionOptions.destPort;
|
||
destShape = map[mapOldId[destPortOptions.parent]];
|
||
destBorder = destShape.getBorderConsideringLayers();
|
||
|
||
// populate points if points has no info (backwards compatibility,
|
||
// e.g. the flow state is null)
|
||
if (points.length === 0) {
|
||
points.push({
|
||
x: sourcePortOptions.x + sourceShape.getAbsoluteX(),
|
||
y: sourcePortOptions.y + sourceShape.getAbsoluteY()
|
||
});
|
||
points.push({
|
||
x: destPortOptions.x + destShape.getAbsoluteX(),
|
||
y: destPortOptions.y + destShape.getAbsoluteY()
|
||
});
|
||
}
|
||
|
||
//create the ports
|
||
sourcePort = new PMUI.draw.Port({
|
||
width: 8,
|
||
height: 8
|
||
});
|
||
destPort = new PMUI.draw.Port({
|
||
width: 8,
|
||
height: 8
|
||
});
|
||
// add the ports to the shapes
|
||
// LOGIC: points is an array of points relative to the canvas.
|
||
// CustomShape.addPort() requires that the point passed as an argument
|
||
// is respect to the shape, so transform the point's coordinates (also
|
||
// consider the border)
|
||
sourceShape.addPort(
|
||
sourcePort,
|
||
points[0].x + diffX + sourceBorder -
|
||
sourceShape.getAbsoluteX(),
|
||
points[0].y + diffX + sourceBorder -
|
||
sourceShape.getAbsoluteY()
|
||
);
|
||
destShape.addPort(
|
||
destPort,
|
||
points[points.length - 1].x + diffX + destBorder -
|
||
destShape.getAbsoluteX(),
|
||
points[points.length - 1].y + diffY + destBorder -
|
||
destShape.getAbsoluteY(),
|
||
false,
|
||
sourcePort
|
||
);
|
||
|
||
connection = this.connectionFactory(
|
||
connectionOptions.type,
|
||
{
|
||
srcPort: sourcePort,
|
||
destPort: destPort,
|
||
canvas: this,
|
||
segmentStyle: connectionOptions.segmentStyle
|
||
}
|
||
);
|
||
connection.id = connectionOptions.id || PMUI.generateUniqueId();
|
||
if (defaults.uniqueID) {
|
||
connection.id = PMUI.generateUniqueId();
|
||
}
|
||
//set its decorators
|
||
connection.setSrcDecorator(new PMUI.draw.ConnectionDecorator({
|
||
width: 11,
|
||
height: 11,
|
||
canvas: this,
|
||
decoratorPrefix: connectionOptions.srcDecoratorPrefix,
|
||
decoratorType: "source",
|
||
parent: connection
|
||
}));
|
||
connection.setDestDecorator(new PMUI.draw.ConnectionDecorator({
|
||
width: 11,
|
||
height: 11,
|
||
canvas: this,
|
||
decoratorPrefix: connectionOptions.destDecoratorPrefix,
|
||
decoratorType: "target",
|
||
parent: connection
|
||
}));
|
||
|
||
command = new PMUI.command.CommandConnect(connection);
|
||
stackCommandConnect.push(command);
|
||
|
||
// connect the two ports
|
||
if (points.length >= 3) {
|
||
connection.connect({
|
||
algorithm: 'user',
|
||
points: connectionOptions.state,
|
||
dx: defaults.diffX,
|
||
dy: defaults.diffY
|
||
});
|
||
} else {
|
||
// use manhattan
|
||
// console.log("manhattan");
|
||
connection.connect();
|
||
}
|
||
connection.setSegmentMoveHandlers();
|
||
|
||
// add the connection to the canvas, that means insert its html to
|
||
// the DOM and adding it to the connections array
|
||
this.addConnection(connection);
|
||
|
||
// now that the connection was drawn try to create the intersections
|
||
connection.checkAndCreateIntersectionsWithAll();
|
||
|
||
//attaching port listeners
|
||
sourcePort.attachListeners(sourcePort);
|
||
destPort.attachListeners(destPort);
|
||
|
||
this.triggerCreateEvent(connection, []);
|
||
}
|
||
|
||
// finally add to currentSelection each shape if possible (this method is
|
||
// down here because of the zIndex problem with connections)
|
||
if (defaults.selectAfterFinish) {
|
||
for (id in map) {
|
||
if (map.hasOwnProperty(id)) {
|
||
if (map[id].family !== 'Canvas') {
|
||
this.addToSelection(map[id]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// create command if possible
|
||
if (defaults.createCommand) {
|
||
this.commandStack.add(new PMUI.command.CommandPaste(this, {
|
||
stackCommandCreate: stackCommandCreate,
|
||
stackCommandConnect: stackCommandConnect
|
||
}));
|
||
}
|
||
return this;
|
||
};
|
||
|
||
Canvas.prototype.getRelativeX = function () {
|
||
return this.x + this.absoluteX;
|
||
};
|
||
|
||
Canvas.prototype.getRelativeY = function () {
|
||
return this.y + this.absoluteY;
|
||
};
|
||
Canvas.prototype.hideAllFocusLabels = function () {
|
||
var size = this.customShapes.getSize(),
|
||
i,
|
||
shape;
|
||
for (i = 0; i < size; i += 1) {
|
||
shape = this.customShapes.get(i);
|
||
shape.labels.get(0).loseFocus();
|
||
}
|
||
return true;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Canvas', Canvas);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Canvas;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @abstract
|
||
* @class PMUI.draw.Shape
|
||
* Represents a shape in the PMDraw framework, shapes can be:
|
||
*
|
||
* - **Regular shapes** (Ovals, rectangles, polygons)
|
||
* - **Custom shapes** (these kind of shapes can have sprites)
|
||
*
|
||
* A shape has the following characteristics:
|
||
*
|
||
* - It has a dragBehavior (inherited from {@link PMUI.draw.Core})
|
||
* - It has a dropBehavior (inherited from {@link PMUI.draw.BehavioralElement})
|
||
* - It has a containerBehavior (inherited from {@link PMUI.draw.BehavioralElement})
|
||
* - It has a resizeBehavior (instantiated in this class)
|
||
*
|
||
* This class cannot be instantiated.
|
||
*
|
||
* @extend PMUI.draw.BehavioralElement
|
||
* @constructor Creates an instance of the class ConnectionDecorator
|
||
* @param {Object} options Initialization options
|
||
* @cfg {boolean} [topLeft=false] If set to true then when this shape is dragged from the toolbar it'll be created
|
||
* and placed in its topLeft coordinate otherwise it'll use the center as its topLeft coordinate
|
||
* @cfg {string} [resizeBehavior="no"] Default resize behavior used to create the correct instance in the factory
|
||
* @cfg {Object} [resizeHandlers={
|
||
* type: "None",
|
||
* total: 4,
|
||
* resizableStyle: {
|
||
* cssProperties: {
|
||
* 'background-color': "rgb(0, 255, 0)",
|
||
* 'border': '1px solid black'
|
||
* }
|
||
* },
|
||
* nonResizableStyle: {
|
||
* cssProperties: {
|
||
* 'background-color': "white",
|
||
* 'border': '1px solid black'
|
||
* }
|
||
* }
|
||
* }] Default styles to create the instances of the class Style
|
||
* @cfg {string} [drag="disabled"] Default drag behavior used to create the correct instance in the factory
|
||
*/
|
||
var Shape = function (options) {
|
||
|
||
Shape.superclass.call(this, options);
|
||
|
||
/**
|
||
* Array built when setting the dimension of the shape to store the
|
||
* x coordinate of the div corners in clockwise order starting at top left
|
||
* @property {Array}
|
||
*/
|
||
this.xCorners = [0, 0, 0, 0];
|
||
/**
|
||
* Array built when setting the dimension of the shape to store the
|
||
* y coordinate of the div corners in clockwise order starting at top left
|
||
* @property {Array}
|
||
*/
|
||
this.yCorners = [0, 0, 0, 0];
|
||
/**
|
||
* Array built when setting the dimension of the shape to store the
|
||
* x coordinate of the midpoints of each div border in clockwise order
|
||
* starting at the top border
|
||
* @property {Array}
|
||
*/
|
||
this.xMidPoints = [0, 0, 0, 0];
|
||
/**
|
||
* Array built when setting the dimension of the shape to store the
|
||
* y coordinate of the midpoints of each div border in clockwise order
|
||
* starting at the top border
|
||
* @property {Array}
|
||
*/
|
||
this.yMidPoints = [0, 0, 0, 0];
|
||
/**
|
||
* List containing the resize Points located in the corner of a div
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.cornerResizeHandlers = new PMUI.util.ArrayList();
|
||
/**
|
||
* List containing the resize Points located in the middle of a border
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.midResizeHandlers = new PMUI.util.ArrayList();
|
||
|
||
/**
|
||
* Center point of the shape (in the case of a polygon).
|
||
* @property {PMUI.util.Point}
|
||
*/
|
||
this.center = null;
|
||
/**
|
||
* The parent of this shape.
|
||
* @property {PMUI.draw.Shape}
|
||
*/
|
||
this.parent = null;
|
||
/**
|
||
* Old parent of this shape (useful to check the previous
|
||
* container of this shape).
|
||
* @property {PMUI.draw.Shape}
|
||
*/
|
||
this.oldParent = null;
|
||
/**
|
||
* Default zOrder of the shape.
|
||
* @property {number} [defaultZOrder=1]
|
||
*/
|
||
this.defaultZOrder = 1;
|
||
/**
|
||
* Denotes whether this shape is being dragged.
|
||
* @property {boolean} [dragging=false]
|
||
*/
|
||
this.dragging = false;
|
||
/**
|
||
* Denotes whether this shape was dragged.
|
||
* @property {boolean} [wasDragged=false]
|
||
*/
|
||
this.wasDragged = false;
|
||
/**
|
||
* Denotes whether this shape was entered by a draggable element.
|
||
* @property {boolean} [entered=false]
|
||
*/
|
||
this.entered = false;
|
||
/**
|
||
* Determines the resizeBehavior that this object has.
|
||
* @property {PMUI.behavior.ResizeBehavior}
|
||
*/
|
||
this.resizeBehavior = null;
|
||
/**
|
||
* Determines whether the shape is being resized or not.
|
||
* @property {boolean} [resizing=false]
|
||
*/
|
||
this.resizing = false;
|
||
/**
|
||
* This shape was repainted.
|
||
* @property {boolean}
|
||
*/
|
||
this.repainted = false;
|
||
/**
|
||
* Determines whether a shape has fixed Dimensions or not
|
||
* @property boolean
|
||
*/
|
||
this.fixed = true;
|
||
/**
|
||
* Determines if the shape's been dropped to a different container
|
||
* @property {boolean}
|
||
*/
|
||
this.changedContainer = false;
|
||
/**
|
||
* Determines whether this shape will be created considering its top-left
|
||
* coordinates or its center
|
||
* @property {boolean}
|
||
*/
|
||
this.topLeftOnCreation = false;
|
||
/**
|
||
* Determines wether the events ["mousedown, mouseup, click"] will be assigned to component.
|
||
* @property {boolean}
|
||
*/
|
||
this.attachEvents = true
|
||
// set defaults
|
||
Shape.prototype.init.call(this, options);
|
||
};
|
||
|
||
// inherits from BehavioralElement
|
||
PMUI.inheritFrom('PMUI.draw.BehavioralElement', Shape);
|
||
|
||
/**
|
||
* Type of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
Shape.prototype.type = "Shape";
|
||
|
||
/**
|
||
* Family of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
Shape.prototype.family = "Shape";
|
||
|
||
/**
|
||
* Instance of RegularDragBehavior (avoiding the creation of multiple same instances)
|
||
* @property {PMUI.behavior.DragBehavior} [noDragBehavior=null]
|
||
*/
|
||
Shape.prototype.noDragBehavior = null;
|
||
|
||
/**
|
||
* Instance of RegularDragBehavior (avoiding the creation of multiple same instances)
|
||
* @property {PMUI.behavior.DragBehavior} [regularDragBehavior=null]
|
||
*/
|
||
Shape.prototype.regularDragBehavior = null;
|
||
|
||
/**
|
||
* Instance of ConnectionDragBehavior (avoiding the creation of multiple same instances)
|
||
* @property {PMUI.behavior.ConnectionDragBehavior} [connectionDragBehavior=null]
|
||
*/
|
||
Shape.prototype.connectionDragBehavior = null;
|
||
|
||
/**
|
||
* Instance of CustomShapeDragBehavior (avoiding the creation of multiple same instances)
|
||
* @property {PMUI.behavior.CustomShapeDragBehavior} [customShapeDragBehavior=null]
|
||
*/
|
||
Shape.prototype.customShapeDragBehavior = null;
|
||
|
||
/**
|
||
* Corner resize identifiers (for jQueryUI Resizable handles)
|
||
* @property {Array} [cornersIdentifiers=['nw', 'ne', 'se', 'sw']]
|
||
*/
|
||
Shape.prototype.cornersIdentifiers = ['nw', 'ne', 'se', 'sw'];
|
||
|
||
/**
|
||
* Mid resize identifiers (for jQueryUI Resizable handles)
|
||
* @property {Array} [midPointIdentifiers=['n', 'e', 's', 'w']]
|
||
*/
|
||
Shape.prototype.midPointIdentifiers = ['n', 'e', 's', 'w'];
|
||
|
||
/**
|
||
* Constant for the maximum z-index
|
||
* @property {number} [MAX_ZINDEX=100]
|
||
*/
|
||
Shape.prototype.MAX_ZINDEX = 100;
|
||
|
||
/**
|
||
* Constant for the default radius used in the class Arc
|
||
* @property {number} [DEFAULT_RADIUS=6]
|
||
*/
|
||
Shape.prototype.DEFAULT_RADIUS = 6;
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance
|
||
* @param {Object} options The object that contains old points and new points
|
||
* @private
|
||
*/
|
||
Shape.prototype.init = function (options) {
|
||
var defaults = {
|
||
topLeft: false,
|
||
resizeBehavior: "no",
|
||
resizeHandlers: {
|
||
type: "None",
|
||
total: 4,
|
||
resizableStyle: {
|
||
cssProperties: {
|
||
'background-color': "rgb(0, 255, 0)",
|
||
'border': '1px solid black'
|
||
}
|
||
},
|
||
nonResizableStyle: {
|
||
cssProperties: {
|
||
'background-color': "white",
|
||
'border': '1px solid black'
|
||
}
|
||
}
|
||
},
|
||
drag: "disabled",
|
||
attachEvents: true
|
||
};
|
||
|
||
$.extend(true, defaults, options);
|
||
|
||
if (defaults.drag !== "disabled") {
|
||
this.setDragBehavior(defaults.drag);
|
||
} else {
|
||
this.setDragBehavior("nodrag");
|
||
}
|
||
this.setResizeBehavior(defaults.resizeBehavior);
|
||
this.createHandlers(defaults.resizeHandlers.type,
|
||
defaults.resizeHandlers.total,
|
||
defaults.resizeHandlers.resizableStyle,
|
||
defaults.resizeHandlers.nonResizableStyle);
|
||
this.topLeftOnCreation = defaults.topLeft;
|
||
this.attachEvents = defaults.attachEvents;
|
||
};
|
||
|
||
/**
|
||
* Creates handlers according to the `number` of handlers, the `type` of handlers (currently only Rectangle
|
||
* is supported), the `resizableStyle` (created in `this.initObject`) and the `nonResizableStyle`
|
||
* (created in `this.initObject`).
|
||
* @param {string} type
|
||
* @param {number} number
|
||
* @param {Object} resizableStyle
|
||
* @param {Object} nonResizableStyle
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.createHandlers = function (type, number, resizableStyle, nonResizableStyle) {
|
||
if (type === "Rectangle") {
|
||
|
||
var i;
|
||
|
||
//First determine how many ResizeHandlers we are to create
|
||
if (!number || (number !== 8 &&
|
||
number !== 4 && number !== 0)) {
|
||
number = 4;
|
||
}
|
||
//Then insert the corners first
|
||
for (i = 0; i < number && i < 4; i += 1) {
|
||
this.cornerResizeHandlers.insert(
|
||
new PMUI.draw.ResizeHandler({
|
||
parent: this,
|
||
zOrder: PMUI.util.Style.MAX_ZINDEX + 3,
|
||
representation: new PMUI.draw.Rectangle(),
|
||
orientation: this.cornersIdentifiers[i],
|
||
resizableStyle: resizableStyle,
|
||
nonResizableStyle: nonResizableStyle
|
||
})
|
||
);
|
||
}
|
||
//subtract 4 just added resize points to the total
|
||
number -= 4;
|
||
//add the rest to the mid list
|
||
for (i = 0; i < number; i += 1) {
|
||
this.midResizeHandlers.insert(
|
||
new PMUI.draw.ResizeHandler({
|
||
parent: this,
|
||
zOrder: PMUI.util.Style.MAX_ZINDEX + 3,
|
||
representation: new PMUI.draw.Rectangle(),
|
||
orientation: this.midPointIdentifiers[i],
|
||
resizableStyle: resizableStyle,
|
||
nonResizableStyle: nonResizableStyle
|
||
})
|
||
);
|
||
}
|
||
}
|
||
return this;
|
||
//console.log(this.cornerResizeHandlers.asArray());
|
||
//console.log(this.midResizeHandlers.asArray());
|
||
};
|
||
|
||
/**
|
||
* Updates the position of the handlers using `this.cornerResizeHandlers` and `this.midResizeHandlers`.
|
||
* NOTE: There's a prerequisite to call this method, `this.setDimensions` must be called first
|
||
* because it updated the arrays used by this method.
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.updateHandlers = function () {
|
||
var handler,
|
||
i;
|
||
for (i = 0; i < this.cornerResizeHandlers.getSize(); i += 1) {
|
||
handler = this.cornerResizeHandlers.get(i);
|
||
handler.setPosition(this.xCorners[i] -
|
||
Math.round(handler.width / 2) - 1,
|
||
this.yCorners[i] - Math.round(handler.height / 2) - 1);
|
||
}
|
||
for (i = 0; i < this.midResizeHandlers.getSize(); i += 1) {
|
||
handler = this.midResizeHandlers.get(i);
|
||
handler.setPosition(this.xMidPoints[i] -
|
||
Math.round(handler.width / 2) - 1,
|
||
this.yMidPoints[i] - Math.round(handler.height / 2) - 1);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the visibility of the resize handlers
|
||
* @param {boolean} visible
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.showOrHideResizeHandlers = function (visible) {
|
||
|
||
var i;
|
||
if (!visible) {
|
||
visible = false;
|
||
}
|
||
for (i = 0; i < this.cornerResizeHandlers.getSize(); i += 1) {
|
||
this.cornerResizeHandlers.get(i).setVisible(visible);
|
||
}
|
||
|
||
for (i = 0; i < this.midResizeHandlers.getSize(); i += 1) {
|
||
this.midResizeHandlers.get(i).setVisible(visible);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Applies a predefined style to its handlers (which can be resizable style or non resizable style)
|
||
* @param {string} styleType
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.applyStyleToHandlers = function (styleType) {
|
||
var i;
|
||
for (i = 0; i < this.cornerResizeHandlers.getSize(); i += 1) {
|
||
this.cornerResizeHandlers.get(i)[styleType].applyStyle();
|
||
}
|
||
|
||
for (i = 0; i < this.midResizeHandlers.getSize(); i += 1) {
|
||
this.midResizeHandlers.get(i)[styleType].applyStyle();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Attaches events to this shape (currently mousedown, mouseup and click events).
|
||
* This method also instantiates the behaviors defined in the configuration options of the object,
|
||
* the behaviors instantiated are:
|
||
*
|
||
* - drag behavior
|
||
* - drop behavior
|
||
* - resize behavior
|
||
*
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.attachListeners = function () {
|
||
var $shape = $(this.html);
|
||
if (this.attachEvents && !this.canvas.readOnly) {
|
||
$shape.on("mousedown", this.onMouseDown(this));
|
||
$shape.on("mouseup", this.onMouseUp(this));
|
||
$shape.on("click", this.onClick(this));
|
||
this.updateBehaviors();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* @event mousedown
|
||
* Moused down callback fired when the user mouse downs on the `shape`
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
Shape.prototype.onMouseDown = function (shape) {
|
||
return function (e, ui) {
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event mouseup
|
||
* Moused up callback fired when the user mouse ups on the `shape`
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
Shape.prototype.onMouseUp = function (shape) {
|
||
return function (e, ui) {
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event click
|
||
* Click callback fired when the user clicks on the `shape`
|
||
* @param {PMUI.draw.Shape} shape
|
||
*/
|
||
Shape.prototype.onClick = function (shape) {
|
||
return function (e, ui) {
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Creates the HTML representation of the shape, besides calling the method `createHTML` of
|
||
* the method of its parent, it also adds the resize handlers to the DOM.
|
||
* @returns {HTMLElement}
|
||
*/
|
||
Shape.prototype.createHTML = function () {
|
||
var i;
|
||
|
||
// call the prototype's createHTML
|
||
Shape.superclass.prototype.createHTML.call(this);
|
||
|
||
// add the handlers
|
||
for (i = 0; i < this.cornerResizeHandlers.getSize(); i += 1) {
|
||
this.addResizeHandler(this.cornerResizeHandlers.get(i),
|
||
this.xCorners[i], this.yCorners[i]);
|
||
}
|
||
for (i = 0; i < this.midResizeHandlers.getSize(); i += 1) {
|
||
this.addResizeHandler(this.midResizeHandlers.get(i),
|
||
this.xMidPoints[i], this.yMidPoints[i]);
|
||
}
|
||
return this.html;
|
||
};
|
||
|
||
|
||
/**
|
||
* Returns true if this object is draggable
|
||
* @return {boolean}
|
||
*/
|
||
Shape.prototype.isDraggable = function () {
|
||
return this.drag &&
|
||
this.drag.type !== "NoDragBehavior";
|
||
};
|
||
|
||
/**
|
||
* Updates the behaviors of this shape (this method is called from `this.attachListeners`).
|
||
* This is the method that actually initializes jQueryUI's plugins (during the creation of the
|
||
* instance of this shapes, the shape's behaviors are initialized but the init that they do
|
||
* initialize jQuery's UI plugins is done through `[behavior].init`).
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.updateBehaviors = function () {
|
||
Shape.superclass.prototype.updateBehaviors.call(this);
|
||
if (this.drag) {
|
||
this.drag.attachDragBehavior(this);
|
||
}
|
||
if (this.resizeBehavior) {
|
||
this.resizeBehavior.init(this);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Adds a `resizeHandler` to the shape at `[x, y]`
|
||
* @param {PMUI.draw.ResizeHandler} resizeHandler
|
||
* @param {number} x
|
||
* @param {number} y
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.addResizeHandler = function (resizeHandler, x, y) {
|
||
if (!this.html) {
|
||
return;
|
||
}
|
||
//console.log(resizeHandler.getHTML());
|
||
this.html.appendChild(resizeHandler.getHTML());
|
||
|
||
resizeHandler.setPosition(x - Math.round(resizeHandler.width / 2) - 1,
|
||
y - Math.round(resizeHandler.height / 2) - 1);
|
||
//add resizable validations
|
||
if (this.isResizable()) {
|
||
resizeHandler.setCategory("resizable");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* Paints the shape performing the following actions:
|
||
*
|
||
* - Paints its resize handlers
|
||
* - Applies the predefined style according to the resize behavior it has
|
||
*
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.paint = function () {
|
||
var i,
|
||
styleToApply;
|
||
|
||
// // apply predefined style
|
||
// this.style.applyStyle();
|
||
|
||
for (i = 0; i < this.cornerResizeHandlers.getSize(); i += 1) {
|
||
this.cornerResizeHandlers.get(i).paint();
|
||
}
|
||
for (i = 0; i < this.midResizeHandlers.getSize(); i += 1) {
|
||
this.midResizeHandlers.get(i).paint();
|
||
}
|
||
|
||
// apply style to the handlers
|
||
if (this.resizeBehavior) {
|
||
styleToApply = this.resizeBehavior.type === "NoResizeBehavior" ?
|
||
"nonResizableStyle" : "resizableStyle";
|
||
this.applyStyleToHandlers(styleToApply);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
Shape.prototype.updateHTML = function () {
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Detaches `this` HTML from the DOM (also removing it from `canvas.customShapes` or `canvas.regularShapes`)
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.saveAndDestroy = function () {
|
||
// save the html but detach it from the DOM
|
||
this.html = $(this.html).detach()[0];
|
||
this.canvas.removeFromList(this);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Updates the dimensions of this shape according to the dimensions and
|
||
* positions of its children
|
||
* @param {number} newMargin Padding to be added when a children is near the edge
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.updateSize = function (newMargin) {
|
||
var children = this.children,
|
||
limits = children.getDimensionLimit(),
|
||
left = limits[3],
|
||
top = limits[0],
|
||
right = limits[1],
|
||
bottom = limits[2],
|
||
newLeft = this.getX(),
|
||
newTop = this.getY(),
|
||
newWidth = this.getWidth(),
|
||
newHeight = this.getHeight(),
|
||
margin,
|
||
diffX = 0,
|
||
diffY = 0,
|
||
positionShift = false,
|
||
dimensionIncrement = false;
|
||
|
||
if (newMargin !== "undefined") {
|
||
margin = newMargin;
|
||
} else {
|
||
margin = 15;
|
||
}
|
||
|
||
if (left < 0) {
|
||
diffX = margin - left;
|
||
positionShift = true;
|
||
this.oldX = this.x;
|
||
this.oldAbsoluteX = this.x;
|
||
this.oldY = this.y;
|
||
this.oldAbsoluteY = this.absoluteY;
|
||
}
|
||
|
||
if (top < 0) {
|
||
diffY = margin - top;
|
||
positionShift = true;
|
||
this.oldX = this.x;
|
||
this.oldAbsoluteX = this.x;
|
||
this.oldY = this.y;
|
||
this.oldAbsoluteY = this.absoluteY;
|
||
}
|
||
|
||
newLeft -= diffX;
|
||
newTop -= diffY;
|
||
newWidth += diffX;
|
||
newHeight += diffY;
|
||
|
||
if (right > this.width) {
|
||
newWidth += right - this.width + margin;
|
||
dimensionIncrement = true;
|
||
this.oldWidth = this.width;
|
||
}
|
||
if (bottom > this.height) {
|
||
newHeight += bottom - this.height + margin;
|
||
dimensionIncrement = true;
|
||
this.oldHeight = this.height;
|
||
}
|
||
|
||
// move the shape to the new coordinates
|
||
this.setPosition(newLeft, newTop);
|
||
|
||
// update the shape's dimension
|
||
this.setDimension(newWidth, newHeight);
|
||
|
||
// custom triggers
|
||
if (positionShift) {
|
||
this.changePosition(this.oldX, this.oldY,
|
||
this.absoluteX, this.absoluteY);
|
||
}
|
||
if (dimensionIncrement) {
|
||
this.changeSize(this.oldWidth, this.oldHeight);
|
||
}
|
||
|
||
// move the children
|
||
this.updateChildrenPosition(diffX, diffY);
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Applies the actual zoom scale to the corresponding shape
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.applyZoom = function () {
|
||
// var zoomFactor = this.canvas.getZoomFactor(),
|
||
// zoomIndex = this.canvas.getZoomPropertiesIndex();
|
||
|
||
this.refreshShape();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the dimension of this shape, it also updates the arrays `this.xCorners, this.yCorners, this.xMidPoints
|
||
* and this.yMidPoints`
|
||
* @param {number} width
|
||
* @param {number} height
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.setDimension = function (width, height) {
|
||
Shape.superclass.prototype.setDimension.call(this, width, height);
|
||
if (this.xCorners) {
|
||
this.xCorners = [0, Math.round(this.zoomWidth), Math.round(this.zoomWidth), 0];
|
||
this.yCorners = [0, 0, Math.round(this.zoomHeight), Math.round(this.zoomHeight)];
|
||
this.xMidPoints = [Math.round(this.zoomWidth / 2), Math.round(this.zoomWidth),
|
||
Math.round(this.zoomWidth / 2), 0];
|
||
this.yMidPoints = [0, Math.round(this.zoomHeight / 2), Math.round(this.zoomHeight),
|
||
Math.round(this.zoomHeight / 2)];
|
||
this.updateHandlers();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets some variables that store what changed during the process of changing the parent and also
|
||
* triggers `changeElement` using those variables.
|
||
*
|
||
* The variables saved in {@link PMUI.draw.Canvas#updatedElement} are:
|
||
*
|
||
* - x (old x and new x)
|
||
* - y (old y and new y)
|
||
* - absoluteX (old absoluteX and new absoluteX)
|
||
* - absoluteY (old absoluteY and new absoluteY)
|
||
* - parent (old parent and new parent)
|
||
*
|
||
* @param {number} oldX
|
||
* @param {number} oldY
|
||
* @param {number} oldAbsoluteX
|
||
* @param {number} oldAbsoluteY
|
||
* @param {Object} oldParent
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.changeParent = function (oldX, oldY, oldAbsoluteX, oldAbsoluteY, oldParent, canvas) {
|
||
var fields = [
|
||
{
|
||
"field": "x",
|
||
"oldVal": oldX,
|
||
"newVal": this.x
|
||
},
|
||
{
|
||
"field": "y",
|
||
"oldVal": oldY,
|
||
"newVal": this.y
|
||
},
|
||
{
|
||
"field": "absoluteX",
|
||
"oldVal": oldAbsoluteX,
|
||
"newVal": this.absoluteX
|
||
},
|
||
{
|
||
"field": "absoluteY",
|
||
"oldVal": oldAbsoluteY,
|
||
"newVal": this.absoluteY
|
||
},
|
||
{
|
||
"field": "parent",
|
||
"oldVal": oldParent,
|
||
"newVal": this.parent
|
||
}
|
||
];
|
||
canvas.updatedElement = {
|
||
"id": this.id,
|
||
"type": this.type,
|
||
"fields": fields,
|
||
"relatedObject": this
|
||
};
|
||
$(canvas.html).trigger("changeelement");
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets some variables that store what changed during the process of resizing and also
|
||
* triggers `changeElement` using those variables.
|
||
*
|
||
* The variables saved in {@link PMUI.draw.Canvas#updatedElement} are:
|
||
*
|
||
* - width (old width and new width)
|
||
* - height (old height and new height)
|
||
*
|
||
* @param {number} oldWidth
|
||
* @param {number} oldHeight
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.changeSize = function (oldWidth, oldHeight) {
|
||
var canvas = this.canvas,
|
||
fields = [
|
||
{
|
||
"field": "width",
|
||
"oldVal": oldWidth,
|
||
"newVal": this.width
|
||
},
|
||
{
|
||
"field": "height",
|
||
"oldVal": oldHeight,
|
||
"newVal": this.height
|
||
}
|
||
];
|
||
canvas.updatedElement = {
|
||
"id": this.id,
|
||
"type": this.type,
|
||
"fields": fields,
|
||
"relatedObject": this
|
||
};
|
||
$(canvas.html).trigger("changeelement");
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets some variables that store what changed during the process of changing its position and also
|
||
* triggers `changeElement` using those variables.
|
||
*
|
||
* The variables saved in {@link PMUI.draw.Canvas#updatedElement} are:
|
||
*
|
||
* - x (old x and new x)
|
||
* - y (old y and new y)
|
||
* - absoluteX (old absoluteX and new absoluteX)
|
||
* - absoluteY (old absoluteY and new absoluteY)
|
||
*
|
||
* @param {number} oldX
|
||
* @param {number} oldY
|
||
* @param {number} oldAbsoluteX
|
||
* @param {number} oldAbsoluteY
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.changePosition = function (oldX, oldY, oldAbsoluteX, oldAbsoluteY) {
|
||
var canvas = this.canvas,
|
||
fields = [
|
||
{
|
||
"field": "x",
|
||
"oldVal": oldX,
|
||
"newVal": this.x
|
||
},
|
||
{
|
||
"field": "y",
|
||
"oldVal": oldY,
|
||
"newVal": this.y
|
||
},
|
||
{
|
||
"field": "absoluteX",
|
||
"oldVal": oldAbsoluteX,
|
||
"newVal": this.absoluteX
|
||
},
|
||
{
|
||
"field": "absoluteY",
|
||
"oldVal": oldAbsoluteY,
|
||
"newVal": this.absoluteY
|
||
}
|
||
|
||
];
|
||
canvas.updatedElement = [{
|
||
"id": this.id,
|
||
"type": this.type,
|
||
"fields": fields,
|
||
"relatedObject": this
|
||
}];
|
||
$(canvas.html).trigger("changeelement");
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets whether the dimensions are fixed or not
|
||
* @param {boolean} fixed
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.setFixed = function (fixed) {
|
||
if (typeof fixed === "boolean") {
|
||
this.fixed = fixed;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Adds `value` to the z-index of the shape (considering the z-index of its parent), since a shape might have
|
||
* children, this method must increase the z-index of each child recursively.
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @param {number} value
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.fixZIndex = function (shape, value) {
|
||
|
||
var i,
|
||
anotherShape,
|
||
port,
|
||
srcShape,
|
||
destShape,
|
||
srcShapeZIndex,
|
||
destShapeZIndex,
|
||
parentZIndex;
|
||
|
||
parentZIndex = shape.parent.html.style.zIndex;
|
||
shape.setZOrder(
|
||
parseInt(parentZIndex, 10) + value + parseInt(shape.defaultZOrder, 10)
|
||
);
|
||
|
||
// fix children zIndex
|
||
for (i = 0; i < shape.children.getSize(); i += 1) {
|
||
anotherShape = shape.children.get(i);
|
||
anotherShape.fixZIndex(anotherShape, 0);
|
||
}
|
||
|
||
// fix connection zIndex
|
||
// only if it has ports
|
||
if (shape.ports) {
|
||
for (i = 0; i < shape.ports.getSize(); i += 1) {
|
||
port = shape.ports.get(i);
|
||
srcShape = port.connection.srcPort.parent;
|
||
destShape = port.connection.destPort.parent;
|
||
srcShapeZIndex = parseInt(srcShape.html.style.zIndex, 10);
|
||
destShapeZIndex = parseInt(destShape.html.style.zIndex, 10);
|
||
port.connection.style.addProperties({
|
||
zIndex: Math.max(srcShapeZIndex + 1, destShapeZIndex + 1)
|
||
});
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Increases the zIndex of this shape by Style.MAX_ZINDEX
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.increaseZIndex = function () {
|
||
this.fixZIndex(this, PMUI.util.Style.MAX_ZINDEX);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Decreases the zIndex of this shape back to normal
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.decreaseZIndex = function () {
|
||
this.fixZIndex(this, 0);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Increases the z-index of `shapes`'s ancestors by one
|
||
* @param shape
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.increaseParentZIndex = function (shape) {
|
||
if (shape.family !== "Canvas") {
|
||
shape.style.addProperties({
|
||
zIndex: parseInt(shape.html.style.zIndex, 10) + 1
|
||
});
|
||
shape.increaseParentZIndex(shape.parent);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Decreases the zIndex of `shapes`'s ancestors by one by one
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.decreaseParentZIndex = function (shape) {
|
||
if (shape && shape.family !== "Canvas") {
|
||
shape.style.addProperties({
|
||
zIndex: parseInt(shape.html.style.zIndex, 10) - 1
|
||
});
|
||
shape.decreaseParentZIndex(shape.parent);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the determined resize behavior to `this` by calling `this.resizeBehaviorFactory` (which creates or returns
|
||
* the instance according to `behavior`) and attaches the drag events to `this`.
|
||
* @param {String} behavior
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.setResizeBehavior = function (behavior) {
|
||
var factory = new PMUI.behavior.BehaviorFactory({
|
||
products: {
|
||
"regularresize": PMUI.behavior.RegularResizeBehavior,
|
||
"Resize": PMUI.behavior.RegularResizeBehavior,
|
||
"yes": PMUI.behavior.RegularResizeBehavior,
|
||
"resize": PMUI.behavior.RegularResizeBehavior,
|
||
"noresize": PMUI.behavior.NoResizeBehavior,
|
||
"NoResize": PMUI.behavior.NoResizeBehavior,
|
||
"no": PMUI.behavior.NoResizeBehavior
|
||
},
|
||
defaultProduct: "noresize"
|
||
});
|
||
this.resizeBehavior = factory.make(behavior);
|
||
if (this.html) {
|
||
this.resizeBehavior.init(this);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns whether the shape is resizable or not
|
||
* @return {boolean}
|
||
*/
|
||
Shape.prototype.isResizable = function () {
|
||
return this.resizeBehavior &&
|
||
this.resizeBehavior.type !== "NoResizeBehavior";
|
||
};
|
||
|
||
/**
|
||
* Updates the position and dimensions of the shape (useful when the parent of this shape
|
||
* has changed positions or dimensions).
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.refreshShape = function () {
|
||
this.setPosition(this.x, this.y)
|
||
.setDimension(this.width, this.height);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Abstract method intended to refresh the connections of a shapes
|
||
* @abstract
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.refreshConnections = function () {
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Updates the positions of the children of this shape recursively
|
||
* @param {boolean} onCommand
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.refreshChildrenPositions = function (onCommand) {
|
||
var i,
|
||
children = this.children,
|
||
child,
|
||
relatedShapes = [],
|
||
coordinates = [];
|
||
for (i = 0; i < children.getSize(); i += 1) {
|
||
child = children.get(i);
|
||
child.setPosition(child.getX(), child.getY());
|
||
if (onCommand) {
|
||
child.refreshConnections(false);
|
||
}
|
||
relatedShapes.push(child);
|
||
coordinates.push({
|
||
x: child.getX(),
|
||
y: child.getY()
|
||
});
|
||
child.refreshChildrenPositions(onCommand);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Fix connections ports on resize (a container must call this method on resize to reposition its
|
||
* ports on resize and the ports of its children)
|
||
* @param {boolean} resizing
|
||
* @param {boolean} root The currentShape is root?
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.fixConnectionsOnResize = function (resizing, root) {
|
||
|
||
var i,
|
||
port,
|
||
child,
|
||
connection,
|
||
zoomFactor = this.canvas.zoomFactor;
|
||
|
||
if (root) {
|
||
if (this.ports) {
|
||
// connections
|
||
for (i = 0; i < this.ports.getSize(); i += 1) {
|
||
port = this.ports.get(i);
|
||
connection = port.connection;
|
||
this.recalculatePortPosition(port);
|
||
|
||
connection.disconnect().connect();
|
||
if (!this.resizing) {
|
||
connection.setSegmentMoveHandlers();
|
||
connection.checkAndCreateIntersectionsWithAll();
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
if (this.ports) {
|
||
// connections
|
||
for (i = 0; i < this.ports.getSize(); i += 1) {
|
||
// for each port update its absolute position and
|
||
// repaint its connections
|
||
port = this.ports.get(i);
|
||
connection = port.connection;
|
||
port.setPosition(port.x, port.y);
|
||
|
||
connection.disconnect().connect();
|
||
if (!this.resizing) {
|
||
connection.setSegmentMoveHandlers();
|
||
connection.checkAndCreateIntersectionsWithAll();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// children
|
||
for (i = 0; i < this.children.getSize(); i += 1) {
|
||
child = this.children.get(i);
|
||
child.setPosition(child.x, child.y);
|
||
child.fixConnectionsOnResize(child.resizing, false);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Serializes this object.
|
||
*
|
||
* This method adds the following to the object retrieved from {@link PMUI.draw.BehavioralElement#stringify}:
|
||
*
|
||
* - resizeBehavior
|
||
* - resizeHandlers (as defined in the config options)
|
||
*
|
||
* @return {Object}
|
||
*/
|
||
Shape.prototype.stringify = function () {
|
||
var inheritedJSON = Shape.superclass.prototype.stringify.call(this),
|
||
type = (this.savedOptions.resizeHandlers &&
|
||
this.savedOptions.resizeHandlers.type) || 'Rectangle',
|
||
total = (this.savedOptions.resizeHandlers &&
|
||
this.savedOptions.resizeHandlers.total) || 4,
|
||
thisJSON = {
|
||
resizeBehavior: this.savedOptions.resizeBehavior,
|
||
resizeHandlers: {
|
||
type: type,
|
||
total: total
|
||
}
|
||
};
|
||
$.extend(true, inheritedJSON, thisJSON);
|
||
return inheritedJSON;
|
||
};
|
||
|
||
/**
|
||
* Sets the center of the shape
|
||
* @param {number} newCenter
|
||
* @throws {Error} parameter newCenter is not an instance of points
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.setCenter = function (newCenter) {
|
||
if (newCenter instanceof PMUI.util.Point) {
|
||
this.center = newCenter;
|
||
} else {
|
||
throw new Error("setCenter(): argument is not an instance of Point");
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the Parent of the shape (might also trigger the custom event change element if the parameter
|
||
* triggerChange is set to true)
|
||
* @chainable
|
||
* @param {PMUI.draw.Shape} newParent
|
||
* @param {boolean} triggerChange
|
||
*/
|
||
Shape.prototype.setParent = function (newParent, triggerChange) {
|
||
|
||
if (newParent) {
|
||
|
||
if (this.canvas && triggerChange) {
|
||
this.canvas.updatedElement = {
|
||
"id": this.id,
|
||
"type": this.type,
|
||
"fields": [
|
||
{
|
||
"field": "parent",
|
||
"oldVal": this.parent,
|
||
"newVal": newParent
|
||
}
|
||
]
|
||
};
|
||
$(this.canvas.html).trigger("changeelement");
|
||
}
|
||
this.parent = newParent;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the oldParent of the shape.
|
||
* @chainable
|
||
* @param {PMUI.draw.Shape} oldParent
|
||
*/
|
||
Shape.prototype.setOldParent = function (oldParent) {
|
||
this.oldParent = oldParent;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the center of the shape.
|
||
* @return {PMUI.util.Point}
|
||
*/
|
||
Shape.prototype.getCenter = function () {
|
||
return this.center;
|
||
};
|
||
|
||
/**
|
||
* Gets the parent of the shape.
|
||
* @return {PMUI.draw.Shape / PMUI.draw.Canvas}
|
||
*/
|
||
Shape.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
|
||
/**
|
||
* Gets the oldParent of the shape
|
||
* @return {PMUI.draw.Shape / PMUI.draw.Canvas}
|
||
*/
|
||
Shape.prototype.getOldParent = function () {
|
||
return this.oldParent;
|
||
};
|
||
|
||
/**
|
||
* Gets the handles IDs used to initialize jQueryUI's resizable plugin
|
||
* @return {Object}
|
||
*/
|
||
Shape.prototype.getHandlesIDs = function () {
|
||
var handlesObject = {},
|
||
i;
|
||
|
||
for (i = 0; i < this.midPointIdentifiers.length; i += 1) {
|
||
handlesObject[this.midPointIdentifiers[i]] = '#' +
|
||
this.midPointIdentifiers[i] + this.id +
|
||
'resizehandler';
|
||
}
|
||
for (i = 0; i < this.cornersIdentifiers.length; i += 1) {
|
||
handlesObject[this.cornersIdentifiers[i]] = '#' +
|
||
this.cornersIdentifiers[i] + this.id +
|
||
'resizehandler';
|
||
}
|
||
return handlesObject;
|
||
};
|
||
|
||
/**
|
||
* Applies all behavior in a Shape
|
||
* @chainable
|
||
*/
|
||
Shape.prototype.applyBehaviors = function () {
|
||
if (this.html) {
|
||
if (this.drag) {
|
||
this.drag.attachDragBehavior(this);
|
||
}
|
||
if (this.drop) {
|
||
this.drop.attachDropBehavior(this);
|
||
}
|
||
if (this.resizeBehavior) {
|
||
this.resizeBehavior.init(this);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Shape', Shape);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Shape;
|
||
}
|
||
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Label
|
||
* Creates a an object that can in order to illustrate text in the HTML it can
|
||
* be inside a shape or by its own directly in the canvas
|
||
*
|
||
* //e.g.
|
||
* var label = new PMUI.draw.Label({
|
||
* //message that the label will display
|
||
* message: "This is a label",
|
||
* //orientation of the text, can be vertical or horizontal
|
||
* orientation: "horizontal",
|
||
* //font-family
|
||
* fontFamily: "arial",
|
||
* //size of the label object not the text
|
||
* size: 80,
|
||
* //position where it will be located relative to its
|
||
* //container
|
||
* position: {
|
||
* //location can be center, top, bottom among others,
|
||
* //relative to its container
|
||
* location: "center",
|
||
* //How many pixels in the x coordinate and y coordinate
|
||
* //we want to move it from its location
|
||
* diffX: 2,
|
||
* diffY: -1
|
||
* },
|
||
* //option that determines if the label should update its
|
||
* //parent size when it grows
|
||
* updateParent: false,
|
||
* //label's parent
|
||
* parent: canvas
|
||
*
|
||
* });
|
||
* @extends PMUI.draw.Shape
|
||
*
|
||
* @constructor
|
||
* Creates an instance of the class
|
||
* @param {Object} options configuration options for the label object
|
||
* @cfg {String} [message=""] Message to be displayed
|
||
* @cfg {String} [orientation="horizontal"] Orientation of the text, can be
|
||
* vertical or horizontal
|
||
* @cfg {String} [fontFamily="arial"] Font family we want the message to be
|
||
* displayed with
|
||
* @cfg {number} [size=0] Size of the label object
|
||
* @cfg {Object} [position={
|
||
* location: "none",
|
||
* diffX: 0,
|
||
* diffY: 0
|
||
* }] Location where we want the label to be positioned relative to its parent
|
||
* @cfg {boolean} [updateParent=false] Determines whether the parent's size
|
||
* should be updated when the label increases its size
|
||
* @cfg {Object} [parent=null] Label's parent
|
||
*/
|
||
var Label = function (options) {
|
||
Label.superclass.call(this, options);
|
||
/**
|
||
* The percentage of this label respect to the width of the shape
|
||
* in the range(0, 1)
|
||
* @property {number}
|
||
*/
|
||
this.xPercentage = 0;
|
||
/**
|
||
* The percentage of this label respect to the height of the shape
|
||
* in the range(0, 1)
|
||
* @property {number}
|
||
*/
|
||
this.yPercentage = 0;
|
||
/**
|
||
* Message that the label will display
|
||
* @property {String}
|
||
*/
|
||
this.message = "";
|
||
/**
|
||
* Orientation of the label
|
||
* @property {String}
|
||
*/
|
||
this.orientation = "";
|
||
/**
|
||
* HTML span that holds the text display
|
||
* @property {HTMLElement}
|
||
*/
|
||
this.text = null;
|
||
/**
|
||
* Determines whether a label's parent should be updated when a label
|
||
* increases its size
|
||
* @property {boolean}
|
||
*/
|
||
this.updateParent = false;
|
||
/**
|
||
* Determines the type of overflow this label should have
|
||
* @property {boolean}
|
||
*/
|
||
this.overflow = false;
|
||
/**
|
||
* XXX
|
||
* @property {boolean}
|
||
*/
|
||
this.onFocus = false;
|
||
/**
|
||
* Determines the location relative to its parent where this label will be
|
||
* positioned
|
||
* @property {String}
|
||
*/
|
||
this.location = "";
|
||
/**
|
||
* x direction pixels that the label will be moved from its location
|
||
* @property {number}
|
||
*/
|
||
this.diffX = 0;
|
||
/**
|
||
* y direction pixels that the label will be moved from its location
|
||
* @property {number}
|
||
*/
|
||
this.diffY = 0;
|
||
/**
|
||
* Determines the font-size to be used in each zoom scale
|
||
* @property {Array}
|
||
*/
|
||
this.fontSizeOnZoom = [];
|
||
/**
|
||
* The font-size that this label will use to display the message
|
||
* @property {number}
|
||
*/
|
||
this.fontSize = 0;
|
||
/**
|
||
* html text field for text editing
|
||
* @property {HTMLElement}
|
||
*/
|
||
this.textField = null;
|
||
|
||
/**
|
||
* Initial width
|
||
* @property {number}
|
||
*/
|
||
this.initialWidth = null;
|
||
|
||
/**
|
||
* Min Height
|
||
* @property {number}
|
||
*/
|
||
this.minHeight = null;
|
||
|
||
|
||
Label.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Shape', Label);
|
||
/**
|
||
* Type of all label instances
|
||
* @property {String}
|
||
*/
|
||
Label.prototype.type = "Label";
|
||
/**
|
||
* Line height to be considered in the label's message
|
||
* @type {number}
|
||
*/
|
||
Label.prototype.lineHeight = 20;
|
||
|
||
|
||
/**
|
||
* Initializer of the object will all the given configuration options
|
||
* @param {Object} options
|
||
*/
|
||
Label.prototype.init = function (options) {
|
||
var defaults = {
|
||
message: "New Label",
|
||
orientation: "horizontal",
|
||
fontFamily: "arial",
|
||
size: 0,
|
||
position: {
|
||
location: "none",
|
||
diffX: 0,
|
||
diffY: 0
|
||
},
|
||
overflow: false,
|
||
updateParent: false,
|
||
parent: null
|
||
};
|
||
this.fontSizeOnZoom = [6, 8, 10, 13, 15];
|
||
$.extend(true, defaults, options);
|
||
this.setMessage(defaults.message)
|
||
.setOverflow(defaults.overflow)
|
||
.setMinHeight(defaults.minHeight)
|
||
.setUpdateParent(defaults.updateParent)
|
||
.setOrientation(defaults.orientation)
|
||
.setFontFamily(defaults.fontFamily)
|
||
.setFontSize(defaults.size)
|
||
.setParent(defaults.parent)
|
||
.setLabelPosition(defaults.position.location, defaults.position.diffX,
|
||
defaults.position.diffY);
|
||
|
||
};
|
||
/**
|
||
* Attach the corresponding listeners to this label
|
||
* @chainable
|
||
*/
|
||
Label.prototype.attachListeners = function () {
|
||
var $label = $(this.html),
|
||
$label = $(this.text);
|
||
var $textField = $(this.textField);
|
||
if (!this.html) {
|
||
return this;
|
||
}
|
||
Label.superclass.prototype.attachListeners.call(this);
|
||
if (!this.getCanvas().readOnly) {
|
||
$($textField).mousedown (function (e) {
|
||
e.stopPropagation();
|
||
});
|
||
$($textField).mouseup (function (e) {
|
||
e.stopPropagation();
|
||
});
|
||
$($textField).click (function (e) {
|
||
e.stopPropagation();
|
||
});
|
||
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the HTML of the label, the input text and the span for displaying the
|
||
* message
|
||
* @return {HTMLElement}
|
||
*/
|
||
Label.prototype.createHTML = function () {
|
||
Label.superclass.prototype.createHTML.call(this);
|
||
this.html.style.textAlign = "center";
|
||
this.html.style.align = "center";
|
||
this.html.style.fontFamily = this.fontFamily;
|
||
this.html.style.fontSize = this.fontSize + "pt";
|
||
this.textField = document.createElement("input");
|
||
this.textField.style.width = "200px";
|
||
this.textField.style.position = "absolute";
|
||
this.textField.style.display = "none";
|
||
this.text = document.createElement("span");
|
||
this.text.style.width = "auto";
|
||
this.text.style.height = "auto";
|
||
this.text.style.lineHeight = this.lineHeight * this.canvas.zoomFactor + "px";
|
||
this.text.innerHTML = this.message;
|
||
this.html.appendChild(this.text);
|
||
this.html.appendChild(this.textField);
|
||
this.html.style.zIndex = '120';
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Displays the style of the label and adds the corresponding classes for
|
||
* rotation
|
||
* @chainable
|
||
*/
|
||
Label.prototype.paint = function () {
|
||
var $label = $(this.html);
|
||
|
||
this.text.style.lineHeight = this.lineHeight * this.canvas.zoomFactor + "px";
|
||
this.textField.value = this.message;
|
||
this.text.innerHTML = this.message;
|
||
|
||
this.html.style.verticalAlign = "middle";
|
||
if (this.overflow) {
|
||
this.html.style.overflow = "hidden";
|
||
} else {
|
||
this.html.style.overflow = "none";
|
||
}
|
||
|
||
this.displayText(true);
|
||
if (this.orientation === "vertical") {
|
||
$label.addClass('rotateText');
|
||
} else {
|
||
$label.removeClass('rotateText');
|
||
}
|
||
if (this.parent.onUpdateLabel) {
|
||
this.parent.onUpdateLabel();
|
||
}
|
||
|
||
return this;
|
||
|
||
};
|
||
/**
|
||
* Displays the label's message in its current orientation or the input text
|
||
* @param {boolean} display true if we want to display the label's message or
|
||
* false for the input text
|
||
* @chainable
|
||
*/
|
||
Label.prototype.displayText = function (display, e) {
|
||
var y1 = 0,
|
||
y2 = 0,
|
||
diffY;
|
||
if (display) {
|
||
this.text.style.display = "block";
|
||
this.textField.style.display = "none";
|
||
if (this.orientation === "vertical") {
|
||
this.textField.style.left = "0px";
|
||
}
|
||
} else {
|
||
this.textField.style.display = "block";
|
||
if (this.orientation === "vertical") {
|
||
this.textField.style.left = this.width / 2 + "px";
|
||
if (e) {
|
||
y1 = this.canvas.getTopScroll() + this.parent.getAbsoluteY() + this.parent.getZoomHeight() / 2;
|
||
y2 = e.pageY - this.canvas.getZoomY();
|
||
diffY = (y2 - y1);
|
||
this.textField.style.top = diffY + "px";
|
||
}
|
||
}
|
||
this.text.style.display = "none";
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the message of this label
|
||
* @param {String} newMessage
|
||
* @chainable
|
||
*/
|
||
Label.prototype.setMessage = function (newMessage) {
|
||
this.message = newMessage;
|
||
if (this.text) {
|
||
this.text.innerHTML = this.message;
|
||
this.textField.value = this.message;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Retrieves the message that this label is displaying
|
||
* @return {String}
|
||
*/
|
||
Label.prototype.getMessage = function () {
|
||
return this.message;
|
||
};
|
||
/**
|
||
* Retrieves the message that this label is displaying
|
||
* @return {String}
|
||
*/
|
||
Label.prototype.setMinHeight = function (minHeight) {
|
||
this.minHeight = minHeight;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the orientation of the text
|
||
* @param {String} newOrientation It can be vertical or horizontal by default
|
||
* @chainable
|
||
*/
|
||
Label.prototype.setOrientation = function (newOrientation) {
|
||
var $label;
|
||
this.orientation = newOrientation;
|
||
if (!this.html) {
|
||
return this;
|
||
}
|
||
$label = $(this.html);
|
||
if (newOrientation === "vertical") {
|
||
$label.addClass("rotateText");
|
||
} else {
|
||
$label.removeClass("rotateText");
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Retrieves the orientation of this label's text
|
||
* @return {String}
|
||
*/
|
||
Label.prototype.getOrientation = function () {
|
||
return this.orientation;
|
||
};
|
||
/**
|
||
* Sets the font family of this label's displayed text
|
||
* @param {String} newFontFamily
|
||
* @chainable
|
||
*/
|
||
Label.prototype.setFontFamily = function (newFontFamily) {
|
||
this.fontFamily = newFontFamily;
|
||
if (this.html) {
|
||
this.html.style.fontFamily = this.fontFamily;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the font-size of this label's displayed text
|
||
* @param {String} newFontSize
|
||
* @chainable
|
||
*/
|
||
Label.prototype.setFontSize = function (newFontSize) {
|
||
if (newFontSize === 0) {
|
||
this.fontSize = this.getZoomFontSize();
|
||
} else {
|
||
this.fontSize = newFontSize;
|
||
}
|
||
if (this.html) {
|
||
this.html.style.fontSize = this.fontSize + "pt";
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the property to determine if a label should update its parent
|
||
* @param {boolean} newUpdateParent
|
||
* @chainable
|
||
*/
|
||
Label.prototype.setUpdateParent = function (newUpdateParent) {
|
||
this.updateParent = newUpdateParent;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the overflow property of this label
|
||
* @param {boolean} newOverflow
|
||
* @chainable
|
||
*/
|
||
Label.prototype.setOverflow = function (newOverflow) {
|
||
this.overflow = newOverflow;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the position of the label regarding its parent, considering the location
|
||
* and x and y differentials
|
||
* @param {String} position location where we want to put the label relative to,
|
||
* its parent, it can be top-left, top, top-right, center-left, center,
|
||
* center-right, bottom-left, bottom, bottom-right
|
||
* @param {number} diffX x coordinate pixels to move from its location
|
||
* @param {number} diffY y coordinate pixels to move from its location
|
||
* @chainable
|
||
*/
|
||
Label.prototype.setLabelPosition = function (position, diffX, diffY) {
|
||
var x,
|
||
y,
|
||
i,
|
||
width = this.zoomWidth,
|
||
height = this.zoomHeight,
|
||
parent = this.parent,
|
||
parentWidth,
|
||
parentHeight,
|
||
zoomFactor = this.canvas.zoomFactor,
|
||
bottomHeightFactor = 4 * zoomFactor,
|
||
positionString = [
|
||
'top-left',
|
||
'top',
|
||
'top-right',
|
||
'center-left',
|
||
'center',
|
||
'center-right',
|
||
'bottom-left',
|
||
'bottom',
|
||
'bottom-right'
|
||
],
|
||
orientation,
|
||
orientationIndex = (this.orientation === "vertical") ? 1 : 0,
|
||
positionCoordinates;
|
||
if (!position || position === "") {
|
||
position = "top-left";
|
||
}
|
||
if (diffX === undefined || diffX === null) {
|
||
diffX = 0;
|
||
}
|
||
if (diffY === undefined || diffY === null) {
|
||
diffY = 0;
|
||
}
|
||
if (parent && parent.family !== "Canvas") {
|
||
parentWidth = parent.getZoomWidth();
|
||
parentHeight = parent.getZoomHeight();
|
||
orientation = [
|
||
{x: width / 2, y: 0},
|
||
{x: 0, y: height / 2}
|
||
];
|
||
positionCoordinates = [
|
||
{
|
||
x: -width / 2,
|
||
y: 0
|
||
},
|
||
{
|
||
x: parentWidth / 2 - width / 2,
|
||
y: 0
|
||
},
|
||
{
|
||
x: parentWidth - width / 2,
|
||
y: 0
|
||
},
|
||
{
|
||
x: -width / 2,
|
||
y: parentHeight / 2 - height / 2
|
||
},
|
||
{
|
||
// Changed width by this.zoomWidth and Height for apply zoom by canvas
|
||
x: parentWidth / 2 - this.zoomWidth / 2,
|
||
y: parentHeight / 2 - this.zoomHeight / 2
|
||
},
|
||
{
|
||
x: parentWidth - width,
|
||
y: parentHeight / 2 - height / 2
|
||
},
|
||
{
|
||
x: -width / 2,
|
||
y: parentHeight - bottomHeightFactor
|
||
},
|
||
{
|
||
x: parentWidth / 2 - width / 2,
|
||
y: parentHeight - bottomHeightFactor
|
||
},
|
||
{
|
||
x: parentWidth - width / 2,
|
||
y: parentHeight - bottomHeightFactor
|
||
}
|
||
];
|
||
for (i = 0; i < 9; i += 1) {
|
||
if (position === positionString[i]) {
|
||
this.setPosition(
|
||
positionCoordinates[i].x / zoomFactor + diffX,
|
||
positionCoordinates[i].y / zoomFactor + diffY
|
||
);
|
||
break;
|
||
}
|
||
}
|
||
|
||
}
|
||
this.location = position;
|
||
this.diffX = diffX;
|
||
this.diffY = diffY;
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Hides the span showing the label's message and display the input text ready
|
||
* to be edited
|
||
* @chainable
|
||
*/
|
||
Label.prototype.getFocus = function (e) {
|
||
var $textField = $(this.textField);
|
||
this.displayText(false, e);
|
||
this.canvas.currentLabel = this;
|
||
$($textField).select();
|
||
this.onFocus = true;
|
||
$label = $(this.html);
|
||
$label.removeClass("rotateText");
|
||
if (this.parent.corona) {
|
||
this.canvas.hideAllCoronas();
|
||
this.canvas.cancelConnect();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Hides the input text and display the label's message, and if the message's
|
||
* changed, then it executes the editlabel command
|
||
* @chainable
|
||
*/
|
||
Label.prototype.loseFocus = function () {
|
||
var command;
|
||
this.canvas.currentLabel = null;
|
||
if (this.textField.value !== this.message) {
|
||
command = new PMUI.command.CommandEditLabel(this, this.textField.value);
|
||
command.execute();
|
||
this.canvas.commandStack.add(command);
|
||
this.setLabelPosition(this.location, this.diffX, this.diffY);
|
||
}
|
||
this.paint();
|
||
this.onFocus = false;
|
||
if (this.orientation === "vertical") {
|
||
$label = $(this.html);
|
||
$label.addClass("rotateText");
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* On Click handler, used to stop propagation when a label is being edited or
|
||
* its parent is the canvas
|
||
* @param {PMUI.draw.Label} label
|
||
* @return {Function}
|
||
*/
|
||
Label.prototype.onClick = function (label) {
|
||
return function (e, ui) {
|
||
|
||
if (label.parent.family === "Canvas") {
|
||
e.stopPropagation();
|
||
}
|
||
if (label.onFocus) {
|
||
e.stopPropagation();
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* Double Click handler, used in order for this label to get focus and being
|
||
* edited
|
||
* @param {PMUI.draw.Label} label
|
||
* @return {Function}
|
||
*/
|
||
Label.prototype.onDblClick = function (label) {
|
||
return function (e, ui) {
|
||
var canvas = label.getCanvas(),
|
||
$label = $(label.html);
|
||
if (canvas.currentLabel) {
|
||
canvas.currentLabel.loseFocus();
|
||
}
|
||
label.getFocus(e);
|
||
e.stopPropagation();
|
||
//e.preventDefault();
|
||
};
|
||
};
|
||
/**
|
||
* Returns the font-size according to the current zoom scale
|
||
* @return {number}
|
||
*/
|
||
Label.prototype.getZoomFontSize = function () {
|
||
var canvas = this.canvas;
|
||
this.fontSize = this.fontSizeOnZoom[canvas.zoomPropertiesIndex];
|
||
return this.fontSize;
|
||
};
|
||
/**
|
||
* Parse the messages in words length.
|
||
* It returns an array with the length of all the words in the message
|
||
* @return {Array}
|
||
*/
|
||
Label.prototype.parseMessage = function () {
|
||
var i,
|
||
start = 0,
|
||
result = [],
|
||
word;
|
||
while (this.message.charAt(start) === ' ') {
|
||
start += 1;
|
||
}
|
||
word = 0;
|
||
for (i = start; i < this.message.length; i += 1) {
|
||
|
||
if (this.message.charAt(i) === ' ') {
|
||
result.push(word);
|
||
word = 0;
|
||
} else {
|
||
word += 1;
|
||
}
|
||
}
|
||
result.push(word);
|
||
return result;
|
||
};
|
||
/**
|
||
* Updates the dimension of the label, according to its message, and if the
|
||
* updateParent property is true then it will call the corresponding method to
|
||
* update its parent according to the label's size
|
||
* @chainable
|
||
*/
|
||
Label.prototype.updateDimension = function (firstTime) {
|
||
var divWidth = this.width || $(this.text).width(),
|
||
newWidth,
|
||
newHeight;
|
||
divWidth = (this.orientation === "vertical") ? this.parent.height : this.zoomWidth;
|
||
if (divWidth === this.parent.width) {
|
||
divWidth = divWidth * 0.9;
|
||
}
|
||
if (divWidth < 10) {
|
||
newWidth = this.parent.getWidth() * 0.9;
|
||
this.initialWidth = this.parent.getWidth() * 0.9;
|
||
} else {
|
||
newWidth = divWidth;
|
||
}
|
||
|
||
newHeight = $(this.text).height();
|
||
|
||
|
||
// Old code for this part
|
||
this.setDimension(newWidth / this.canvas.zoomFactor,
|
||
newHeight / this.canvas.zoomFactor);
|
||
|
||
if (this.updateParent) {
|
||
this.updateParentDimension();
|
||
}
|
||
this.setLabelPosition(this.location, this.diffX, this.diffY);
|
||
this.width = newWidth;
|
||
return this;
|
||
|
||
};
|
||
/**
|
||
* Apply all properties necessary for this label in a given zoom scale
|
||
* @chainable
|
||
*/
|
||
Label.prototype.applyZoom = function () {
|
||
var canvas = this.canvas;
|
||
this.setFontSize(0);
|
||
this.updateDimension();
|
||
return this;
|
||
};
|
||
/**
|
||
* Calls the method to update the label's parent dimension according to the
|
||
* label's orientation
|
||
* @chainable
|
||
*/
|
||
Label.prototype.updateParentDimension = function () {
|
||
|
||
if (this.orientation === "vertical") {
|
||
this.updateVertically();
|
||
} else {
|
||
this.updateHorizontally();
|
||
}
|
||
if (this.parent.html) {
|
||
this.parent.paint();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Updates its parent height according to the size of the label
|
||
* @chainable
|
||
*/
|
||
Label.prototype.updateVertically = function () {
|
||
var margin = 5,
|
||
parent = this.parent,
|
||
labelWidth = this.zoomWidth,
|
||
newHeight,
|
||
zoomFactor = this.canvas.zoomFactor;
|
||
|
||
if (this.minHeight || this.maxHeight) {
|
||
if (this.zoomHeight < this.maxHeight && this.zoomHeight > this.minHeight)
|
||
newHeight = this.zoomHeight;
|
||
if (this.zoomHeight > this.maxHeight)
|
||
newHeight = this.maxHeight;
|
||
if (this.zoomHeight < this.minHeight)
|
||
newHeight = this.minHeight;
|
||
if (this.zoomHeight > this.minHeight)
|
||
newHeight = this.zoomHeight;
|
||
}
|
||
else {
|
||
newHeight = this.zoomHeight;
|
||
}
|
||
parent.setDimension(parent.width, newHeight / zoomFactor);
|
||
parent.updateChildrenPosition(0, 0);
|
||
parent.refreshConnections();
|
||
this.setLabelPosition(this.location, this.diffX, this.diffY);
|
||
return this;
|
||
};
|
||
/**
|
||
* Updates its parent width and height according to the new label's dimension
|
||
* @chainable
|
||
*/
|
||
Label.prototype.updateHorizontally = function () {
|
||
var margin = 5,
|
||
parent = this.parent,
|
||
labelWidth = this.zoomWidth,
|
||
labelHeight = this.zoomHeight,
|
||
newWidth,
|
||
newHeight,
|
||
zoomFactor = this.canvas.zoomFactor;
|
||
if (labelWidth > parent.zoomWidth - margin * 2) {
|
||
newWidth = labelWidth + margin * 2;
|
||
} else {
|
||
newWidth = parent.zoomWidth;
|
||
}
|
||
if (labelHeight > parent.zoomHeight - margin * 2) {
|
||
newHeight = labelHeight + margin * 2;
|
||
} else {
|
||
newHeight = parent.zoomHeight;
|
||
}
|
||
parent.refreshConnections();
|
||
this.setLabelPosition(this.location, this.diffX, this.diffY);
|
||
return this;
|
||
};
|
||
/**
|
||
* Serializes this object
|
||
* @return {Object}
|
||
*/
|
||
Label.prototype.stringify = function () {
|
||
// TODO: USE CLASS STYLE IN THE METHODS OF THIS CLASS
|
||
// TODO: COMPLETE THE JSON
|
||
/**
|
||
* inheritedJSON = {
|
||
* id: #
|
||
* x: #,
|
||
* y: #,
|
||
* width: #,
|
||
* height: #
|
||
* }
|
||
* @property {Object}
|
||
*/
|
||
var inheritedJSON = {},
|
||
thisJSON = {
|
||
id: this.getID(),
|
||
message: this.getMessage(),
|
||
orientation: this.getOrientation(),
|
||
position: {
|
||
location: this.location,
|
||
diffX: this.diffX,
|
||
diffY: this.diffY
|
||
}
|
||
};
|
||
$.extend(true, inheritedJSON, thisJSON);
|
||
return inheritedJSON;
|
||
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Label', Label);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Label;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.CustomShape
|
||
* This is a custom shape, where there can be applied styles, sprites and
|
||
* decoration, it can have connections associated to it by ports, different
|
||
* layers and labels as well
|
||
*
|
||
* //e.g.
|
||
* var customShape = new PMUI.draw.CustomShape({
|
||
* //Determines whether the shape will be connected only in its
|
||
* //middle points
|
||
* connectAtMiddlePoints : true,
|
||
* //The layers that will be instantiated with this shape
|
||
* layers: [
|
||
* {
|
||
* {
|
||
* layerName : "first-layer",
|
||
* priority: 2,
|
||
* visible: true,
|
||
* style: {
|
||
* cssClasses: ['bpmn_zoom']
|
||
* },
|
||
* zoomSprites : ['img_50_start',
|
||
* 'img_75_start', 'img_100_start',
|
||
* 'img_125_start', 'img_150_start']
|
||
* }, {
|
||
* layerName: "second-layer",
|
||
* priority: 3,
|
||
* visible: true
|
||
* }
|
||
*
|
||
* ],
|
||
* //Labels that belong to this shape
|
||
* labels : [
|
||
* {
|
||
* message: "this is one label",
|
||
* position: {
|
||
* location : "bottom",
|
||
* diffX: 0,
|
||
* diffY: 5
|
||
* }
|
||
* }
|
||
* ],
|
||
* //The type of connections that are made with this shape,
|
||
* //Each type differs of one another for the type of lines
|
||
* //used in the connection
|
||
* connectionType: "regular"
|
||
*
|
||
* });
|
||
*
|
||
* @extends PMUI.draw.Shape
|
||
*
|
||
* @constructor
|
||
* Creates an instance of a CustomShape
|
||
* @param {Object} options configuration options used in a custom shape
|
||
* @cfg {Boolean} [connectAtMiddlePoints=true] Determines whether shape's,
|
||
* connections should be created only in the middle points of its sides
|
||
* @cfg {Array} [layers=[]] Configuration options of all layers that will be,
|
||
* instantiated with this shape
|
||
* @cfg {Array} [labels=[]] Configuration options of all labels that will be
|
||
* instantiated with this shape
|
||
* @cfg {String} [connectionType="regular"] Type of lines that will be used in
|
||
* all connections involving this shape
|
||
*/
|
||
var CustomShape = function (options) {
|
||
/**
|
||
* List of all the layers associated to this shape
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.layers = new PMUI.util.ArrayList();
|
||
|
||
CustomShape.superclass.call(this, options);
|
||
/**
|
||
* List of all the ports associated to this shape
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.ports = new PMUI.util.ArrayList();
|
||
|
||
/**
|
||
* List of all the labels associated to this shape
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.labels = new PMUI.util.ArrayList();
|
||
/**
|
||
* List of all the zoom properties in different zoom scales
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.zoomProperties = new PMUI.util.ArrayList();
|
||
|
||
/**
|
||
* Inner figure for drawing connection limits
|
||
* @property {Array}
|
||
*/
|
||
this.limits = [0, 0, 0, 0];
|
||
/**
|
||
* Border to be added to determine the new position of the port
|
||
* @property {Array}
|
||
*/
|
||
this.border = [
|
||
{x: 0, y: 0},
|
||
{x: 0, y: 0},
|
||
{x: 0, y: 0},
|
||
{x: 0, y: 0}
|
||
];
|
||
/**
|
||
* Determines which type of drag behavior should be assigned
|
||
* @property {number}
|
||
*/
|
||
this.dragType = this.CANCEL;
|
||
/**
|
||
* Reference to the point where a connection drag is being started
|
||
* @property {PMUI.util.Point}
|
||
*/
|
||
this.startConnectionPoint = null;
|
||
/**
|
||
* if set to true, a port will only be added at its middle points
|
||
* @property {Boolean}
|
||
*/
|
||
this.connectAtMiddlePoints = null;
|
||
/**
|
||
* Auxiliary property for saving the previous x coordinate in the dragging
|
||
* procedure for multiple drag
|
||
* @property {Number}
|
||
*/
|
||
this.previousXDragPosition = 0;
|
||
/**
|
||
* Auxiliary property for saving the previous y coordinate in the dragging
|
||
* procedure for multiple drag
|
||
* @property {Number}
|
||
*/
|
||
this.previousYDragPosition = 0;
|
||
/**
|
||
* The type of lines for connections made with this shape
|
||
* @property {String}
|
||
*/
|
||
this.connectionType = null;
|
||
// init the custom shape
|
||
CustomShape.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Shape', CustomShape);
|
||
/**
|
||
* Type the instances of this class
|
||
* @property {String}
|
||
*/
|
||
CustomShape.prototype.type = "CustomShape";
|
||
/**
|
||
* Family where this class and all its subclasses belong
|
||
* @property {String}
|
||
* @readonly
|
||
*/
|
||
CustomShape.prototype.family = "CustomShape";
|
||
/**
|
||
* Reference to a drop behaviors for containers
|
||
* @property {PMUI.behavior.ContainerDropBehavior}
|
||
*/
|
||
CustomShape.prototype.containerDropBehavior = null;
|
||
/**
|
||
* Reference to a drop behavior that allows us to make connections
|
||
* @property {PMUI.behavior.ConnectionDropBehavior}
|
||
*/
|
||
CustomShape.prototype.connectionDropBehavior = null;
|
||
/**
|
||
* Reference to a drop behavior that has no acceptable droppables
|
||
* @property {PMUI.behavior.NoDropBehavior}
|
||
*/
|
||
CustomShape.prototype.noDropBehavior = null;
|
||
/**
|
||
* Constant that represents that a drag behavior for making connections should
|
||
* be used
|
||
* @property {Number}
|
||
*/
|
||
CustomShape.prototype.CONNECT = 1;
|
||
/**
|
||
* Constant that represents that a drag behavior for moving the shape should be
|
||
* used
|
||
* @property {Number}
|
||
*/
|
||
CustomShape.prototype.DRAG = 2;
|
||
/**
|
||
* Constant that represents that no drag behavior should be used
|
||
* @property {Number}
|
||
*/
|
||
CustomShape.prototype.CANCEL = 0;
|
||
|
||
/**
|
||
* Initializes the basic attributes for the custom shape, and also the
|
||
* particular objects the shape needs to instantiate
|
||
* //TODO Base limits on zoom
|
||
* @param options
|
||
*/
|
||
CustomShape.prototype.init = function (options) {
|
||
|
||
var defaults = {
|
||
connectAtMiddlePoints: true,
|
||
layers: [],
|
||
labels: [],
|
||
connectionType: "regular",
|
||
drag: "customshapedrag"
|
||
},
|
||
i;
|
||
|
||
// init the object with NO configurable options
|
||
this.limits = [5, 5, 5, 5, 5];
|
||
this.setStartConnectionPoint(new PMUI.util.Point(0, 0));
|
||
|
||
// init the object with configurable options
|
||
$.extend(true, defaults, options);
|
||
for (i = 0; i < defaults.layers.length; i += 1) {
|
||
this.createLayer(defaults.layers[i]);
|
||
}
|
||
for (i = 0; i < defaults.labels.length; i += 1) {
|
||
this.createLabel(defaults.labels[i]);
|
||
}
|
||
this.setConnectAtMiddlePoints(defaults.connectAtMiddlePoints)
|
||
.setConnectionType(defaults.connectionType);
|
||
};
|
||
/**
|
||
* Creates a layer given its configuration options
|
||
* @param {Object} options configuration options
|
||
* @return {PMUI.draw.Layer}
|
||
*/
|
||
CustomShape.prototype.createLayer = function (options) {
|
||
|
||
var layer;
|
||
options.parent = this;
|
||
layer = new PMUI.draw.Layer(options);
|
||
this.addLayer(layer);
|
||
return layer;
|
||
};
|
||
/**
|
||
* Creates a label given its configuration options
|
||
* @param {Object} options configuration options for instantiating a label
|
||
* @return {PMUI.draw.Label}
|
||
*/
|
||
CustomShape.prototype.createLabel = function (options) {
|
||
var label;
|
||
options.canvas = this.canvas;
|
||
options.parent = this;
|
||
if (options.width === 0) {
|
||
options.width = this.width * 0.9;
|
||
}
|
||
label = new PMUI.draw.Label(options);
|
||
this.addLabel(label);
|
||
return label;
|
||
};
|
||
|
||
/**
|
||
* Adds a label to the array of labels and also appends its html
|
||
* @param {PMUI.draw.Label} label
|
||
*/
|
||
CustomShape.prototype.addLabel = function (label) {
|
||
if (this.html) {
|
||
//so we just append it to the parent
|
||
label.parent = this;
|
||
this.html.appendChild(label.getHTML());
|
||
}
|
||
if (!this.labels.contains(label)) {
|
||
this.labels.insert(label);
|
||
}
|
||
};
|
||
/**
|
||
* Creates the html for the shape, its layers and labels
|
||
* @returns {HTMLElement}
|
||
*/
|
||
CustomShape.prototype.createHTML = function () {
|
||
var i,
|
||
label;
|
||
CustomShape.superclass.prototype.createHTML.call(this);
|
||
|
||
this.style.addClasses(["custom_shape"]);
|
||
|
||
this.layers.sort(PMUI.draw.Layer.prototype.comparisonFunction);
|
||
|
||
for (i = 0; i < this.layers.getSize(); i += 1) {
|
||
this.html.appendChild(this.layers.get(i).getHTML());
|
||
|
||
}
|
||
for (i = 0; i < this.labels.getSize(); i += 1) {
|
||
label = this.labels.get(i);
|
||
this.addLabel(label);
|
||
label.attachListeners();
|
||
|
||
}
|
||
return this.html;
|
||
};
|
||
|
||
/**
|
||
* This function will attach all the listeners corresponding to the CustomShape
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.attachListeners = function () {
|
||
if (this.html === null) {
|
||
return this;
|
||
}
|
||
|
||
if (!this.canvas.readOnly) {
|
||
var $customShape = $(this.html)
|
||
.click(this.onClick(this));
|
||
//drag options for the added shapes
|
||
$customShape.on("mousedown", this.onMouseDown(this));
|
||
$customShape.mousemove(this.onMouseMove(this));
|
||
$customShape.mouseup(this.onMouseUp(this));
|
||
$customShape.on("contextmenu", function (e) {
|
||
e.preventDefault();
|
||
});
|
||
this.updateBehaviors();
|
||
}
|
||
|
||
return this;
|
||
|
||
};
|
||
|
||
/**
|
||
* Apply the styles related to the shape, its layers and labels
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.paint = function () {
|
||
var i,
|
||
label;
|
||
|
||
CustomShape.superclass.prototype.paint.call(this);
|
||
|
||
//TODO Apply the style of the given shape
|
||
for (i = 0; i < this.layers.getSize(); i += 1) {
|
||
this.layers.get(i).paint();
|
||
}
|
||
for (i = 0; i < this.ports.getSize(); i += 1) {
|
||
this.ports.get(i).paint();
|
||
}
|
||
for (i = 0; i < this.labels.getSize(); i += 1) {
|
||
label = this.labels.get(i);
|
||
label.paint();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Updates properties obtained when the HTML is on the DOM
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.updateHTML = function () {
|
||
var i,
|
||
label;
|
||
this.setDimension(this.width, this.height);
|
||
for (i = 0; i < this.labels.getSize(); i += 1) {
|
||
label = this.labels.get(i);
|
||
label.paint();
|
||
label.updateDimension();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Verify if a shape is into a set of related shapes
|
||
* @param shape {CustmShape} item to test
|
||
* @param relatedShapes {Array} items
|
||
* @returns {boolean}
|
||
*/
|
||
CustomShape.prototype.containsElement = function (shape, relatedShapes) {
|
||
var i,
|
||
max;
|
||
if (jQuery.isArray(relatedShapes)) {
|
||
for (i = 0, max = relatedShapes.length; i < max; i += 1) {
|
||
if (relatedShapes[i].getID() === shape.getID()) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
return false
|
||
};
|
||
/**
|
||
* Repaints connections related to this shape
|
||
* @param {Boolean} inContainer Determines if the points of a connection should
|
||
* be saved for its reconstruction
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.refreshConnections = function (inContainer,
|
||
relatedShapes,
|
||
delta) {
|
||
var i,
|
||
connection,
|
||
ports = this.ports,
|
||
port,
|
||
srcElem,
|
||
destElem;
|
||
|
||
for (i = 0; i < ports.getSize(); i += 1) {
|
||
port = ports.get(i);
|
||
port.setPosition(port.getX(), port.getY());
|
||
connection = port.connection;
|
||
|
||
srcElem = connection.getSrcPort().parent;
|
||
destElem = connection.getDestPort().parent;
|
||
|
||
if (!(this.containsElement(srcElem, relatedShapes)
|
||
&& this.containsElement(destElem, relatedShapes))) {
|
||
connection.reconnectManhattah(inContainer);
|
||
connection.setSegmentMoveHandlers()
|
||
.checkAndCreateIntersectionsWithAll();
|
||
this.canvas.triggerConnectionStateChangeEvent(connection);
|
||
} else if (delta) {
|
||
if (!this.canvas.refreshArray.contains(connection)) {
|
||
connection.canvas.refreshArray.insert(connection);
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Updates the properties of this shape layers according to the shape itself
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.updateLayers = function () {
|
||
var i, j,
|
||
layer;
|
||
for (i = 0; i < this.getLayers().getSize(); i += 1) {
|
||
layer = this.getLayers().get(i);
|
||
layer.setProperties();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns what it should be the next layer if there is such in the DOM tree
|
||
* or null otherwise
|
||
* @param {PMUI.draw.Layer} layer
|
||
* @returns {PMUI.draw.Layer}
|
||
*/
|
||
CustomShape.prototype.findLayerPosition = function (layer) {
|
||
var nextLayer = null, //holds the next layer regarding the position where
|
||
// the new layer should be inserted
|
||
minVal = 10000000, //holds the minimum value of all the values greater
|
||
// than the newLayer priority
|
||
i,
|
||
currLayer,
|
||
currPriority;
|
||
// iterate through all the layers and find the minimum priority of all
|
||
// the priorities that are greater than the priority of the current layer
|
||
for (i = 0; i < this.layers.getSize(); i += 1) {
|
||
currLayer = this.layers.get(i);
|
||
currPriority = currLayer.getPriority();
|
||
if (currPriority > layer.getPriority()) {
|
||
if (minVal > currPriority) {
|
||
minVal = currPriority;
|
||
nextLayer = currLayer;
|
||
}
|
||
}
|
||
}
|
||
return nextLayer;
|
||
};
|
||
|
||
/**
|
||
* Adds a new layer to the corresponding shape
|
||
* @param {PMUI.draw.Layer} newLayer
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.addLayer = function (newLayer) {
|
||
// gets the layer that would come next the new one
|
||
var nextLayer = this.findLayerPosition(newLayer);
|
||
// if there is none it means that the new layer has the highest priority
|
||
// of all
|
||
if (this.html) {
|
||
if (!nextLayer) {
|
||
//so we just append it to the parent
|
||
this.html.appendChild(newLayer.getHTML());
|
||
} else {
|
||
//otherwise we append it before nextLayer
|
||
this.html.insertBefore(newLayer.getHTML(), nextLayer.getHTML());
|
||
}
|
||
newLayer.paint();
|
||
}
|
||
this.layers.insert(newLayer);
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Finds a given layer by ID or null of it doesn't exist
|
||
* @param {String} layerID
|
||
* @returns {PMUI.draw.Layer}
|
||
*/
|
||
CustomShape.prototype.findLayer = function (layerID) {
|
||
return this.layers.find('id', layerID);
|
||
};
|
||
|
||
/**
|
||
* Set the dimension of the customShape
|
||
* @param {Number} newWidth
|
||
* @param {Number} newHeight
|
||
*/
|
||
CustomShape.prototype.setDimension = function (newWidth, newHeight) {
|
||
CustomShape.superclass.prototype.setDimension.call(this, newWidth, newHeight);
|
||
this.updateLabels();
|
||
this.updateLayers();
|
||
return this;
|
||
};
|
||
/**
|
||
* Updates the labels properties if necessary
|
||
* @abstract
|
||
* @template
|
||
* @protected
|
||
*/
|
||
CustomShape.prototype.updateLabels = function () {
|
||
|
||
};
|
||
/**
|
||
* Makes a layer non-visible
|
||
* @param {String} layerID
|
||
* @returns {PMUI.draw.CustomShape}
|
||
*/
|
||
CustomShape.prototype.hideLayer = function (layerID) {
|
||
var currLayer;
|
||
if (!layerID || typeof layerID !== "string") {
|
||
return this;
|
||
}
|
||
currLayer = this.findLayer(layerID);
|
||
if (!currLayer) {
|
||
return this;
|
||
}
|
||
|
||
currLayer.setVisible(false);
|
||
return this;
|
||
|
||
};
|
||
/**
|
||
* Makes a layer visible
|
||
* @param {String} layerID
|
||
* @returns {PMUI.draw.CustomShape}
|
||
*/
|
||
CustomShape.prototype.showLayer = function (layerID) {
|
||
var currLayer;
|
||
if (!layerID || typeof layerID !== "string") {
|
||
return this;
|
||
}
|
||
|
||
currLayer = this.findLayer(layerID);
|
||
if (!currLayer) {
|
||
return this;
|
||
}
|
||
currLayer.setVisible(true);
|
||
|
||
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* Adds a port to the Shape
|
||
* @param {PMUI.draw.Port} port
|
||
* @param {Number} xPortCoord
|
||
* @param {Number} yPortCoord
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.addPort = function (port, xPortCoord, yPortCoord, triggerChange, sourcePort) {
|
||
|
||
|
||
//where the user is attempting to create the port
|
||
//TODO Fix trowing custom events by using properties of the objects
|
||
var position = new PMUI.util.Point(xPortCoord, yPortCoord);
|
||
|
||
//set the corresponding shape where the port would be created
|
||
port.setParent(this);
|
||
port.setCanvas(this.canvas);
|
||
this.definePortPosition(port, position, sourcePort);
|
||
|
||
//append the html to the DOM and paint the port
|
||
this.html.appendChild(port.getHTML());
|
||
|
||
port.paint();
|
||
|
||
//insert the port to the ports array of the shape
|
||
this.ports.insert(port);
|
||
return this;
|
||
};
|
||
/**
|
||
*
|
||
* Removes a port from the Shape
|
||
* @param {PMUI.draw.Port} port
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.removePort = function (port) {
|
||
this.ports.remove(port);
|
||
return this;
|
||
};
|
||
/**
|
||
* Determines the position where the port will be located
|
||
* @param {PMUI.draw.Port} port
|
||
* @param {PMUI.util.Point} point
|
||
* @param {PMUI.draw.Port} sourcePort
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.definePortPosition = function (port, point, sourcePort) {
|
||
var canvas = this.canvas,
|
||
directionArray = [this.TOP, this.RIGHT, this.BOTTOM, this.LEFT],
|
||
// midPointArray is used when connectAtMiddlePoints is set to TRUE
|
||
midPointArray = [
|
||
new PMUI.util.Point(Math.round(this.zoomWidth / 2), 0), // TOP
|
||
new PMUI.util.Point(this.zoomWidth, Math.round(this.zoomHeight / 2)), // RIGHT
|
||
new PMUI.util.Point(Math.round(this.zoomWidth / 2), this.zoomHeight), // BOTTOM
|
||
new PMUI.util.Point(0, Math.round(this.zoomHeight / 2)) // LEFT
|
||
],
|
||
// sideArray is used when connectAtMiddlePoints is set to FALSE
|
||
sideArray = [
|
||
new PMUI.util.Point(point.x, 0), // TOP
|
||
new PMUI.util.Point(this.getZoomWidth(), point.y), // RIGHT
|
||
new PMUI.util.Point(point.x, this.getZoomHeight()), // BOTTOM
|
||
new PMUI.util.Point(0, point.y) // LEFT
|
||
],
|
||
usedArray, // selects either the midPointArray or the side array
|
||
direction,
|
||
i,
|
||
candidateDistance,
|
||
minDistance,
|
||
option,
|
||
border,
|
||
directionBorderMultiplier = [-1, 1, 1, -1],
|
||
rightBorderMultiplier = [0, 1, 0, 0],
|
||
bottomBorderMultiplier = [0, -2, 0, 1];
|
||
|
||
// if the shape has the connectAtMiddlePoints flag on then use the midPoints
|
||
usedArray = this.connectAtMiddlePoints ? midPointArray : sideArray;
|
||
|
||
//console.log(this.connectAtMiddlePoints, usedArray, point, sourcePort);
|
||
// if the shape has a source port available then use manhattan distance
|
||
// instead of squaredDistance
|
||
option = "getSquaredDistance";
|
||
if (sourcePort && this.connectAtMiddlePoints) {
|
||
option = "getManhattanDistance";
|
||
}
|
||
direction = undefined; //obtain location of the port
|
||
minDistance = Infinity;
|
||
// get the minimum distance between 2 points;
|
||
for (i = 0; i < usedArray.length; i += 1) {
|
||
candidateDistance = point[option](usedArray[i]);
|
||
if (minDistance > candidateDistance) {
|
||
minDistance = candidateDistance;
|
||
direction = directionArray[i];
|
||
}
|
||
}
|
||
|
||
border = this.getBorderConsideringLayers();
|
||
for (i = 0; i < 4; i += 1) {
|
||
this.border[i].x =
|
||
(border * directionBorderMultiplier[i] +
|
||
border * rightBorderMultiplier[i]);
|
||
this.border[i].y =
|
||
(border * directionBorderMultiplier[i] +
|
||
border * bottomBorderMultiplier[i]);
|
||
}
|
||
// because of the zIndex problem move the ports towards the center
|
||
// of the shape (this is done when the destDecorator is selected)
|
||
port.setDirection(direction);
|
||
// setPosition logic:
|
||
// since the port must face the border of the shape (or the shape if it
|
||
// doesn't have a border) first let's move the port according to the
|
||
// direction of the port (up -> -1 * border, right -> 1 * border, bottom ->
|
||
// 1 * border, left -> -1 * border)
|
||
// after the port will be right in the edge of the shape but now the
|
||
// multiplier has also affected the positioning of the port if it's located
|
||
// in the right or in the bottom (the port will move 2 * border in the
|
||
// y-axis or x-axis) so let's reverse that movement using another array
|
||
port.setPosition(
|
||
(
|
||
usedArray[direction].x
|
||
- port.getWidth() / 2
|
||
),
|
||
(
|
||
usedArray[direction].y
|
||
- port.getHeight() / 2
|
||
)
|
||
);
|
||
|
||
// determines the percentage of port in relation with the shape's width or
|
||
// height (useful to determine the new position of the port while resizing)
|
||
port.determinePercentage();
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the border of this shape or the border of its layers (max)
|
||
* @return {Number}
|
||
*/
|
||
CustomShape.prototype.getBorderConsideringLayers = function () {
|
||
var border = parseInt(this.style.getProperty('borderTopWidth') || 0, 10),
|
||
layer,
|
||
i;
|
||
for (i = 0; i < this.getLayers().getSize(); i += 1) {
|
||
layer = this.getLayers().get(i);
|
||
border = Math.max(border, parseInt(
|
||
layer.style.getProperty('borderTopWidth') || 0,
|
||
10
|
||
));
|
||
}
|
||
return border;
|
||
};
|
||
|
||
/**
|
||
* Show all the ports of the Shape
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.showPorts = function () {
|
||
var i;
|
||
for (i = 0; i < this.ports.getSize(); i += 1) {
|
||
this.ports.get(i).show();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* hide all the ports of the Shape
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.hidePorts = function () {
|
||
var i;
|
||
for (i = 0; i < this.ports.getSize(); i += 1) {
|
||
this.ports.get(i).hide();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Updates the position of the ports regarding the CustomShape and two
|
||
* differentials
|
||
* TODO Improve triggering of events with ports own properties
|
||
* @param {Number} xDiff
|
||
* @param {Number} yDiff
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.updatePortsPosition = function (xDiff, yDiff) {
|
||
var i,
|
||
port,
|
||
ports = this.ports;
|
||
for (i = 0; i < ports.getSize(); i += 1) {
|
||
port = ports.get(i);
|
||
if (port.direction === this.RIGHT || port.direction === this.BOTTOM) {
|
||
port.oldX = port.x;
|
||
port.oldY = port.y;
|
||
port.oldAbsoluteX = port.absoluteX;
|
||
port.oldAbsoluteY = port.absoluteY;
|
||
port.setPosition(port.x + xDiff, port.y + yDiff, true);
|
||
port.changePosition(port.oldX, port.oldY, port.oldAbsoluteX,
|
||
port.oldAbsoluteY);
|
||
} else {
|
||
port.setPosition(port.x, port.y, true);
|
||
}
|
||
port.connection.disconnect().connect();
|
||
port.connection.setSegmentMoveHandlers();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Recalculates a port position given the port
|
||
* TODO Determine if this method is necessary
|
||
* @param {PMUI.draw.Port} port
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.recalculatePortPosition = function (port) {
|
||
var x = 0,
|
||
y = 0;
|
||
|
||
switch (port.getDirection()) {
|
||
case 2:
|
||
y = this.getZoomHeight();
|
||
case 0:
|
||
x = this.getZoomWidth() / 2;
|
||
break;
|
||
case 1:
|
||
x = this.getZoomWidth();
|
||
case 3:
|
||
y = this.getZoomHeight() / 2;
|
||
break;
|
||
}
|
||
|
||
port.setPosition(
|
||
Math.round(x - (port.getWidth() / 2)),
|
||
Math.round(y - (port.getHeight() /2)));
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Initializes properties to to save the current position of the ports
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.initPortsChange = function () {
|
||
var i,
|
||
ports = this.ports,
|
||
port;
|
||
for (i = 0; i < ports.getSize(); i += 1) {
|
||
port = ports.get(i);
|
||
port.oldX = port.x;
|
||
port.oldY = port.y;
|
||
port.oldAbsoluteX = port.absoluteX;
|
||
port.oldAbsoluteY = port.absoluteY;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Trigger to save the port changes
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.firePortsChange = function () {
|
||
var i,
|
||
ports = this.ports,
|
||
port;
|
||
for (i = 0; i < ports.getSize(); i += 1) {
|
||
port = ports.get(i);
|
||
// port is not a shape so use call
|
||
CustomShape.superclass.prototype.changePosition.call(this, port.oldX, port.oldY,
|
||
port.oldAbsoluteX, port.oldAbsoluteY);
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Updates ports and connections of the current shape
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.refreshShape = function () {
|
||
CustomShape.superclass.prototype.refreshShape.call(this);
|
||
this.updatePortsOnZoom()
|
||
.refreshConnections(false);
|
||
this.paint();
|
||
return this;
|
||
};
|
||
/**
|
||
* Updates the position of the ports after applying a zoom scale
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.updatePortsOnZoom = function () {
|
||
var i,
|
||
ports = this.ports,
|
||
port,
|
||
zoomFactor = this.canvas.zoomFactor,
|
||
prevZoomFactor = (this.canvas.prevZoom * 25 + 50) / 100,
|
||
portFactor = (ports.getSize() > 0) ? ports.get(0).width / 2 : 0,
|
||
srcDecorator,
|
||
destDecorator,
|
||
xCoords = [
|
||
this.zoomWidth / 2 - portFactor,
|
||
this.zoomWidth - portFactor,
|
||
this.zoomWidth / 2 - portFactor,
|
||
-portFactor
|
||
],
|
||
yCoords = [
|
||
-portFactor,
|
||
this.zoomHeight / 2 - portFactor,
|
||
this.zoomHeight - portFactor,
|
||
this.zoomHeight / 2 - portFactor
|
||
];
|
||
|
||
for (i = 0; i < ports.getSize(); i += 1) {
|
||
port = ports.get(i);
|
||
if (this.connectAtMiddlePoints) {
|
||
port.setPosition(xCoords[port.direction], yCoords[port.direction]);
|
||
} else {
|
||
port.setPosition(port.x / prevZoomFactor * zoomFactor,
|
||
port.y / prevZoomFactor * zoomFactor);
|
||
}
|
||
srcDecorator = port.connection.srcDecorator;
|
||
destDecorator = port.connection.destDecorator;
|
||
if (srcDecorator) {
|
||
srcDecorator.applyZoom();
|
||
}
|
||
if (destDecorator) {
|
||
destDecorator.applyZoom();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* TODO Determine if this method is necessary
|
||
*/
|
||
CustomShape.prototype.calculateLabelsPercentage = function () {
|
||
var i, label;
|
||
for (i = 0; i < this.labels.getSize(); i += 1) {
|
||
label = this.labels.get(i);
|
||
label.xPercentage = label.getX() / this.getWidth();
|
||
label.yPercentage = label.getY() / this.getHeight();
|
||
}
|
||
|
||
};
|
||
|
||
/**
|
||
* Updates the labels position according to its configuration properties
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.updateLabelsPosition = function () {
|
||
var i,
|
||
label;
|
||
for (i = 0; i < this.labels.getSize(); i += 1) {
|
||
label = this.labels.get(i);
|
||
label.setLabelPosition(label.location, label.diffX, label.diffY);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the respective drag behavior according to a given point
|
||
* @return {Number}
|
||
*/
|
||
CustomShape.prototype.determineDragBehavior = function (point) {
|
||
// limit to consider inside the shape
|
||
var Point = PMUI.util.Point,
|
||
Geometry = PMUI.draw.Geometry,
|
||
limit = this.limits[this.canvas.zoomPropertiesIndex],
|
||
|
||
border = parseInt(this.style.getProperty('border') || 0, 10);
|
||
|
||
// if the point is inside the rectangle determine the behavior
|
||
// (drag or connect)
|
||
if (Geometry.pointInRectangle(point, new Point(0, 0),
|
||
new Point(this.zoomWidth + 2 * border,
|
||
this.zoomHeight + 2 * border))) {
|
||
// if the shape is inside the inner rectangle then drag
|
||
if (Geometry.pointInRectangle(point,
|
||
new Point(border + limit, border + limit),
|
||
new Point(this.zoomWidth + border - limit,
|
||
this.zoomHeight + border - limit))) {
|
||
return this.DRAG;
|
||
}
|
||
return this.CONNECT;
|
||
}
|
||
|
||
// if the mouse pointer is outside then return cancel
|
||
return this.CANCEL;
|
||
};
|
||
/**
|
||
* Creates a drag helper for drag and drop operations for the helper property
|
||
* in jquery ui draggable
|
||
* TODO Create a singleton object for this purpose
|
||
* @returns {String} html
|
||
*/
|
||
CustomShape.prototype.createDragHelper = function () {
|
||
var html = document.createElement("div");
|
||
|
||
// can't use class style here
|
||
html.style.width = 8 + "px";
|
||
html.style.height = 8 + "px";
|
||
html.style.backgroundColor = "black";
|
||
html.style.zIndex = 2 * PMUI.draw.Shape.prototype.MAX_ZINDEX;
|
||
html.id = "drag-helper";
|
||
html.className = "drag-helper";
|
||
return html;
|
||
};
|
||
|
||
/**
|
||
* Handler for the onmousedown event, changes the draggable properties
|
||
* according to the drag behavior that is being applied
|
||
* @param {PMUI.draw.CustomShape} CustomShape
|
||
* @returns {Function}
|
||
*/
|
||
CustomShape.prototype.onMouseDown = function (customShape) {
|
||
return function (e, ui) {
|
||
var canvas = customShape.canvas;
|
||
if (e.which === 3) {
|
||
$(canvas.html).trigger("rightclick", [e, customShape]);
|
||
} else {
|
||
|
||
if (customShape.dragType === customShape.DRAG) {
|
||
customShape.setDragBehavior("customshapedrag");
|
||
|
||
} else if (customShape.dragType === customShape.CONNECT) {
|
||
customShape.setDragBehavior("connection");
|
||
} else {
|
||
customShape.setDragBehavior("nodrag");
|
||
}
|
||
customShape.dragging = true;
|
||
}
|
||
e.stopPropagation();
|
||
};
|
||
};
|
||
|
||
|
||
/**
|
||
* On Mouse Up handler it allows the shape to recalculate drag behavior
|
||
* whenever there was a mouse down event but no drag involved
|
||
* @param {PMUI.draw.CustomShape} customShape
|
||
* @return {Function}
|
||
*/
|
||
CustomShape.prototype.onMouseUp = function (customShape) {
|
||
return function (e, ui) {
|
||
customShape.dragging = false;
|
||
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Handler for the onmousemove event, determines the drag behavior that is
|
||
* being applied, the coordinates where the mouse is currently located and
|
||
* changes the mouse cursor
|
||
* @param {PMUI.draw.CustomShape} customShape
|
||
* @returns {Function}
|
||
*/
|
||
|
||
CustomShape.prototype.onMouseMove = function (customShape) {
|
||
return function (e, ui) {
|
||
var $customShape,
|
||
canvas,
|
||
realPoint,
|
||
auxPoint;
|
||
|
||
if (customShape.dragging || customShape.entered) {
|
||
return;
|
||
}
|
||
//TODO ADD TO UTILS A FUNCTION TO RETRIEVE A POINT RESPECTING THE SHAPE
|
||
$customShape = $(customShape.html);
|
||
canvas = customShape.getCanvas();
|
||
|
||
realPoint = canvas.relativePoint(e);
|
||
|
||
customShape.startConnectionPoint.x = realPoint.x - customShape.absoluteX;
|
||
customShape.startConnectionPoint.y = realPoint.y - customShape.absoluteY;
|
||
//console.log(customShape.startConnectionPoint);
|
||
auxPoint = new PMUI.util.Point(e.pageX - canvas.getX() -
|
||
customShape.absoluteX + canvas.getLeftScroll(),
|
||
e.pageY - canvas.getY() -
|
||
customShape.absoluteY + canvas.getTopScroll());
|
||
|
||
customShape.dragType = customShape
|
||
.determineDragBehavior(auxPoint);
|
||
//customShape.startConnectionPoint = auxPoint;
|
||
|
||
if (customShape.dragType === customShape.DRAG) {
|
||
$customShape.css('cursor', 'move');
|
||
} else if (customShape.dragType === customShape.CONNECT) {
|
||
$customShape.css('cursor', 'crosshair');
|
||
|
||
} else {
|
||
$customShape.css('cursor', 'default');
|
||
}
|
||
//e.stopPropagation();
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Handler of the onClick Event hides the selected ports and resize Handlers if
|
||
* any and show its corresponding resize handler
|
||
* @param {PMUI.draw.CustomShape} customShape
|
||
* @returns {Function}
|
||
*/
|
||
CustomShape.prototype.onClick = function (customShape) {
|
||
return function (e, ui) {
|
||
var isCtrl = false,
|
||
canvas = customShape.canvas,
|
||
currentSelection = canvas.currentSelection,
|
||
currentLabel = canvas.currentLabel;
|
||
|
||
if (e.ctrlKey) { // Ctrl is also pressed
|
||
isCtrl = true;
|
||
}
|
||
|
||
// hide the current connection if there was one
|
||
customShape.canvas.hideCurrentConnection();
|
||
|
||
if (e.which === 3) { // right click
|
||
e.preventDefault();
|
||
// trigger right click
|
||
customShape.canvas.triggerRightClickEvent(customShape);
|
||
} else {
|
||
if (!customShape.wasDragged) {
|
||
// if the custom shape was not dragged (this var is set to true
|
||
// in custom_shape_drag_behavior >> onDragEnd)
|
||
if (isCtrl) {
|
||
if (currentSelection.contains(customShape)) {
|
||
// remove from the current selection
|
||
canvas.removeFromSelection(customShape);
|
||
} else {
|
||
// add to the current selection
|
||
canvas.addToSelection(customShape);
|
||
}
|
||
|
||
} else {
|
||
canvas.emptyCurrentSelection();
|
||
canvas.addToSelection(customShape);
|
||
}
|
||
}
|
||
if (!currentSelection.isEmpty()) {
|
||
canvas.triggerSelectEvent(currentSelection.asArray());
|
||
}
|
||
}
|
||
|
||
if (this.helper) {
|
||
$(this.helper.html).remove();
|
||
}
|
||
|
||
// if (currentLabel) {
|
||
// currentLabel.loseFocus();
|
||
// $(currentLabel.textField).focusout();
|
||
// }
|
||
customShape.wasDragged = false;
|
||
// customShape.canvas.setCurrentShape(customShape);
|
||
e.stopPropagation();
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Empty function to perform some actions when parsing a diagram (called
|
||
* from Canvas.parse)
|
||
* @template
|
||
* @protected
|
||
*/
|
||
CustomShape.prototype.parseHook = function () {
|
||
};
|
||
|
||
/**
|
||
* Returns a list of ports related to the shape
|
||
* @returns {PMUI.util.ArrayList}
|
||
*/
|
||
CustomShape.prototype.getPorts = function () {
|
||
return this.ports;
|
||
};
|
||
/**
|
||
* Returns a list of Layers related to the shape
|
||
* @returns {PMUI.util.ArrayList}
|
||
*/
|
||
CustomShape.prototype.getLayers = function () {
|
||
return this.layers;
|
||
};
|
||
|
||
/**
|
||
* Returns the labels associated to the current shape
|
||
* @return {PMUI.util.ArrayList}
|
||
*/
|
||
CustomShape.prototype.getLabels = function () {
|
||
return this.labels;
|
||
};
|
||
|
||
/**
|
||
* Applies the current zoom to the corresponding shape its layers and labels
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.applyZoom = function () {
|
||
var i,
|
||
label;
|
||
|
||
CustomShape.superclass.prototype.applyZoom.call(this);
|
||
|
||
for (i = 0; i < this.layers.getSize(); i += 1) {
|
||
this.layers.get(i).applyZoom();
|
||
}
|
||
|
||
for (i = 0; i < this.labels.getSize(); i += 1) {
|
||
label = this.labels.get(i);
|
||
label.applyZoom();
|
||
label.setLabelPosition(label.location, label.diffX, label.diffY);
|
||
//label.setPosition(label.x, label.y);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the start point of a connection corresponding to this shape
|
||
* @param {PMUI.util.Point} point
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.setStartConnectionPoint = function (point) {
|
||
this.startConnectionPoint = point;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the connectAtMiddlePoints property
|
||
* @param {Boolean} connect
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.setConnectAtMiddlePoints = function (connect) {
|
||
this.connectAtMiddlePoints = connect;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns whether a shape connections will be done only in the middle points of
|
||
* its sides or not
|
||
* @return {Boolean}
|
||
*/
|
||
CustomShape.prototype.getConnectAtMiddlePoints = function () {
|
||
return this.connectAtMiddlePoints;
|
||
};
|
||
/**
|
||
* Sets the connection type of the shape
|
||
* @param {String} newConnType
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.setConnectionType = function (newConnType) {
|
||
this.connectionType = newConnType;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the connection type of the shape
|
||
* @return {String}
|
||
*/
|
||
CustomShape.prototype.getConnectionType = function () {
|
||
return this.connectionType;
|
||
};
|
||
/**
|
||
* Serializes this object
|
||
* @return {Object}
|
||
*/
|
||
CustomShape.prototype.stringify = function () {
|
||
/**
|
||
* inheritedJSON = {
|
||
* id: #
|
||
* x: #,
|
||
* y: #,
|
||
* width: #,
|
||
* height: #
|
||
* }
|
||
* @property {Object}
|
||
*/
|
||
var sLayers = [],
|
||
labels = [],
|
||
i,
|
||
inheritedJSON,
|
||
thisJSON;
|
||
|
||
// serialize layers
|
||
for (i = 0; i < this.layers.getSize(); i += 1) {
|
||
sLayers.push(this.layers.get(i).stringify());
|
||
}
|
||
|
||
// serialize labels
|
||
for (i = 0; i < this.labels.getSize(); i += 1) {
|
||
labels.push(this.labels.get(i).stringify());
|
||
}
|
||
|
||
inheritedJSON = CustomShape.superclass.prototype.stringify.call(this);
|
||
thisJSON = {
|
||
canvas: this.canvas.getID(),
|
||
layers: sLayers,
|
||
labels: labels,
|
||
connectAtMiddlePoints: this.getConnectAtMiddlePoints(),
|
||
connectionType: this.getConnectionType(),
|
||
parent: this.parent.getID()
|
||
};
|
||
$.extend(true, inheritedJSON, thisJSON);
|
||
return inheritedJSON;
|
||
};
|
||
|
||
/**
|
||
* Builds a custom shape based on the parameter 'json'
|
||
* @param {String} json
|
||
* @chainable
|
||
*/
|
||
CustomShape.prototype.parseJSON = function (json) {
|
||
this.initObject(json);
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.CustomShape', CustomShape);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = CustomShape;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @abstract
|
||
* @class PMUI.draw.RegularShape
|
||
* @extend PMUI.draw.Shape
|
||
* The class RegularShape represents all
|
||
* regular shapes created in the canvas such as, rectangles, ovals, ports, and
|
||
* handlers
|
||
*
|
||
* This class will hold all the common behavior of regular shapes
|
||
* like rectangles or ovals
|
||
*
|
||
* @constructor
|
||
* Initializes a regular shape
|
||
*/
|
||
var RegularShape = function (options) {
|
||
RegularShape.superclass.call(this, options);
|
||
|
||
/**
|
||
* color of the shape
|
||
* @property {PMUI.util.Color}
|
||
*/
|
||
this.color = new PMUI.util.Color();
|
||
|
||
/**
|
||
* Graphics for this regular shape
|
||
*/
|
||
this.graphics = null;
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Shape', RegularShape);
|
||
|
||
/**
|
||
* Type of the shape
|
||
* @property {String}
|
||
*/
|
||
RegularShape.prototype.type = "RegularShape";
|
||
|
||
/**
|
||
* Returns the color of the shape
|
||
* @returns {PMUI.util.Color}
|
||
*/
|
||
RegularShape.prototype.getColor = function () {
|
||
return this.color;
|
||
};
|
||
|
||
/**
|
||
* Sets the color of the shape
|
||
* @returns {PMUI.draw.RegularShape}
|
||
* @param {PMUI.util.Color} newColor
|
||
*/
|
||
RegularShape.prototype.setColor = function (newColor) {
|
||
if (newColor.type && newColor.type === "Color") {
|
||
this.color = newColor;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.RegularShape', RegularShape);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = RegularShape;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Arc
|
||
* @extend PMUI.draw.RegularShape
|
||
* Class arc that draws arcs using the HTMLElement draw engine.
|
||
* Since the canvas is inverted in the y-axis the angles are:
|
||
*
|
||
* - TOP 270
|
||
* - RIGHT 0
|
||
* - BOTTOM 90
|
||
* - LEFT 180
|
||
*
|
||
* An arc can be defined with the following elements:
|
||
*
|
||
* - *startAngle* start angle `0 <= startAngle < 360`.
|
||
* - *endAngle* end angle `0 <= endAngle < 360`.
|
||
* - *radius* the radius of the circle.
|
||
*
|
||
* Besides, the HTMLElement draw engine needs another parameter called *step*, this field tells the engine to
|
||
* draw only at '*step*' steps
|
||
*
|
||
* e.g.
|
||
* startAngle = 90
|
||
* endAngle = 150
|
||
* engine.paint() with step = 10:
|
||
* 90, 100, 110, 120, 130, 140, 150
|
||
* engine.paint() with step = 20:
|
||
* 90, 110, 130, 150
|
||
*
|
||
* As a consequence of the y-axis being inverted,we start drawing from the end angle towards the start angle,
|
||
* therefore to draw an arc from 0 deg to 90 deg we must invert the parameters
|
||
*
|
||
* var a = new PMUI.draw.Arc({
|
||
* center: new PMUI.util.Point(10, 10),
|
||
* radius: 200,
|
||
* startAngle: 270,
|
||
* endAngle: 0
|
||
* });
|
||
*
|
||
* @param {Object} options Initialization options
|
||
* @cfg {PMUI.util.Point} [center=new PMUI.util.Points(0, 0)] Point representing the center of the arc
|
||
* @cfg {number} [radius=Shape.prototype.DEFAULT_RADIUS] radius of the arc
|
||
* @cfg {number} [startAngle=270] start angle of the arc
|
||
* @cfg {number} [endAngle=90] end angle of the arc
|
||
* @cfg {number} [step=10] steps to jump from end angle (to get to start angle)
|
||
* @constructor Creates a new instance of arc
|
||
*/
|
||
var Arc = function (options) {
|
||
Arc.superclass.call(this);
|
||
|
||
/**
|
||
* Start angle of this arc
|
||
* @property {number}
|
||
*/
|
||
this.startAngle = null;
|
||
|
||
/**
|
||
* End angle of this arc
|
||
* @property {number}
|
||
*/
|
||
this.endAngle = null;
|
||
|
||
/**
|
||
* Radius of the arc
|
||
* @property {number}
|
||
*/
|
||
this.radius = null;
|
||
|
||
/**
|
||
* Steps to draw the arc
|
||
* @property {number}
|
||
*/
|
||
this.step = null;
|
||
|
||
// set defaults
|
||
Arc.prototype.init.call(this, options);
|
||
};
|
||
|
||
// prototype chaining
|
||
PMUI.inheritFrom('PMUI.draw.RegularShape', Arc);
|
||
|
||
/**
|
||
* Type of this shape
|
||
* @property {String}
|
||
*/
|
||
Arc.prototype.type = "Arc";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to
|
||
* initialize the instance
|
||
* @private
|
||
* @param {Object} options
|
||
*/
|
||
Arc.prototype.init = function (options) {
|
||
|
||
// Default options for the object
|
||
var defaults = {
|
||
center: new PMUI.util.Point(0, 0),
|
||
radius: PMUI.draw.Shape.prototype.DEFAULT_RADIUS,
|
||
startAngle: 270,
|
||
endAngle: 90,
|
||
step: 10
|
||
};
|
||
|
||
// extend recursively defaults with the given options
|
||
$.extend(true, defaults, options);
|
||
|
||
// call setters using the defaults object
|
||
this.setCenter(defaults.center)
|
||
.setStartAngle(defaults.startAngle)
|
||
.setEndAngle(defaults.endAngle)
|
||
.setRadius(defaults.radius)
|
||
.setStep(defaults.step);
|
||
|
||
// change the id (to debug easier)
|
||
this.id += "-ARC";
|
||
};
|
||
|
||
/**
|
||
* In charge of the painting / positioning of the figure on
|
||
* the DOM and setting the styles
|
||
* @chainable
|
||
*/
|
||
Arc.prototype.paint = function () {
|
||
|
||
this.setVisible(this.visible);
|
||
|
||
if (this.html) {
|
||
this.style.applyStyle();
|
||
// this.graphic is inherited from RegularShape
|
||
this.graphics = new PMUI.draw.Graphics(this.id);
|
||
this.graphics.setColor("black");
|
||
this.graphics.drawArc(this.center.x, this.center.y, this.radius,
|
||
this.startAngle, this.endAngle, this.step);
|
||
this.graphics.graphics.paint();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Creates the HTML representation of the Arc
|
||
* @returns {HTMLElement}
|
||
*/
|
||
Arc.prototype.createHTML = function () {
|
||
Arc.superclass.prototype.createHTML.call(this);
|
||
return this.html;
|
||
};
|
||
|
||
/**
|
||
* Returns the startAngle of the arc
|
||
* @returns {number}
|
||
*/
|
||
Arc.prototype.getStartAngle = function () {
|
||
return this.startAngle;
|
||
};
|
||
|
||
/**
|
||
* Sets the startAngle of the arc
|
||
* @param {number} newAngle
|
||
* @chainable
|
||
*/
|
||
Arc.prototype.setStartAngle = function (newAngle) {
|
||
this.startAngle = newAngle;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the endAngle of the arc
|
||
* @returns {number}
|
||
*/
|
||
Arc.prototype.getEndAngle = function () {
|
||
return this.endAngle;
|
||
};
|
||
|
||
/**
|
||
* Sets the endAngle of the arc
|
||
* @param {number} newAngle
|
||
* @chainable
|
||
*/
|
||
Arc.prototype.setEndAngle = function (newAngle) {
|
||
this.endAngle = newAngle;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the radius of the arc
|
||
* @returns {number}
|
||
*/
|
||
Arc.prototype.getRadius = function () {
|
||
return this.radius;
|
||
};
|
||
|
||
/**
|
||
* Sets the radius of the arc
|
||
* @param {number} newRadius
|
||
* @chainable
|
||
*/
|
||
Arc.prototype.setRadius = function (newRadius) {
|
||
this.radius = newRadius;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the radius of the arc
|
||
* @returns {number}
|
||
*/
|
||
Arc.prototype.getStep = function () {
|
||
return this.step;
|
||
};
|
||
|
||
/**
|
||
* Sets the step to draw the arc (steps jumped from startAngle to endAngle)
|
||
* @param {number} newStep
|
||
* @chainable
|
||
*/
|
||
Arc.prototype.setStep = function (newStep) {
|
||
this.step = newStep;
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Arc', Arc);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Arc;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Oval
|
||
* A regular shape that represents an oval, in the PMDraw framework instances of the class Oval
|
||
* are used to represent a Port.
|
||
*
|
||
* Some examples of use:
|
||
*
|
||
* var oval = new PMUI.draw.Oval({
|
||
* width: 8,
|
||
* height: 8,
|
||
* center: new PMUI.util.Point(100, 100)
|
||
* });
|
||
*
|
||
* @extend PMUI.draw.RegularShape
|
||
*
|
||
* @constructor Creates an instance of the class Oval
|
||
* @param {Object} options Initialization options
|
||
* @cfg {number} [width=4] The width of this oval
|
||
* @cfg {number} [height=4] The height of this oval
|
||
* @cfg {number} [center=new Center(0, 0)] The center of this oval
|
||
*/
|
||
var Oval = function (options) {
|
||
Oval.superclass.call(this, options);
|
||
Oval.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.RegularShape', Oval);
|
||
|
||
/**
|
||
* The type of each instance of this class
|
||
* @property {String} [type=Oval]
|
||
*/
|
||
Oval.prototype.type = "Oval";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance
|
||
* @param {Object} options The object that contains the config
|
||
* @private
|
||
*/
|
||
Oval.prototype.init = function (options) {
|
||
/**
|
||
* Default options for the object
|
||
* @property {Object}
|
||
*/
|
||
var defaults = {
|
||
center: new PMUI.util.Point(0, 0),
|
||
width: 4,
|
||
height: 4
|
||
};
|
||
|
||
// extend recursively the defaultOptions with the given options
|
||
$.extend(true, defaults, options);
|
||
|
||
// call setters using the defaults object
|
||
this.setCenter(defaults.center)
|
||
.setWidth(defaults.width)
|
||
.setHeight(defaults.height);
|
||
};
|
||
|
||
/**
|
||
* Paints a **red** oval using the configuration options (the HTML is not appended to
|
||
* the DOM)
|
||
* @chainable
|
||
*/
|
||
Oval.prototype.paint = function () {
|
||
|
||
// show or hide the oval
|
||
this.setVisible(this.visible);
|
||
|
||
if (this.html) {
|
||
this.style.applyStyle();
|
||
|
||
this.graphic = new JSGraphics(this.id);
|
||
this.graphic.setColor("red");
|
||
this.graphic.fillOval(0, 0, this.getWidth(), this.getHeight());
|
||
this.graphic.paint();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Creates the HTML representation of the Oval
|
||
* @returns {HTMLElement}
|
||
*/
|
||
Oval.prototype.createHTML = function () {
|
||
Oval.superclass.prototype.createHTML.call(this);
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Oval', Oval);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Oval;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Polygon
|
||
* Abstract class polygon to draw simple poly-lines
|
||
*
|
||
* An example of usage:
|
||
*
|
||
* var polygon = new PMUI.draw.Polygon({
|
||
* points: []
|
||
* });
|
||
*
|
||
* @extend PMUI.draw.RegularShape
|
||
*
|
||
* @constructor Creates an instance of the class Polygon
|
||
* @param {Object} options Initialization options
|
||
* @cfg {Array} [points=[]] The points that make the polygon
|
||
*/
|
||
var Polygon = function (options) {
|
||
|
||
Polygon.superclass.call(this, options);
|
||
|
||
/**
|
||
* The points representing this polygon
|
||
* @property {Array}
|
||
*/
|
||
this.points = null;
|
||
|
||
Polygon.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.RegularShape', Polygon);
|
||
|
||
/**
|
||
* The type of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
Polygon.prototype.type = "Polygon";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance
|
||
* @param {Object} options The object that contains the config
|
||
* @private
|
||
*/
|
||
Polygon.prototype.init = function (options) {
|
||
var defaults = {
|
||
points: []
|
||
};
|
||
$.extend(true, defaults, options);
|
||
this.setPoints(defaults.points);
|
||
};
|
||
|
||
/**
|
||
* Sets the points of this polygon
|
||
* @param {Array} newPoints
|
||
* @chainable
|
||
*/
|
||
Polygon.prototype.setPoints = function (newPoints) {
|
||
var i,
|
||
point;
|
||
this.points = [];
|
||
for (i = 0; i < newPoints.length; i += 1) {
|
||
point = newPoints[i];
|
||
this.points.push(new PMUI.util.Point(point.getX(), point.getY()));
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Gets the points of this polygon
|
||
* @return {Array}
|
||
*/
|
||
Polygon.prototype.getPoints = function () {
|
||
return this.points;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Polygon', Polygon);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Polygon;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Intersection
|
||
* An intersection in the designer is defined as an arc which has only one additional property: `idOtherConnection`
|
||
* and it's the ID of the other connection this segment has intersection with.
|
||
*
|
||
* All the intersection of a segment are stored in `segment.intersections`.
|
||
*
|
||
* An example of instantiation:
|
||
*
|
||
* // let's assume that 'segment' is an instance of the class Segment
|
||
* // let's assume that 'otherSegment' is an instance of the class Segment
|
||
* // let's assume that 'segment' has an intersection with 'otherSegment' at 'ip' (intersection point)
|
||
* var intersection = new PMUI.draw.Intersection(
|
||
* ip,
|
||
* otherSegment.parent,getID(),
|
||
* segment
|
||
* );
|
||
*
|
||
* @extends PMUI.draw.Arc
|
||
*
|
||
* @constructor Creates an instance of the class Intersection
|
||
* @param {PMUI.util.Point} center
|
||
* @param {String} idOtherConnection
|
||
* @param {PMUI.draw.Segment} parent
|
||
*/
|
||
var Intersection = function (center, idOtherConnection, parent) {
|
||
|
||
Intersection.superclass.call(this);
|
||
/**
|
||
* The center of the arc
|
||
* @property {PMUI.util.Point} [center=null]
|
||
*/
|
||
this.center = (!center) ? null : center;
|
||
/**
|
||
* Visibility of this arc
|
||
* @property {boolean}
|
||
*/
|
||
this.visible = true;
|
||
/**
|
||
* Parent of this intersection is a segment
|
||
* @property {PMUI.draw.Segment}
|
||
*/
|
||
this.parent = parent;
|
||
/**
|
||
* Id of the other connection
|
||
* @property {String}
|
||
*/
|
||
this.idOtherConnection = idOtherConnection;
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Arc', Intersection);
|
||
|
||
/**
|
||
* The type of each instance of the class Intersection
|
||
* @property {String}
|
||
*/
|
||
Intersection.prototype.type = "Intersection";
|
||
|
||
/**
|
||
* Paints this intersection (calling `Arc.paint()`) considering the orientation of its parent.
|
||
*
|
||
* It overwrites the properties `startAngle` and `endAngle` inherited from {@link PMUI.draw.Arc}
|
||
* according to the orientation of its parent (segment), the calculation is as follows:
|
||
*
|
||
* - Segment is vertical
|
||
* - startAngle = 270
|
||
* - endAngle = 90
|
||
* - Segment is horizontal
|
||
* - startAngle = 180
|
||
* - endAngle = 0
|
||
*
|
||
* @chainable
|
||
*/
|
||
Intersection.prototype.paint = function () {
|
||
|
||
// NOTE: it's always visible so do not call setVisible()
|
||
|
||
if (this.parent.orientation === this.VERTICAL) {
|
||
this.startAngle = 270;
|
||
this.endAngle = 90;
|
||
} else {
|
||
this.startAngle = 180;
|
||
this.endAngle = 0;
|
||
}
|
||
|
||
// call the representation (always an arc)
|
||
Intersection.superclass.prototype.paint.call(this);
|
||
|
||
// apply predefined style
|
||
this.style.applyStyle();
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Destroys the intersection by removing its HTML from the DOM.
|
||
* @chainable
|
||
*/
|
||
Intersection.prototype.destroy = function () {
|
||
$(this.html).remove();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Creates the HTML representation of the Intersection.
|
||
* @returns {HTMLElement}
|
||
*/
|
||
Intersection.prototype.createHTML = function () {
|
||
PMUI.draw.Shape.prototype.createHTML.call(this);
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Intersection', Intersection);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Intersection;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Rectangle
|
||
* A regular shape that represents a rectangle, in the PMDraw framework instances of the class Rectangle
|
||
* are used to represent a resize handler and a segment move handler.
|
||
*
|
||
* Some examples of use:
|
||
*
|
||
* var rectangle = new PMUI.draw.Rectangle();
|
||
*
|
||
* @extend PMUI.draw.Polygon
|
||
*
|
||
* @constructor Creates an instance of the class Rectangle
|
||
* @param {Object} options Initialization options (currently there are no initialization options)
|
||
*/
|
||
var Rectangle = function (options) {
|
||
Rectangle.superclass.call(this, options);
|
||
Rectangle.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Polygon', Rectangle);
|
||
|
||
/**
|
||
* The type of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
Rectangle.prototype.type = "Rectangle";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance
|
||
* @param {Object} options The object that contains the config
|
||
* @private
|
||
*/
|
||
Rectangle.prototype.init = function (options) {
|
||
};
|
||
|
||
/**
|
||
* Paints the rectangle applying the predefined style and adding a background color if
|
||
* it's possible (it's possible if this rectangle has an instance of the class Color).
|
||
* @chainable
|
||
*/
|
||
Rectangle.prototype.paint = function () {
|
||
if (this.html) {
|
||
this.style.applyStyle();
|
||
if (this.color) {
|
||
this.style.addProperties({
|
||
backgroundColor: this.color.getCSS()
|
||
});
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Creates the HTML representation of the Rectangle
|
||
* @returns {HTMLElement}
|
||
*/
|
||
Rectangle.prototype.createHTML = function () {
|
||
PMUI.draw.Shape.prototype.createHTML.call(this);
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Rectangle', Rectangle);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Rectangle;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.MultipleSelectionContainer
|
||
* Represents the rectangle created to do multiple selection after firing
|
||
{@link PMUI.draw.Canvas#event-mousedown} and
|
||
* dragging a rectangle over the desired elements in the canvas and firing
|
||
{@link PMUI.draw.Canvas#event-mouseup},
|
||
* currently it can only select shapes that are direct children of the canvas.
|
||
*
|
||
* An example of use:
|
||
*
|
||
* // let's assume that canvas is an instance of the class Canvas
|
||
* var multipleSelectionContainer = new PMUI.draw.MultipleSelectionContainer(canvas);
|
||
*
|
||
* @extend PMUI.draw.Rectangle
|
||
*
|
||
* @constructor Creates an instance of the class MultipleSelectionContainer
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
*/
|
||
var MultipleSelectionContainer = function (options) {
|
||
MultipleSelectionContainer.superclass.call(this);
|
||
|
||
/**
|
||
* The background color of this element
|
||
* @property {PMUI.util.Color}
|
||
*/
|
||
this.backgroundColor = null;
|
||
|
||
/**
|
||
* Reference to the canvas
|
||
* @property {PMUI.draw.Canvas}
|
||
*/
|
||
this.canvas = null;
|
||
|
||
// init object
|
||
MultipleSelectionContainer.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Rectangle', MultipleSelectionContainer);
|
||
|
||
/**
|
||
* Type of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
MultipleSelectionContainer.prototype.type = "MultipleSelectionContainer";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance
|
||
* @param {PMUI.draw.Canvas} canvas The canvas of this multiple selection container
|
||
* @private
|
||
*/
|
||
MultipleSelectionContainer.prototype.init = function (options) {
|
||
var defaults = {
|
||
canvas: null,
|
||
x: 0,
|
||
y: 0,
|
||
color: new PMUI.util.Color(0, 128, 255, 0.1)
|
||
};
|
||
jQuery.extend(true, defaults, options);
|
||
this.backgroundColor = defaults.color;
|
||
// light blue
|
||
this.canvas = defaults.canvas;
|
||
this.absoluteX = this.canvas.absoluteX;
|
||
this.absoluteY = this.canvas.absoluteY;
|
||
};
|
||
|
||
/**
|
||
* Paints the multiple selection container with the color *light blue* (defined in initObject)
|
||
* @chainable
|
||
*/
|
||
MultipleSelectionContainer.prototype.paint = function () {
|
||
this.style.addProperties({
|
||
backgroundColor: this.backgroundColor.getCSS()
|
||
});
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Changes the opacity of this multiple selection container (and repaints it later).
|
||
* @param {number} value
|
||
* @chainable
|
||
*/
|
||
MultipleSelectionContainer.prototype.changeOpacity = function (value) {
|
||
this.backgroundColor.setOpacity(value);
|
||
this.paint();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Wraps the direct children of the canvas. To call this method it's assumed that this instance has a position
|
||
* and a dimension in the canvas (this method is called from {@link PMUI.draw.Canvas#event-mouseup}).
|
||
* It executes the following actions:
|
||
*
|
||
* 1. Gathers the currentSelection
|
||
* 2. Checks which direct children of the canvas are inside the selection
|
||
* (done through {@link PMUI.draw.MultipleSelectionContainer#intersectElements}).
|
||
* 3. Fires {@link PMUI.draw.Canvas#triggerSelectEvent} using the new `this.canvas.currentSelection`
|
||
* 4. Resets the state of this instance
|
||
*
|
||
* @chainable
|
||
*/
|
||
MultipleSelectionContainer.prototype.wrapElements = function () {
|
||
var currentSelection = this.canvas.currentSelection,
|
||
selection = [];
|
||
this.intersectElements();
|
||
if (!currentSelection.isEmpty()) {
|
||
selection = currentSelection.asArray();
|
||
this.canvas.triggerSelectEvent(selection);
|
||
}
|
||
this.reset();
|
||
this.setVisible(false);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Checks which direct children of the canvas are inside `this` (represented as a rectangle in the canvas).
|
||
* The steps are:
|
||
*
|
||
* 1. Empty `this.canvas.currentSelection` by calling {@link PMUI.draw.Canvas#emptyCurrentSelection}.
|
||
* 2. If a child is inside this rectangle then it's added to `this.canvas.currentSelection`.
|
||
*
|
||
* @chainable
|
||
*/
|
||
MultipleSelectionContainer.prototype.intersectElements = function () {
|
||
var i,
|
||
shape,
|
||
children;
|
||
|
||
//empty the current selection
|
||
this.canvas.emptyCurrentSelection();
|
||
|
||
// get all the customShapes
|
||
children = this.canvas.customShapes;
|
||
for (i = 0; i < children.getSize(); i += 1) {
|
||
shape = children.get(i);
|
||
if (shape.parent.family === "Canvas" && this.checkIntersection(shape)) {
|
||
this.canvas.addToSelection(shape);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Resets the position and dimensions of this selection container.
|
||
* @chainable
|
||
*/
|
||
MultipleSelectionContainer.prototype.reset = function () {
|
||
this.setPosition(0, 0);
|
||
this.setDimension(0, 0);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Alias for {@link PMUI.draw.Core#getAbsoluteX}.
|
||
* @property {Function} getLeft
|
||
*/
|
||
MultipleSelectionContainer.prototype.getLeft = PMUI.draw.Shape.prototype.getAbsoluteX;
|
||
|
||
/**
|
||
* Alias for {@link PMUI.draw.Core#getAbsoluteY}.
|
||
* @property {Function} getTop
|
||
*/
|
||
MultipleSelectionContainer.prototype.getTop = PMUI.draw.Shape.prototype.getAbsoluteY;
|
||
|
||
/**
|
||
* Checks if `shape` is inside `this`, `shape` is inside `this` if one of its corners
|
||
* its inside `this`.
|
||
* @param {PMUI.draw.Shape} shape
|
||
* @return {boolean}
|
||
*/
|
||
MultipleSelectionContainer.prototype.checkIntersection = function (shape) {
|
||
var Point = PMUI.util.Point,
|
||
Geometry = PMUI.draw.Geometry,
|
||
topLeft = new PMUI.util.Point(this.zoomX, this.zoomY),
|
||
bottomRight = new PMUI.util.Point(this.zoomX + this.zoomWidth,
|
||
this.zoomY + this.zoomHeight);
|
||
return Geometry.pointInRectangle(new PMUI.util.Point(shape.getZoomX(), shape.getZoomY()),
|
||
topLeft, bottomRight) ||
|
||
Geometry.pointInRectangle(new PMUI.util.Point(shape.zoomX +
|
||
shape.zoomWidth, shape.zoomY), topLeft, bottomRight) ||
|
||
Geometry.pointInRectangle(new PMUI.util.Point(shape.zoomX, shape.zoomY +
|
||
shape.zoomHeight), topLeft, bottomRight) ||
|
||
Geometry.pointInRectangle(new PMUI.util.Point(shape.zoomX +
|
||
shape.zoomWidth, shape.zoomY + shape.zoomHeight), topLeft, bottomRight);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.MultipleSelectionContainer', MultipleSelectionContainer);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = MultipleSelectionContainer;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Snapper
|
||
* Class snapper represents the helper shown while moving shapes.
|
||
* @extend PMUI.draw.Core
|
||
*
|
||
* @constructor Creates an instance of the class Snapper
|
||
* @param {Object} options Initialization options
|
||
* @cfg {PMUI.util.Point} [orientation="horizontal"] The default orientation of this snapper
|
||
*/
|
||
var Snapper = function (options) {
|
||
|
||
Snapper.superclass.call(this, options);
|
||
|
||
/**
|
||
* Orientation of this snapper, it can be either "horizontal" or "vertical".
|
||
* @property {string} [orientation=null]
|
||
*/
|
||
this.orientation = null;
|
||
|
||
/**
|
||
* Data saved to define the positioning of this snapper in the canvas.
|
||
* @property {Array} [data=[]]
|
||
*/
|
||
this.data = [];
|
||
|
||
/**
|
||
* The visibility of this snapper.
|
||
* @property {boolean} [visible=false]
|
||
*/
|
||
this.visible = false;
|
||
|
||
Snapper.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Core', Snapper);
|
||
|
||
/**
|
||
* The type of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
Snapper.prototype.type = "Snapper";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance.
|
||
* @param {Object} options The object that contains the config
|
||
* @private
|
||
*/
|
||
Snapper.prototype.init = function (options) {
|
||
|
||
var defaults = {
|
||
orientation: "horizontal"
|
||
};
|
||
|
||
// extend recursively the defaultOptions with the given options
|
||
$.extend(true, defaults, options);
|
||
|
||
// call setters using the defaults object
|
||
this.setOrientation(defaults.orientation);
|
||
};
|
||
|
||
/**
|
||
* Creates the HTML representation of the snapper.
|
||
* @returns {HTMLElement}
|
||
*/
|
||
Snapper.prototype.createHTML = function () {
|
||
Snapper.superclass.prototype.createHTML.call(this);
|
||
return this.html;
|
||
};
|
||
|
||
Snapper.prototype.enable = function () {
|
||
if (this.html) {
|
||
this.graphic = new JSGraphics(this.id);
|
||
this.graphic.setColor("#81DAF5");
|
||
if (this.orientation === 'horizontal') {
|
||
this.graphic.drawLine(0, 0, 4000, 0);
|
||
} else {
|
||
this.graphic.drawLine(0, 0, 0, 4000);
|
||
}
|
||
this.graphic.paint();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Hides the snapper.
|
||
* @chainable
|
||
*/
|
||
Snapper.prototype.hide = function () {
|
||
this.visible = false;
|
||
this.setVisible(this.visible);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Shows the snapper.
|
||
* @chainable
|
||
*/
|
||
Snapper.prototype.show = function () {
|
||
this.visible = true;
|
||
this.setVisible(this.visible);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Fills the data for the snapper (using customShapes and regularShapes).
|
||
* The data considered for each shape is:
|
||
*
|
||
* - Its absoluteX
|
||
* - Its absoluteY
|
||
* - Its absoluteX + width
|
||
* - Its absoluteY + height
|
||
*
|
||
* @chainable
|
||
*/
|
||
Snapper.prototype.createSnapData = function () {
|
||
var i,
|
||
index = 0,
|
||
shape,
|
||
border = 0;
|
||
|
||
// clear the data before populating it
|
||
this.data = [];
|
||
|
||
// populate the data array using the customShapes
|
||
for (i = 0; i < this.canvas.customShapes.getSize(); i += 1) {
|
||
shape = this.canvas.customShapes.get(i);
|
||
border = parseInt($(shape.getHTML()).css('borderTopWidth'), 10);
|
||
if (this.orientation === 'horizontal') {
|
||
this.data[index * 2] = shape.getAbsoluteY() - border;
|
||
this.data[index * 2 + 1] = shape.getAbsoluteY() + shape.getZoomHeight();
|
||
} else {
|
||
this.data[index * 2] = shape.getAbsoluteX() - border;
|
||
this.data[index * 2 + 1] = shape.getAbsoluteX() + shape.getZoomWidth();
|
||
}
|
||
index += 1;
|
||
}
|
||
|
||
// populate the data array using the regularShapes
|
||
for (i = 0; i < this.canvas.regularShapes.getSize(); i += 1) {
|
||
shape = this.canvas.regularShapes.get(i);
|
||
border = parseInt($(shape.getHTML()).css('borderTopWidth'), 10);
|
||
if (this.orientation === 'horizontal') {
|
||
this.data[index * 2] = shape.getAbsoluteY() - border;
|
||
this.data[index * 2 + 1] = shape.getAbsoluteY() +
|
||
shape.getZoomHeight();
|
||
} else {
|
||
this.data[index * 2] = shape.getAbsoluteX() - border;
|
||
this.data[index * 2 + 1] = shape.getAbsoluteX() +
|
||
shape.getZoomWidth();
|
||
}
|
||
index += 1;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sorts the data using the builtin `sort()` function, so that there's an strictly increasing order.
|
||
* @chainable
|
||
*/
|
||
Snapper.prototype.sortData = function () {
|
||
this.data.sort();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Performs a binary search for `value` in `this.data`, return true if `value` was found in the data.
|
||
* @param {number} value
|
||
* @return {boolean}
|
||
*/
|
||
Snapper.prototype.binarySearch = function (value) {
|
||
var low = 0,
|
||
up = this.data.length - 1,
|
||
mid;
|
||
|
||
while (low <= up) {
|
||
mid = parseInt((low + up) / 2, 10);
|
||
if (this.data[mid] === value) {
|
||
return value;
|
||
}
|
||
if (this.data[mid] > value) {
|
||
up = mid - 1;
|
||
} else {
|
||
low = mid + 1;
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
|
||
/**
|
||
* Attaches listeners to this snapper, currently it only has the
|
||
* mouseMove event which hides the snapper.
|
||
* @param {PMUI.draw.Snapper} snapper
|
||
* @chainable
|
||
*/
|
||
Snapper.prototype.attachListeners = function (snapper) {
|
||
var $snapper = $(snapper.html).mousemove(
|
||
function () {
|
||
snapper.hide();
|
||
}
|
||
);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the orientation of this snapper.
|
||
* @param {string} orientation
|
||
* @chainable
|
||
*/
|
||
Snapper.prototype.setOrientation = function (orientation) {
|
||
if (orientation === "horizontal" || orientation === "vertical") {
|
||
this.orientation = orientation;
|
||
} else {
|
||
throw new Error("setOrientation(): parameter is not valid");
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the orientation of this snapper.
|
||
* @return {string}
|
||
*/
|
||
Snapper.prototype.getOrientation = function () {
|
||
return this.orientation;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Snapper', Snapper);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Snapper;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @abstract
|
||
* @class PMUI.draw.Router
|
||
* Represents the router used to define the points for a connection.
|
||
* @extend PMUI.draw.Core
|
||
*
|
||
* @constructor Creates an instance of the class Router
|
||
*/
|
||
var Router = function () {
|
||
Router.superclass.call(this);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Core', Router);
|
||
|
||
/**
|
||
* The type of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
Router.prototype.type = "Router";
|
||
|
||
/**
|
||
* @abstract Abstract method to create a route (defined in other inherited classes)
|
||
* @returns {boolean}
|
||
*/
|
||
Router.prototype.createRoute = function () {
|
||
return true;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Router', Router);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Router;
|
||
}
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.ManhattanConnectionRouter
|
||
* Class ManhattanConnectionRouter uses the 'ManhattanRouter' algorithm to define the points of the connection.
|
||
* @extends PMUI.draw.Router
|
||
*
|
||
* @constructor Creates an instance of the class ManhattanConnectionRouter
|
||
*/
|
||
var ManhattanConnectionRouter = function () {
|
||
ManhattanConnectionRouter.superclass.call(this);
|
||
/**
|
||
* Minimum distance used in the algorithm
|
||
* @property {number} [mindist=20]
|
||
*/
|
||
this.mindist = 20;
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Router', ManhattanConnectionRouter);
|
||
|
||
/**
|
||
* The type of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
ManhattanConnectionRouter.prototype.type = "ManhattanConnectionRouter";
|
||
|
||
/**
|
||
* Creates the points of `connection` by calling the #route method and using
|
||
* `connection.srcPort` and `connection.destPort` as the start and end points
|
||
* @param {PMUI.draw.Connection} connection
|
||
* @return {Array} An array of points that define the connection.
|
||
*/
|
||
ManhattanConnectionRouter.prototype.createRoute = function (connection) {
|
||
var fromPt, fromDir, toPt, toDir, points = [];
|
||
|
||
fromPt = connection.srcPort.getPoint(false);
|
||
fromDir = connection.srcPort.direction;
|
||
|
||
toPt = connection.destPort.getPoint(false);
|
||
toDir = connection.destPort.direction;
|
||
|
||
// draw a line between the two points.
|
||
this.route(connection, toPt, toDir, fromPt, fromDir, points);
|
||
return points;
|
||
};
|
||
|
||
/**
|
||
* Implementation of the 'MahattanRouter' algorithm
|
||
* @param {PMUI.draw.Connection} conn Instance of the class Connection
|
||
* @param {PMUI.util.Point} fromPt initial Point
|
||
* @param {number} fromDir route using to begin line
|
||
* UP = 0; RIGHT= 1; DOWN = 2; LEFT = 3;
|
||
* @param {PMUI.util.Point} toPt final Point
|
||
* @param {number} toDir route using to end line
|
||
* UP = 0; RIGHT= 1; DOWN = 2; LEFT = 3;
|
||
* @param {Array} points array where points are saved
|
||
*/
|
||
ManhattanConnectionRouter.prototype.route = function (conn, fromPt, fromDir, toPt, toDir, points) {
|
||
var TOL,
|
||
TOLxTOL,
|
||
UP,
|
||
RIGHT,
|
||
DOWN,
|
||
LEFT,
|
||
xDiff,
|
||
yDiff,
|
||
nPoint,
|
||
dir,
|
||
pos;
|
||
|
||
TOL = 0.1;
|
||
TOLxTOL = 0.01;
|
||
|
||
// fromPt is an x,y to start from.
|
||
// fromDir is an angle that the first link must
|
||
UP = 0;
|
||
RIGHT = 1;
|
||
DOWN = 2;
|
||
LEFT = 3;
|
||
|
||
xDiff = fromPt.x - toPt.x;
|
||
yDiff = fromPt.y - toPt.y;
|
||
|
||
if (((xDiff * xDiff) < (TOLxTOL)) && ((yDiff * yDiff) < (TOLxTOL))) {
|
||
points.push(toPt);
|
||
return;
|
||
}
|
||
|
||
if (fromDir === LEFT) {
|
||
if ((xDiff > 0) && ((yDiff * yDiff) < TOL) && (toDir === RIGHT)) {
|
||
nPoint = toPt;
|
||
dir = toDir;
|
||
} else {
|
||
if (xDiff < 0) {
|
||
nPoint = new PMUI.util.Point(fromPt.x - this.mindist, fromPt.y);
|
||
} else if (((yDiff > 0) && (toDir === DOWN)) || ((yDiff < 0) &&
|
||
(toDir === UP))) {
|
||
nPoint = new PMUI.util.Point(toPt.x, fromPt.y);
|
||
} else if (fromDir === toDir) {
|
||
pos = Math.min(fromPt.x, toPt.x) - this.mindist;
|
||
nPoint = new PMUI.util.Point(pos, fromPt.y);
|
||
} else {
|
||
nPoint = new PMUI.util.Point(fromPt.x - (xDiff / 2), fromPt.y);
|
||
}
|
||
|
||
if (yDiff > 0) {
|
||
dir = UP;
|
||
} else {
|
||
dir = DOWN;
|
||
}
|
||
}
|
||
} else if (fromDir === RIGHT) {
|
||
if ((xDiff < 0) && ((yDiff * yDiff) < TOL) && (toDir === LEFT)) {
|
||
nPoint = toPt;
|
||
dir = toDir;
|
||
} else {
|
||
if (xDiff > 0) {
|
||
nPoint = new PMUI.util.Point(fromPt.x + this.mindist, fromPt.y);
|
||
} else if (((yDiff > 0) && (toDir === DOWN)) || ((yDiff < 0) &&
|
||
(toDir === UP))) {
|
||
nPoint = new PMUI.util.Point(toPt.x, fromPt.y);
|
||
} else if (fromDir === toDir) {
|
||
pos = Math.max(fromPt.x, toPt.x) + this.mindist;
|
||
nPoint = new PMUI.util.Point(pos, fromPt.y);
|
||
} else {
|
||
nPoint = new PMUI.util.Point(fromPt.x - (xDiff / 2), fromPt.y);
|
||
}
|
||
|
||
if (yDiff > 0) {
|
||
dir = UP;
|
||
} else {
|
||
dir = DOWN;
|
||
}
|
||
}
|
||
} else if (fromDir === DOWN) {
|
||
if (((xDiff * xDiff) < TOL) && (yDiff < 0) && (toDir === UP)) {
|
||
nPoint = toPt;
|
||
dir = toDir;
|
||
} else {
|
||
if (yDiff > 0) {
|
||
nPoint = new PMUI.util.Point(fromPt.x, fromPt.y + this.mindist);
|
||
} else if (((xDiff > 0) && (toDir === RIGHT)) || ((xDiff < 0) &&
|
||
(toDir === LEFT))) {
|
||
nPoint = new PMUI.util.Point(fromPt.x, toPt.y);
|
||
} else if (fromDir === toDir) {
|
||
pos = Math.max(fromPt.y, toPt.y) + this.mindist;
|
||
nPoint = new PMUI.util.Point(fromPt.x, pos);
|
||
} else {
|
||
nPoint = new PMUI.util.Point(fromPt.x, fromPt.y - (yDiff / 2));
|
||
}
|
||
|
||
if (xDiff > 0) {
|
||
dir = LEFT;
|
||
} else {
|
||
dir = RIGHT;
|
||
}
|
||
}
|
||
} else if (fromDir === UP) {
|
||
if (((xDiff * xDiff) < TOL) && (yDiff > 0) && (toDir === DOWN)) {
|
||
nPoint = toPt;
|
||
dir = toDir;
|
||
} else {
|
||
if (yDiff < 0) {
|
||
nPoint = new PMUI.util.Point(fromPt.x, fromPt.y - this.mindist);
|
||
} else if (((xDiff > 0) && (toDir === RIGHT)) || ((xDiff < 0) &&
|
||
(toDir === LEFT))) {
|
||
nPoint = new PMUI.util.Point(fromPt.x, toPt.y);
|
||
} else if (fromDir === toDir) {
|
||
pos = Math.min(fromPt.y, toPt.y) - this.mindist;
|
||
nPoint = new PMUI.util.Point(fromPt.x, pos);
|
||
} else {
|
||
nPoint = new PMUI.util.Point(fromPt.x, fromPt.y - (yDiff / 2));
|
||
}
|
||
|
||
if (xDiff > 0) {
|
||
dir = LEFT;
|
||
} else {
|
||
dir = RIGHT;
|
||
}
|
||
}
|
||
}
|
||
|
||
this.route(conn, nPoint, dir, toPt, toDir, points);
|
||
points.push(fromPt);
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.ManhattanConnectionRouter', ManhattanConnectionRouter);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = ManhattanConnectionRouter;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Connection
|
||
* Class that represents a connection between two elements in the diagram.
|
||
*
|
||
* A connection is defined with a set of points, there's a segment between two points e.g. `point[i]`
|
||
* and `point[i + 1]` with `i >= 0` and `i < points.length - 1`, there are two ways to paint a connection:
|
||
*
|
||
* - given *2* {@link PMUI.draw.Port Ports}, use the algorithm 'ManhattanConnection' to define the points
|
||
* - given *n* points, make the segments with the rule defined above (but first let's use the first and
|
||
* the last points to make them {@link PMUI.draw.Port Ports}).
|
||
*
|
||
* Some characteristics of the connection:
|
||
*
|
||
* - The connection has references to its source port and end port.
|
||
* - The `state` of the connection is the set of points that define that connection.
|
||
* - The connections can have a color, the color is an instance of the class Color.
|
||
*
|
||
* The connections can have the following types of segments:
|
||
*
|
||
* - regular (a complete segment)
|
||
* - dotted
|
||
* - segmented
|
||
* - segmented and dotted (mixed)
|
||
*
|
||
* Some examples of the configuration:
|
||
*
|
||
* // e.g.
|
||
* // let's assume that there are two shapes (sourceShape and destShape)
|
||
* // let's assume that srcPort is a port that is stored in sourceShape
|
||
* // let's assume that destPort is a port that is stored in destShape
|
||
* // to create an instance of Connection with regular light green segments
|
||
* var connectionGreen = new PMUI.draw.Connection({
|
||
* srcPort: srcPort,
|
||
* destPort: destPort,
|
||
* segmentColor: new Color(0, 200, 0),
|
||
* segmentStyle: "regular"
|
||
* });
|
||
* // to create an instance of Connection with dotted red segments
|
||
* var connectionRed = new PMUI.draw.Connection({
|
||
* srcPort: srcPort,
|
||
* destPort: destPort,
|
||
* segmentColor: new Color(255, 0, 0),
|
||
* segmentStyle: "dotted"
|
||
* });
|
||
*
|
||
* @extend PMUI.draw.Core
|
||
*
|
||
* @constructor Creates an instance of the class Connection
|
||
* @param {Object} options Initialization options
|
||
* @cfg {PMUI.util.Point} [srcPort=new Port()] Source port of the connection
|
||
* @cfg {PMUI.util.Point} [destPort=new Port()] Destination port of the connection
|
||
* @cfg {PMUI.util.Color} [segmentColor=new Color(0, 0, 0)] Color of the connection (by default it's black)
|
||
* @cfg {string} [segmentStyle="regular"] Type of segments as defined above
|
||
*/
|
||
var Connection = function (options) {
|
||
|
||
Connection.superclass.call(this, options);
|
||
|
||
/**
|
||
* The source port of the connection
|
||
* @property {PMUI.draw.Port}
|
||
*/
|
||
this.srcPort = null;
|
||
|
||
/**
|
||
* The end port of the connection
|
||
* @property {PMUI.draw.Port}
|
||
*/
|
||
this.destPort = null;
|
||
|
||
/**
|
||
* The decorator of the source of the connection
|
||
* @property {PMUI.draw.ConnectionDecorator}
|
||
*/
|
||
this.srcDecorator = null;
|
||
|
||
/**
|
||
* The decorator of the target of the connection
|
||
* @property {PMUI.draw.ConnectionDecorator}
|
||
*/
|
||
this.destDecorator = null;
|
||
|
||
/**
|
||
* List of the lines that forms the connection
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.lineSegments = new PMUI.util.ArrayList();
|
||
|
||
/**
|
||
* Saves a copy of the line segments' points when a flag is passed to the
|
||
* disconnect method (NOTE: this array is used in the
|
||
* userDefinedRoute method)
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.points = [];
|
||
|
||
this.zoomPoints = [];
|
||
/**
|
||
* Saves a copy of the line segments' points when a flag is passed to the
|
||
* disconnect method (NOTE: this array is used while creating the object
|
||
* updatedElement in Canvas.triggerConnectionStateChangeEvent)
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.oldPoints = [];
|
||
|
||
/**
|
||
* Current segment style
|
||
* @property {"dotted" / "regular" / "segmented" / "segmentdot"}
|
||
*/
|
||
this.segmentStyle = null;
|
||
|
||
/**
|
||
* This segment style ej. "dotted", "segmented", "segmentdot" (it's the
|
||
* original style set in `this.initObject()`)
|
||
* @property {"dotted" / "regular" / "segmented" / "segmentdot"}
|
||
*/
|
||
this.originalSegmentStyle = null;
|
||
|
||
/**
|
||
* Actual color of all the segment in this connection
|
||
* @property {PMUI.util.Color}
|
||
*/
|
||
this.segmentColor = null;
|
||
|
||
/**
|
||
* Original color of all the segments in this connection (set in `this.initObject()`)
|
||
* @property {PMUI.util.Color}
|
||
*/
|
||
this.originalSegmentColor = null;
|
||
|
||
/**
|
||
* default zIndex of the connection
|
||
* @property {number}
|
||
*/
|
||
this.defaultZOrder = 2;
|
||
|
||
/**
|
||
* Current zIndex of the connection
|
||
* @property {number}
|
||
*/
|
||
this.zOrder = 2;
|
||
|
||
/**
|
||
* ArrayList which contains the ids of the Connections it has an
|
||
* intersection with:
|
||
*
|
||
* // e.g.
|
||
* // let's assume that there's an instance of the class Connection called anotherConnection
|
||
* intersectionWith = new PMUI.util.ArrayList();
|
||
* intersectionWith.insert(anotherConnection);
|
||
*
|
||
* @property {PMUI.util.ArrayList}
|
||
*/
|
||
this.intersectionWith = new PMUI.util.ArrayList();
|
||
|
||
this.corona = 10;
|
||
|
||
Connection.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Core', Connection);
|
||
|
||
/**
|
||
* The type of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
Connection.prototype.type = "Connection";
|
||
|
||
/**
|
||
* The family of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
Connection.prototype.family = "Connection";
|
||
|
||
/**
|
||
* Router associated with the connection
|
||
* @property {PMUI.draw.Router}
|
||
*/
|
||
Connection.prototype.router = new PMUI.draw.ManhattanConnectionRouter();
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance.
|
||
* @param {Object} options The object that contains the config
|
||
* @private
|
||
*/
|
||
Connection.prototype.init = function (options) {
|
||
var defaultOptions = {
|
||
srcPort: new PMUI.draw.Port(),
|
||
destPort: new PMUI.draw.Port(),
|
||
segmentColor: new PMUI.util.Color(0, 0, 0),
|
||
segmentStyle: "regular"
|
||
};
|
||
|
||
// extend recursively the defaultOptions with the given options
|
||
$.extend(true, defaultOptions, options);
|
||
|
||
// init
|
||
this.setSrcPort(defaultOptions.srcPort)
|
||
.setDestPort(defaultOptions.destPort)
|
||
.setSegmentStyle(defaultOptions.segmentStyle, false)
|
||
.setSegmentColor(defaultOptions.segmentColor, false);
|
||
|
||
// init originals
|
||
this.originalSegmentStyle = defaultOptions.segmentStyle;
|
||
this.originalSegmentColor = defaultOptions.segmentColor;
|
||
|
||
// set the connections for each port as this
|
||
this.getSrcPort().setConnection(this);
|
||
this.getDestPort().setConnection(this);
|
||
};
|
||
|
||
/**
|
||
* Creates the HTML Representation of the Connection.
|
||
* @returns {HTMLElement}
|
||
*/
|
||
Connection.prototype.createHTML = function () {
|
||
this.html = document.createElement('div');
|
||
this.html.id = this.id;
|
||
|
||
this.style.addProperties({
|
||
position: "absolute",
|
||
left: 0,
|
||
top: 0,
|
||
height: 0,
|
||
width: 0,
|
||
zIndex: this.zOrder
|
||
});
|
||
return this.html;
|
||
};
|
||
|
||
|
||
Connection.prototype.attachListeners = function () {
|
||
if (!this.canvas.readOnly) {
|
||
$(this.html).children().click(this.onClick(this));
|
||
}
|
||
};
|
||
|
||
/**
|
||
* @event click
|
||
* Click callback fired when the decorator is clicked on.
|
||
* It hides the currentSelection if any and shows the ports and handlers of `decorator` parent
|
||
* (which is a connection).
|
||
* @param {PMUI.draw.Connection} decorator
|
||
*/
|
||
Connection.prototype.onClick = function (conn) {
|
||
return function (e, ui) {
|
||
var connection = conn,
|
||
oldConnection = conn.canvas.currentConnection,
|
||
canvas = connection.canvas;
|
||
|
||
// HIDE
|
||
// if there were some shapes in the current selection then
|
||
// empty the current selection
|
||
canvas.emptyCurrentSelection();
|
||
|
||
// if there was a connection previously select hide its ports
|
||
// and its handlers
|
||
if (oldConnection) {
|
||
oldConnection.hidePortsAndHandlers();
|
||
}
|
||
|
||
// SHOW
|
||
// show the ports and the handlers of the new connection
|
||
connection.showPortsAndHandlers();
|
||
|
||
// set the old connection as this connection
|
||
canvas.currentConnection = connection;
|
||
|
||
// TODO: zIndex
|
||
e.stopPropagation();
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Sets the handlers for each segment.
|
||
* This method sets the handler for each segment, also sets a variable called hasMoveHandler on each segment to
|
||
* either true or false (it'll be false if the current segment is either the first or the last segment of
|
||
* the connection)
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.setSegmentMoveHandlers = function () {
|
||
var i,
|
||
currentSegment,
|
||
orientationOptions = [this.HORIZONTAL, this.VERTICAL],
|
||
segmentOrientation = (this.destPort.direction === this.TOP ||
|
||
this.destPort.direction === this.BOTTOM) ? 1 : 0;
|
||
for (i = this.lineSegments.getSize() - 1; i >= 0; i -= 1) {
|
||
currentSegment = this.lineSegments.get(i);
|
||
currentSegment.orientation =
|
||
orientationOptions[segmentOrientation];
|
||
currentSegment.hasMoveHandler = false;
|
||
|
||
// set prev and next segments
|
||
if (i < this.lineSegments.getSize() - 1 && i > 0) {
|
||
currentSegment.nextNeighbor = this.lineSegments.get(i + 1);
|
||
currentSegment.previousNeighbor = this.lineSegments.get(i - 1);
|
||
currentSegment.hasMoveHandler = true;
|
||
currentSegment.addSegmentMoveHandler();
|
||
}
|
||
segmentOrientation = 1 - segmentOrientation;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Remove all the segmentHandlers of this connection
|
||
* (removing its html)
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.removeAllSegmentHandlers = function () {
|
||
var segment,
|
||
i;
|
||
for (i = 0; i < this.lineSegments.getSize(); i += 1) {
|
||
segment = this.lineSegments.get(i);
|
||
if (segment.hasMoveHandler) {
|
||
$(segment.moveHandler.html).remove();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Show the moveHandlers of the connections
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.showMoveHandlers = function () {
|
||
var i,
|
||
currentHandler;
|
||
for (i = 0; i < this.lineSegments.getSize(); i += 1) {
|
||
currentHandler = this.lineSegments.get(i).moveHandler;
|
||
if (currentHandler) {
|
||
currentHandler.setVisible(true);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Hide the moveHandlers of the connection
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.hideMoveHandlers = function () {
|
||
var i,
|
||
currentHandler;
|
||
for (i = 0; i < this.lineSegments.getSize(); i += 1) {
|
||
currentHandler = this.lineSegments.get(i).moveHandler;
|
||
if (currentHandler) {
|
||
currentHandler.setVisible(false);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Hides the ports and handlers of this connection.
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.hidePortsAndHandlers = function () {
|
||
this.hidePorts();
|
||
this.hideMoveHandlers();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Shows the ports and handlers of this connection.
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.showPortsAndHandlers = function () {
|
||
this.showPorts();
|
||
this.showMoveHandlers();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Paints the connection according to the parameters given as config options, this method `paint()`
|
||
* unlike other similar `paint()` does not append the HTML to the DOM, this is done with a call
|
||
* to `canvas.addConnection(connection)`.
|
||
* @param {Object} options Configuration options
|
||
* @param {string} [options.algorithm="manhattan"] The algorithm used to draw the connection
|
||
* @param {Array} [options.points=[]] Points to be used if the algorithm is "user"
|
||
* @param {number} [options.dx=0] Move the points dx
|
||
* @param {number} [options.dy=0] Move the points dy
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.paint = function (options) {
|
||
var defaults = {
|
||
algorithm: 'manhattan',
|
||
points: [],
|
||
dx: 0,
|
||
dy: 0
|
||
};
|
||
$.extend(true, defaults, options);
|
||
try {
|
||
if (this.html === null) {
|
||
this.createHTML();
|
||
}
|
||
|
||
$(this.html).empty();
|
||
this.oldPoint = null;
|
||
|
||
switch (defaults.algorithm) {
|
||
case 'manhattan':
|
||
this.createManhattanRoute();
|
||
break;
|
||
case 'user':
|
||
this.createUserDefinedRoute(defaults.points,
|
||
defaults.dx, defaults.dy);
|
||
break;
|
||
default:
|
||
throw new Error('Connection.paint(): the algorithm provided ' +
|
||
'is not correct');
|
||
}
|
||
if (options && options.updateZoomPoints !== undefined) {
|
||
this.savePoints({updateZoomPoints: options.updateZoomPoints});
|
||
} else {
|
||
this.savePoints();
|
||
}
|
||
this.style.applyStyle();
|
||
|
||
// the inline style might have changed in this.move()
|
||
// so restore the style to the original setting
|
||
this.style.addProperties({
|
||
top: 0,
|
||
left: 0
|
||
});
|
||
|
||
// paint the decorator if any exists
|
||
if (this.destDecorator !== null) {
|
||
this.destDecorator.paint();
|
||
if (!this.canvas.readOnly) {
|
||
this.destDecorator.attachListeners();
|
||
}
|
||
}
|
||
if (this.srcDecorator !== null) {
|
||
this.srcDecorator.paint();
|
||
}
|
||
|
||
this.oldPoint = null;
|
||
|
||
} catch (e) {
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Hides the connection and its intersections
|
||
* @param {boolean} [savePoints] If set to true, the connection state will be saved in `this.points
|
||
* (see the definition of {@link PMUI.draw.Connection#property-points} in the definition of the class).
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.disconnect = function (savePoints) {
|
||
this.clearAllIntersections();
|
||
|
||
// hide the segment handlers
|
||
this.hideMoveHandlers();
|
||
|
||
// save the line segments and use them in the createCustomRoute method
|
||
if (savePoints) {
|
||
this.savePoints();
|
||
}
|
||
this.lineSegments.clear();
|
||
|
||
// empty the contents
|
||
$(this.html).empty();
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Connects two elements using options as a parameter (alias for `this.paint`)
|
||
* @param {Object} options Configuration options
|
||
* @param {string} [options.algorithm="manhattan"] The algorithm used to draw the connection
|
||
* @param {Array} [options.points=[]] Points to be used if the algorithm is "user"
|
||
* @param {number} [options.dx=0] Move the points dx
|
||
* @param {number} [options.dy=0] Move the points dy
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.connect = function (options) {
|
||
var i,
|
||
max,
|
||
srcPortPosition,
|
||
destPortPosition,
|
||
lineLength,
|
||
lastPoint,
|
||
currentOrientation,
|
||
newPoint,
|
||
referencePoints,
|
||
x,
|
||
y;
|
||
|
||
if (options && options.algorithm === 'user' && options.points) {
|
||
referencePoints = this.zoomPoints.length ? this.zoomPoints : options.points;
|
||
srcPortPosition = {
|
||
x: Math.round(this.srcPort.getAbsoluteX() + (this.srcPort.getWidth() / 2)),
|
||
y: Math.round(this.srcPort.getAbsoluteY() + (this.srcPort.getHeight() / 2))
|
||
};
|
||
destPortPosition = {
|
||
x: Math.round(this.destPort.getAbsoluteX() + (this.destPort.getWidth() / 2)),
|
||
y: Math.round(this.destPort.getAbsoluteY() + (this.destPort.getHeight() / 2))
|
||
};
|
||
|
||
this.points = [];
|
||
for (i = 0, max = options.points.length; i < max; i += 1) {
|
||
if (i === 0) {
|
||
x = srcPortPosition.x;
|
||
y = srcPortPosition.y;
|
||
currentOrientation = (this.srcPort.getDirection() === this.srcPort.LEFT
|
||
|| this.srcPort.getDirection() === this.srcPort.RIGHT) ? this.srcPort.HORIZONTAL
|
||
: this.srcPort.VERTICAL;
|
||
} else if (i === max - 2 || i === max - 1) {
|
||
if (currentOrientation === this.srcPort.HORIZONTAL) {
|
||
x = destPortPosition.x;
|
||
} else {
|
||
y = destPortPosition.y;
|
||
}
|
||
currentOrientation = currentOrientation === this.srcPort.HORIZONTAL ? this.srcPort.VERTICAL
|
||
: this.srcPort.HORIZONTAL;
|
||
} else {
|
||
if (currentOrientation === this.srcPort.HORIZONTAL) {
|
||
lineLength = (referencePoints[i].x - referencePoints[i - 1].x) * this.canvas.zoomFactor;
|
||
x = lastPoint.x + lineLength;
|
||
} else {
|
||
lineLength = (referencePoints[i].y - referencePoints[i - 1].y) * this.canvas.zoomFactor;
|
||
y = lastPoint.y + lineLength;
|
||
}
|
||
currentOrientation = currentOrientation === this.srcPort.HORIZONTAL ? this.srcPort.VERTICAL
|
||
: this.srcPort.HORIZONTAL;
|
||
}
|
||
newPoint = new PMUI.util.Point(x, y);
|
||
this.points.push(newPoint);
|
||
lastPoint = newPoint;
|
||
}
|
||
options.points = this.points;
|
||
}
|
||
|
||
this.paint(options);
|
||
this.attachListeners();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Hides the ports of the connection
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.hidePorts = function () {
|
||
this.srcPort.hide();
|
||
this.destPort.hide();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Shows the ports of the connection
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.showPorts = function () {
|
||
this.srcPort.show();
|
||
this.destPort.show();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Saves the state of the connection.
|
||
* @param {Object} options
|
||
* @param {boolean} [options.saveToOldPoints=false] If set to true then it will save the state
|
||
* to `this.oldPoints` array
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.savePoints = function (options) {
|
||
var i,
|
||
segment,
|
||
arrayChosen = 'points',
|
||
defaults = {
|
||
saveToOldPoints: false,
|
||
updateZoomPoints: true
|
||
};
|
||
|
||
$.extend(true, defaults, options);
|
||
|
||
if (defaults.saveToOldPoints) {
|
||
arrayChosen = "oldPoints";
|
||
}
|
||
|
||
this[arrayChosen] = [];
|
||
if (defaults.updateZoomPoints) {
|
||
this.zoomPoints = [];
|
||
}
|
||
for (i = 0; i < this.lineSegments.getSize(); i += 1) {
|
||
segment = this.lineSegments.get(i);
|
||
if (i === 0) {
|
||
// insert the startPoint only for the first segment
|
||
this[arrayChosen].push(new PMUI.util.Point(
|
||
segment.startPoint.x,
|
||
segment.startPoint.y
|
||
));
|
||
if (defaults.updateZoomPoints) {
|
||
this.zoomPoints.push(new PMUI.util.Point(
|
||
segment.startPoint.x / this.canvas.zoomFactor,
|
||
segment.startPoint.y / this.canvas.zoomFactor
|
||
));
|
||
}
|
||
}
|
||
this[arrayChosen].push(new PMUI.util.Point(
|
||
segment.endPoint.x,
|
||
segment.endPoint.y
|
||
));
|
||
if (defaults.updateZoomPoints) {
|
||
this.zoomPoints.push(new PMUI.util.Point(
|
||
segment.endPoint.x / this.canvas.zoomFactor,
|
||
segment.endPoint.y / this.canvas.zoomFactor
|
||
));
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Creates the segments of the connection using points and moving the segments dx and dy
|
||
* @param {Array} points
|
||
* @param {number} dx
|
||
* @param {number} dy
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.createUserDefinedRoute = function (points, dx, dy) {
|
||
var i,
|
||
segment,
|
||
diffPoint = new PMUI.util.Point(dx, dy);
|
||
for (i = 1; i < points.length; i += 1) {
|
||
segment = new PMUI.draw.Segment({
|
||
startPoint: new PMUI.util.Point(
|
||
parseInt(points[i - 1].x, 10),
|
||
parseInt(points[i - 1].y, 10)
|
||
).add(diffPoint),
|
||
endPoint: new PMUI.util.Point(
|
||
parseInt(points[i].x, 10),
|
||
parseInt(points[i].y, 10)
|
||
).add(diffPoint),
|
||
parent: this,
|
||
canvas: this.canvas,
|
||
color: this.segmentColor
|
||
});
|
||
this.addSegment(segment);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Create the segments of the connection using the points defined by the algorithm "ManhattanConnection"
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.createManhattanRoute = function () {
|
||
var points = this.router.createRoute(this),
|
||
i,
|
||
segment;
|
||
// create the segments now that we have the points
|
||
for (i = 1; i < points.length; i += 1) {
|
||
segment = new PMUI.draw.Segment({
|
||
startPoint: new PMUI.util.Point(
|
||
parseInt(points[i - 1].x - this.canvas.absoluteX, 10),
|
||
parseInt(points[i - 1].y - this.canvas.absoluteY, 10)
|
||
),
|
||
endPoint: new PMUI.util.Point(
|
||
parseInt(points[i].x - this.canvas.absoluteX, 10),
|
||
parseInt(points[i].y - this.canvas.absoluteY, 10)
|
||
),
|
||
parent: this,
|
||
canvas: this.canvas,
|
||
color: this.segmentColor
|
||
});
|
||
this.addSegment(segment);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Add a segment to the line segments arrayList (painting it first)
|
||
* @param {PMUI.draw.Segment} segment
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.addSegment = function (segment) {
|
||
segment.setStyle(this.segmentStyle);
|
||
segment.paint();
|
||
this.lineSegments.insert(segment);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Destroys the connection but saving its HTML first
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.saveAndDestroy = function () {
|
||
|
||
if (this.canvas.currentConnection) {
|
||
this.hidePortsAndHandlers();
|
||
this.canvas.currentConnection = null;
|
||
}
|
||
|
||
// remove this from the canvas connections arrayList
|
||
this.canvas.removeConnection(this);
|
||
|
||
//this.canvas.removeFromList(this);
|
||
this.srcPort.saveAndDestroy(); //destroy srcPort
|
||
this.destPort.saveAndDestroy(); //destroy destPort
|
||
|
||
// save the html but detach it from the DOM
|
||
this.html = $(this.html).detach()[0];
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Fixes the zIndex of the connection based on the parents of the connection ports (which are
|
||
* shapes), the zIndex is defined as the maximum zIndex the ports parents + 2
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.fixZIndex = function () {
|
||
var sourceShape = this.srcPort.parent,
|
||
destShape = this.destPort.parent,
|
||
sourceShapeParent,
|
||
destShapeParent,
|
||
sourceShapeParentZIndex,
|
||
destShapeParentZIndex;
|
||
|
||
if (sourceShape.parent) {
|
||
sourceShapeParent = sourceShape.parent;
|
||
} else {
|
||
sourceShapeParent = sourceShape.canvas;
|
||
}
|
||
sourceShapeParentZIndex = Math.min(sourceShapeParent.getZOrder(),
|
||
sourceShape.getZOrder() - 1);
|
||
|
||
if (destShape.parent) {
|
||
destShapeParent = destShape.parent;
|
||
} else {
|
||
destShapeParent = destShape.canvas;
|
||
}
|
||
destShapeParentZIndex = Math.min(destShapeParent.getZOrder(),
|
||
destShape.getZOrder() - 1);
|
||
|
||
this.setZOrder(Math.max(sourceShapeParentZIndex, destShapeParentZIndex) +
|
||
2);
|
||
return this;
|
||
};
|
||
/**
|
||
* Checks and creates intersections of `this` connection with the `otherConnection`
|
||
* @param {PMUI.draw.Connection} otherConnection
|
||
* @return {boolean} True if there is at least one intersection
|
||
*/
|
||
Connection.prototype.checkAndCreateIntersections = function (otherConnection) {
|
||
// iterate over all the segments of this connection
|
||
var i,
|
||
j,
|
||
segment,
|
||
testingSegment,
|
||
hasAtLeastOneIntersection = false,
|
||
ip; // intersectionPoint
|
||
|
||
for (i = 0; i < this.lineSegments.getSize(); i += 1) {
|
||
segment = this.lineSegments.get(i);
|
||
for (j = 0; j < otherConnection.lineSegments.getSize(); j += 1) {
|
||
testingSegment = otherConnection.lineSegments.get(j);
|
||
|
||
// create the intersection of the segments if possible
|
||
ip = PMUI.draw.Geometry.perpendicularSegmentIntersection(segment.startPoint,
|
||
segment.endPoint, testingSegment.startPoint,
|
||
testingSegment.endPoint);
|
||
if (ip) {
|
||
hasAtLeastOneIntersection = true;
|
||
segment.createIntersectionWith(testingSegment, ip);
|
||
}
|
||
}
|
||
}
|
||
if (hasAtLeastOneIntersection) {
|
||
if (!this.intersectionWith.find('id', otherConnection.getID())) {
|
||
this.intersectionWith.insert(otherConnection);
|
||
}
|
||
if (!otherConnection.intersectionWith.find('id', this.getID())) {
|
||
otherConnection.intersectionWith.insert(this);
|
||
}
|
||
}
|
||
return hasAtLeastOneIntersection;
|
||
};
|
||
|
||
/**
|
||
* Checks and creates intersections with all the other connections found in this canvas.
|
||
* This method also repaints the segments that have intersections.
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.checkAndCreateIntersectionsWithAll = function () {
|
||
var i,
|
||
otherConnection,
|
||
segment;
|
||
// create the intersections of this connection
|
||
// each segment of this connection saves the intersections it has with
|
||
// other segments as an ArrayList of Intersections
|
||
// console.log(this.canvas.connections.getSize());
|
||
for (i = 0; i < this.canvas.connections.getSize(); i += 1) {
|
||
otherConnection = this.canvas.connections.get(i);
|
||
if (otherConnection.getID() !== this.getID()) {
|
||
this.checkAndCreateIntersections(otherConnection);
|
||
}
|
||
}
|
||
|
||
// after we've got all the intersections
|
||
// paint the segments with their intersections
|
||
for (i = 0; i < this.lineSegments.getSize(); i += 1) {
|
||
segment = this.lineSegments.get(i);
|
||
if (segment.intersections.getSize()) {
|
||
segment.paintWithIntersections();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Clears all the intersections with the otherConnection that exist in this connection
|
||
* @param {PMUI.draw.Connection} otherConnection
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.clearIntersectionsWith = function (otherConnection) {
|
||
var i,
|
||
segment,
|
||
intersectionObject,
|
||
intersectionWasErased;
|
||
for (i = 0; i < this.lineSegments.getSize(); i += 1) {
|
||
intersectionWasErased = false;
|
||
segment = this.lineSegments.get(i);
|
||
while (true) {
|
||
intersectionObject = segment.
|
||
intersections.find('idOtherConnection',
|
||
otherConnection.getID());
|
||
if (intersectionObject) {
|
||
segment.intersections.remove(intersectionObject);
|
||
intersectionObject.destroy();
|
||
} else {
|
||
break;
|
||
}
|
||
intersectionWasErased = true;
|
||
}
|
||
if (intersectionWasErased) {
|
||
segment.paintWithIntersections();
|
||
}
|
||
}
|
||
// remove other connection from this connection intersectionWith ArrayList
|
||
this.intersectionWith.remove(otherConnection);
|
||
otherConnection.intersectionWith.remove(this);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Clear all the intersections of this connection calling clearIntersectionsWith
|
||
* many times (one for each connection that exists in the canvas)
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.clearAllIntersections = function () {
|
||
var otherIntersection;
|
||
while (this.intersectionWith.getSize() > 0) {
|
||
otherIntersection = this.intersectionWith.get(0);
|
||
otherIntersection.clearIntersectionsWith(this);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Moves the connection [dx, dy]
|
||
* @param {number} dx
|
||
* @param {number} dy
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.move = function (dx, dy) {
|
||
var top,
|
||
left;
|
||
|
||
// moving with inline style
|
||
top = parseFloat(this.html.style.top);
|
||
left = parseFloat(this.html.style.left);
|
||
$(this.html).css({
|
||
'top': top + dy,
|
||
'left': left + dx
|
||
});
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Serializes this object (as a JavaScript object)
|
||
* @return {Object}
|
||
* @return {string} return.segmentStyle The style of each segment of this connection
|
||
* @return {Object} return.srcPort The serialization of `this.srcPort`
|
||
* @return {Object} return.destPort The serialization of `this.destPort`
|
||
* @return {Array} return.state The array of points that represent this connection a.k.a. state
|
||
* @return {string} return.srcDecoratorPrefix The source decorator prefix
|
||
* @return {string} return.destDecoratorPrefix The destination decorator prefix
|
||
*/
|
||
Connection.prototype.stringify = function () {
|
||
return {
|
||
segmentStyle: this.getSegmentStyle(),
|
||
srcPort: this.getSrcPort().stringify(),
|
||
destPort: this.getDestPort().stringify(),
|
||
state: this.savePoints() && this.points,
|
||
srcDecoratorPrefix: this.getSrcDecorator().getDecoratorPrefix(),
|
||
destDecoratorPrefix: this.getDestDecorator().getDecoratorPrefix()
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Sets the color of the segments of this connection
|
||
* @param {PMUI.util.Color} newColor
|
||
* @param {boolean} [repaint] True if the segment are to be painted immediately
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.setSegmentColor = function (newColor, repaint) {
|
||
var i,
|
||
segment;
|
||
this.segmentColor = newColor;
|
||
if (this.html && repaint) {
|
||
for (i = 0; i < this.lineSegments.getSize(); i += 1) {
|
||
segment = this.lineSegments.get(i);
|
||
segment.setColor(this.segmentColor);
|
||
segment.paint();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Get the segment color of this connection
|
||
* @return {PMUI.util.Color}
|
||
*/
|
||
Connection.prototype.getSegmentColor = function () {
|
||
return this.segmentColor;
|
||
};
|
||
|
||
/**
|
||
* Sets the style of each segment of this connection
|
||
* @param {string} newStyle
|
||
* @param {boolean} [repaint] True if the segment are to be painted immediately
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.setSegmentStyle = function (newStyle, repaint) {
|
||
var i,
|
||
segment;
|
||
this.segmentStyle = newStyle;
|
||
if (this.html && repaint) {
|
||
for (i = 0; i < this.lineSegments.getSize(); i += 1) {
|
||
segment = this.lineSegments.get(i);
|
||
segment.setStyle(this.segmentStyle);
|
||
segment.paint();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Get the segment style of this connection
|
||
* @return {string}
|
||
*/
|
||
Connection.prototype.getSegmentStyle = function () {
|
||
return this.segmentStyle;
|
||
};
|
||
|
||
/**
|
||
* Sets the source port
|
||
* @param {PMUI.draw.Port} newSrcPort
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.setSrcPort = function (newSrcPort) {
|
||
this.srcPort = newSrcPort;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the source port
|
||
* @return {PMUI.draw.Port}
|
||
*/
|
||
Connection.prototype.getSrcPort = function () {
|
||
return this.srcPort;
|
||
};
|
||
|
||
/**
|
||
* Sets the destination port
|
||
* @param {PMUI.draw.Port} newDestPort
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.setDestPort = function (newDestPort) {
|
||
this.destPort = newDestPort;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the destination port
|
||
* @return {PMUI.draw.Port}
|
||
*/
|
||
Connection.prototype.getDestPort = function () {
|
||
return this.destPort;
|
||
};
|
||
|
||
/**
|
||
* Returns the source decorator of the connection
|
||
* @returns {PMUI.draw.ConnectionDecorator}
|
||
*/
|
||
Connection.prototype.getSrcDecorator = function () {
|
||
return this.srcDecorator;
|
||
};
|
||
/**
|
||
* Returns the target decorator of the connection
|
||
* @returns {PMUI.draw.ConnectionDecorator}
|
||
*/
|
||
Connection.prototype.getDestDecorator = function () {
|
||
return this.destDecorator;
|
||
};
|
||
/**
|
||
* Returns a list of the lines associated with this connection
|
||
* @returns {PMUI.util.ArrayList}
|
||
*/
|
||
Connection.prototype.getLineSegments = function () {
|
||
return this.lineSegments;
|
||
};
|
||
|
||
/**
|
||
* Sets the source decorator of the connection
|
||
* @param {PMUI.draw.ConnectionDecorator} newDecorator
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.setSrcDecorator = function (newDecorator) {
|
||
if (newDecorator.type === 'ConnectionDecorator') {
|
||
this.srcDecorator = newDecorator;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the destination decorator of the connection
|
||
* @param {PMUI.draw.ConnectionDecorator} newDecorator
|
||
* @chainable
|
||
*/
|
||
Connection.prototype.setDestDecorator = function (newDecorator) {
|
||
if (newDecorator.type === 'ConnectionDecorator') {
|
||
this.destDecorator = newDecorator;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the zOrder of the connection
|
||
* @return {number}
|
||
*/
|
||
Connection.prototype.getZOrder = function () {
|
||
return PMUI.draw.Shape.prototype.getZOrder.call(this);
|
||
};
|
||
|
||
/**
|
||
* Gets the oldPoints of the connection
|
||
* @return {Array}
|
||
*/
|
||
Connection.prototype.getOldPoints = function () {
|
||
return this.oldPoints;
|
||
};
|
||
|
||
/**
|
||
* Gets the points of the connection
|
||
* @return {Array}
|
||
*/
|
||
Connection.prototype.getPoints = function () {
|
||
return this.points;
|
||
};
|
||
|
||
Connection.prototype.hitTest = function (point) {
|
||
var count = this.getLineSegments().asArray().length,
|
||
i,
|
||
segment,
|
||
response;
|
||
|
||
for (i = 0; i < count; i += 1) {
|
||
segment = this.getLineSegments().get(i);
|
||
response = segment.hit(this.corona, point);
|
||
if (response) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
|
||
Connection.prototype.applyZoom = function () {
|
||
this.disconnect(false);
|
||
this.connect({
|
||
algorithm: 'user',
|
||
points: this.points,
|
||
updateZoomPoints: false
|
||
});
|
||
this.canvas.refreshArray.insert(this);
|
||
this.setSegmentMoveHandlers();
|
||
this.checkAndCreateIntersectionsWithAll();
|
||
};
|
||
|
||
Connection.prototype.reconnectUser = function (delta, inContainer) {
|
||
var j;
|
||
if (delta) {
|
||
for (j = 0; j < this.points.length; j += 1) {
|
||
this.points[j].x += delta.dx * this.canvas.zoomFactor;
|
||
this.points[j].y += delta.dy * this.canvas.zoomFactor;
|
||
}
|
||
|
||
this.disconnect(inContainer);
|
||
this.connect({
|
||
algorithm: 'user',
|
||
points: this.points
|
||
});
|
||
}
|
||
};
|
||
|
||
Connection.prototype.reconnectManhattah = function (inContainer) {
|
||
this.disconnect(inContainer);
|
||
this.connect();
|
||
};
|
||
/**
|
||
* Increases z-index to bring to front a connection
|
||
* @returns {PMUI.draw.Connection}
|
||
*/
|
||
Connection.prototype.increaseZIndex = function () {
|
||
this.setZOrder(PMUI.util.Style.MAX_ZINDEX);
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Connection', Connection);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Connection;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.ConnectionDecorator
|
||
* Represents the decorator on each endpoint of a connection (represented as srcDecorator and destDecorator in
|
||
* the class Connection).
|
||
* The connection will be painted as follows:
|
||
*
|
||
* 1. Each connection decorator is painted with a CSS sprite
|
||
* 2. The CSS class is built concatenating (with underscores) the following:
|
||
*
|
||
* 1. The prefix (passed as an argument in the config options)
|
||
* 2. The zoom factor multiplied by 100
|
||
* 3. The decorator type (passed as an argument in the config options)
|
||
* 4. The direction of the decorator (which is the same as the direction of the port it corresponds to)
|
||
*
|
||
* Some examples:
|
||
*
|
||
* // e.g.
|
||
* // let's assume that the zoom factor is 1
|
||
* // let's assume that connection is an instance of the class Connection
|
||
*
|
||
* // To create a target decorator
|
||
* var connectionDecorator = new PMUI.draw.ConnectionDecorator({
|
||
* decoratorPrefix: 'con',
|
||
* decoratorType: 'target',
|
||
* style: {
|
||
* cssClasses: [],
|
||
* cssProperties: {}
|
||
* },
|
||
* parent: connection
|
||
* });
|
||
*
|
||
* // assuming that the direction of the port is (1) TOP
|
||
* // paint() will build the class like this:
|
||
* // CSSClass = decoratorPrefix + "_" + zoomFactor * 100 + "_" + decoratorType + "_" + direction
|
||
* // CSSClass = "con_100_target_TOP"
|
||
*
|
||
* // To create a source decorator
|
||
* var connectionDecorator = new PMUI.draw.ConnectionDecorator({
|
||
* decoratorPrefix: 'con',
|
||
* decoratorType: 'source',
|
||
* style: {
|
||
* cssClasses: [],
|
||
* cssProperties: {}
|
||
* },
|
||
* parent: connection
|
||
* });
|
||
*
|
||
* // assuming that the direction of the port is (3) LEFT
|
||
* // paint() will build the class like this:
|
||
* // CSSClass = decoratorPrefix + "_" + zoomFactor * 100 + "_" + decoratorType + "_" + direction
|
||
* // CSSClass = "con_100_source_LEFT"
|
||
*
|
||
* @extends PMUI.draw.Core
|
||
*
|
||
* @constructor Creates an instance of the class ConnectionDecorator
|
||
* @param {Object} options Initialization options
|
||
* @cfg {PMUI.util.Point} [decoratorPrefix=''] Decorator prefix used to
|
||
reconstruct the css class for the sprite
|
||
* @cfg {PMUI.draw.Connection} [parent=null] The parent of this decorator
|
||
(must be an instance of the class Connection)
|
||
* @cfg {Object} [style={cssClasses: [], cssProperties: {}}] CSS classes and properties
|
||
*/
|
||
var ConnectionDecorator = function (options) {
|
||
|
||
ConnectionDecorator.superclass.call(this, options);
|
||
|
||
/**
|
||
* Parent of this decorator (must be a Connection)
|
||
* @property {PMUI.draw.Connection}
|
||
*/
|
||
this.parent = null;
|
||
|
||
/**
|
||
* The type of this decorator (either "source" or "target")
|
||
* @property {"source" / "target"}
|
||
*/
|
||
this.decoratorType = null;
|
||
|
||
/**
|
||
* Decorator prefix of this decorator to build the CSS class for the sprite
|
||
* @property {String}
|
||
*/
|
||
this.decoratorPrefix = null;
|
||
|
||
/**
|
||
* This parameter is an array to see if the end point
|
||
* is UP, RIGHT, BOTTOM and LEFT
|
||
* @property {Object} spriteDirection
|
||
* @property {string} [spriteDirection.0="up"] Enum for "up"
|
||
* @property {string} [spriteDirection.1="right"] Enum for "right"
|
||
* @property {string} [spriteDirection.2="bottom"] Enum for "bottom"
|
||
* @property {string} [spriteDirection.3="left"] Enum for "left"
|
||
*/
|
||
this.spriteDirection = {
|
||
'0': 'top', '1': 'right',
|
||
'2': 'bottom', '3': 'left'
|
||
};
|
||
|
||
/**
|
||
* Height of this decorator
|
||
* @property {number} [height=11]
|
||
*/
|
||
this.height = 11;
|
||
|
||
/**
|
||
* Width of this decorator
|
||
* @property {number} [width=11]
|
||
*/
|
||
this.width = 11;
|
||
|
||
/**
|
||
* Separator used to build the class
|
||
* @type {String}
|
||
*/
|
||
this.separator = null;
|
||
|
||
/**
|
||
* Sprite used to build the class
|
||
* @type {String}
|
||
*/
|
||
this.sprite = null;
|
||
|
||
/**
|
||
* The class that will be constructed using the parameters given in
|
||
* the options object
|
||
* @type {string}
|
||
*/
|
||
this.cssClass = null;
|
||
|
||
ConnectionDecorator.prototype.initObject.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Core', ConnectionDecorator);
|
||
|
||
/**
|
||
* Type of this connection decorator
|
||
* @property {String}
|
||
*/
|
||
ConnectionDecorator.prototype.type = "ConnectionDecorator";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance
|
||
* @param {Object} options The object that contains the config
|
||
* @private
|
||
*/
|
||
ConnectionDecorator.prototype.initObject = function (options) {
|
||
|
||
var defaults = {
|
||
width: 11,
|
||
height: 11,
|
||
sprite: 'bpmn_zoom',
|
||
decoratorPrefix: '',
|
||
separator: '_',
|
||
decoratorType: 'target',
|
||
parent: null
|
||
};
|
||
|
||
// extend recursively the defaultOptions with the given options
|
||
$.extend(true, defaults, options);
|
||
|
||
// init
|
||
this.setDecoratorType(defaults.decoratorType)
|
||
.setDecoratorPrefix(defaults.decoratorPrefix)
|
||
.setSeparator(defaults.separator)
|
||
.setSprite(defaults.sprite)
|
||
.setParent(defaults.parent)
|
||
.setDimension(defaults.width, defaults.height)
|
||
.setCssClass(''); // cssClass defaults to empty
|
||
};
|
||
|
||
/**
|
||
* Paints the connectionDecorator according to the parameters saved in `this.initObject`.
|
||
* The steps to paint the decorator are:
|
||
*
|
||
* 1. Determine if this decorator belongs to the source or destination port
|
||
* 2. Determine the direction of the decorator
|
||
* 3. Build the class using the direction, decorator prefix, decorator type and zoom
|
||
* 4. Determine the position of this decorator
|
||
*
|
||
* @chainable
|
||
*/
|
||
ConnectionDecorator.prototype.paint = function (options) {
|
||
var linePoint,
|
||
portPoint,
|
||
canvas,
|
||
direction,
|
||
lineSegment,
|
||
port,
|
||
topStyle,
|
||
leftStyle;
|
||
|
||
if (this.decoratorType === "source") {
|
||
port = this.parent.getSrcPort();
|
||
lineSegment = this.parent.lineSegments.get(0);
|
||
linePoint = lineSegment.startPoint;
|
||
} else {
|
||
port = this.parent.getDestPort();
|
||
lineSegment = this.parent.lineSegments.get(this.parent.lineSegments.getSize() - 1);
|
||
linePoint = lineSegment.endPoint;
|
||
}
|
||
|
||
portPoint = port.getPoint();
|
||
portPoint.x = Math.round(portPoint.x - this.canvas.absoluteX);
|
||
portPoint.y = Math.round(portPoint.y - this.canvas.absoluteY);
|
||
|
||
direction = port.getDirection();
|
||
canvas = port.canvas;
|
||
|
||
switch (direction) {
|
||
case 0:
|
||
case 2:
|
||
if (this.zoomWidth % 2 === 0) {
|
||
leftStyle = (this.zoomWidth / 2) - 1;
|
||
} else {
|
||
leftStyle = Math.floor(this.zoomWidth / 2);
|
||
}
|
||
leftStyle = linePoint.x - leftStyle;
|
||
topStyle = portPoint.y - (direction === 0 ? this.zoomHeight : 0);
|
||
break;
|
||
case 1:
|
||
case 3:
|
||
if (this.zoomHeight % 2 === 0) {
|
||
topStyle = (this.zoomHeight / 2) - 1;
|
||
} else {
|
||
topStyle = Math.floor(this.zoomHeight / 2);
|
||
}
|
||
topStyle = linePoint.y - topStyle;
|
||
leftStyle = portPoint.x - ((direction === 1) ? 0 : this.zoomWidth);
|
||
break;
|
||
default:
|
||
throw new Error("paint(): invalid direction.");
|
||
}
|
||
|
||
if (this.getHTML() === null) {
|
||
this.createHTML();
|
||
}
|
||
|
||
if (this.decoratorType === null) {
|
||
this.html = null;
|
||
return this;
|
||
}
|
||
|
||
// remove the last class if possible
|
||
this.style.removeClasses([this.cssClass]);
|
||
|
||
// construct the new class to be applied
|
||
this.setCssClass([this.prefix, parseInt(canvas.zoomFactor * 100, 10),
|
||
this.decoratorType, this.spriteDirection[direction]].join(this.separator));
|
||
|
||
this.style.addClasses([
|
||
this.sprite,
|
||
this.getCssClass()
|
||
]);
|
||
|
||
// top and left position
|
||
this.style.addProperties({
|
||
top: topStyle,
|
||
left: leftStyle
|
||
});
|
||
|
||
this.parent.html.appendChild(this.html);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Creates the HTML Representation of the SourceSpriteConnectionDecorator
|
||
* @returns {HTMLElement}
|
||
*/
|
||
ConnectionDecorator.prototype.createHTML = function () {
|
||
this.html = document.createElement('div');
|
||
this.html.id = this.id;
|
||
this.style.applyStyle();
|
||
this.style.addProperties({
|
||
position: "absolute",
|
||
left: 0,
|
||
top: 0,
|
||
height: this.zoomHeight,
|
||
width: this.zoomWidth,
|
||
zIndex: PMUI.util.Style.MAX_ZINDEX
|
||
});
|
||
|
||
return this.html;
|
||
};
|
||
|
||
/**
|
||
* Attaches listeners to the connectionDecorator (currently it has click and mouseDown events)
|
||
* @chainable
|
||
*/
|
||
ConnectionDecorator.prototype.attachListeners = function () {
|
||
var $connectionDecorator;
|
||
$connectionDecorator = $(this.getHTML()).click(this.onClick(this));
|
||
$connectionDecorator.on("mousedown", this.onMouseDown(this));
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Refresh the dimension and position of the decorator to apply the current
|
||
* zoom scale
|
||
* @chainable
|
||
*/
|
||
ConnectionDecorator.prototype.applyZoom = function () {
|
||
this.setDimension(this.width, this.height);
|
||
return this;
|
||
};
|
||
/**
|
||
* @event mousedown
|
||
* ConnectionDecorator mouse down callback fired when the mouse is down on it.
|
||
* @param {PMUI.draw.ConnectionDecorator} decorator
|
||
*/
|
||
ConnectionDecorator.prototype.onMouseDown = function (decorator) {
|
||
return function (e, ui) {
|
||
e.preventDefault();
|
||
if (e.which === 3) {
|
||
decorator.parent.canvas.updatedElement = decorator.parent;
|
||
$(decorator.parent.canvas.html).trigger("rightclick");
|
||
}
|
||
e.stopPropagation();
|
||
};
|
||
};
|
||
/**
|
||
* @event click
|
||
* Click callback fired when the decorator is clicked on.
|
||
* It hides the currentSelection if any and shows the ports and handlers of `decorator` parent
|
||
* (which is a connection).
|
||
* @param {PMUI.draw.ConnectionDecorator} decorator
|
||
*/
|
||
ConnectionDecorator.prototype.onClick = function (decorator) {
|
||
return function (e, ui) {
|
||
var connection = decorator.parent,
|
||
oldConnection = decorator.parent.canvas.currentConnection,
|
||
canvas = connection.canvas;
|
||
|
||
// SHOW
|
||
// show the ports and the handlers of the new connection
|
||
connection.showPortsAndHandlers();
|
||
|
||
// HIDE
|
||
// if there were some shapes in the current selection then
|
||
// empty the current selection
|
||
canvas.emptyCurrentSelection();
|
||
|
||
// if there was a connection previously select hide its ports
|
||
// and its handlers
|
||
if (oldConnection) {
|
||
oldConnection.hidePortsAndHandlers();
|
||
}
|
||
// set the old connection as this connection
|
||
canvas.currentConnection = connection;
|
||
|
||
// TODO: zIndex
|
||
e.stopPropagation();
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Serializes this connection decorator.
|
||
* @return {Object}
|
||
* @return {"source" / "target"} return.decoratorType The decorator type to build the CSS class for the sprite
|
||
* @return {string} return.decoratorPrefix The decorator prefix to build the CSS class for the sprite
|
||
*/
|
||
ConnectionDecorator.prototype.stringify = function () {
|
||
var inheritedJSON = {},
|
||
thisJSON = {
|
||
decoratorType: this.getDecoratorType(),
|
||
decoratorPrefix: this.getDecoratorPrefix()
|
||
};
|
||
$.extend(true, inheritedJSON, thisJSON);
|
||
return inheritedJSON;
|
||
};
|
||
|
||
/**
|
||
* Returns the decorator type
|
||
* @returns {String}
|
||
*/
|
||
ConnectionDecorator.prototype.getDecoratorType = function () {
|
||
return this.decoratorType;
|
||
};
|
||
|
||
/**
|
||
* Sets the decoration type
|
||
* @param {String} newType
|
||
* @chainable
|
||
*/
|
||
ConnectionDecorator.prototype.setDecoratorType = function (newType) {
|
||
this.decoratorType = newType;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the decorator type
|
||
* @returns {String}
|
||
*/
|
||
ConnectionDecorator.prototype.getDecoratorPrefix = function () {
|
||
return this.prefix;
|
||
};
|
||
|
||
/**
|
||
* Sets the decoration prefix
|
||
* @param {String} newType
|
||
* @chainable
|
||
*/
|
||
ConnectionDecorator.prototype.setDecoratorPrefix = function (newType) {
|
||
this.prefix = newType;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the parent of this connectionDecorator
|
||
* @param {PMUI.draw.Connection} newParent
|
||
* @chainable
|
||
*/
|
||
ConnectionDecorator.prototype.setParent = function (newParent) {
|
||
this.parent = newParent;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the parent of this connectionDecorator
|
||
* @return {PMUI.draw.Connection}
|
||
*/
|
||
ConnectionDecorator.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
|
||
/**
|
||
* Sets the separator of this connectionDecorator
|
||
* @param {String} newSeparator
|
||
* @chainable
|
||
*/
|
||
ConnectionDecorator.prototype.setSeparator = function (newSeparator) {
|
||
this.separator = newSeparator;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the sprite of this connectionDecorator
|
||
* @param {String} newSprite
|
||
* @chainable
|
||
*/
|
||
ConnectionDecorator.prototype.setSprite = function (newSprite) {
|
||
this.sprite = newSprite;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the cssClass of this connectionDecorator
|
||
* @param {string} newCssClass
|
||
* @chainable
|
||
*/
|
||
ConnectionDecorator.prototype.setCssClass = function (newCssClass) {
|
||
this.cssClass = newCssClass;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the cssClass of this connectionDecorator
|
||
* @return {string}
|
||
*/
|
||
ConnectionDecorator.prototype.getCssClass = function () {
|
||
return this.cssClass;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.ConnectionDecorator', ConnectionDecorator);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = ConnectionDecorator;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
*
|
||
* @class PMUI.draw.Layer
|
||
* Class that contains the properties of a layer for a shape we need
|
||
* to have a shape already instantiated and added to the canvas in order for
|
||
* this class to be effective
|
||
*
|
||
* //e.g.
|
||
* var layer = new PMUI.draw.Layer({
|
||
* //Determine the layer's parent
|
||
* parent: customShape,
|
||
* layerName: "first layer",
|
||
* //the order in which the layers will be added in increasing
|
||
* //order
|
||
* priority: 0,
|
||
* //determines if the layer will be hidden or visible
|
||
* visible: true,
|
||
* //sprites to be applied on the layers according to a zoom
|
||
* //scale
|
||
* zoomSprites : ["class50, class75, class100, class125,
|
||
* class 150"]
|
||
* });
|
||
* @extend PMUI.draw.Core
|
||
*
|
||
* @constructor
|
||
* Initializes a layer, the constructor must be called with all its parameter
|
||
* for the object to be meaningful, its is important to denote that the css
|
||
* class must follow this structure
|
||
* any word_zoomScale_anythingYouWantHere
|
||
* @param {Object} options
|
||
* @cfg {Object} parent, Parent of a corresponding layer, a layer may not exist
|
||
* without a parent
|
||
* @cfg {String} [layerName="defaultLayerName"] A name we want to label a layer
|
||
* with
|
||
* @cfg {number} [priority=0] The orders in which the layers will be added in
|
||
* increasing order
|
||
* @cfg {boolean} [visible=true] Determines whether a layer wll be visible or
|
||
* hidden
|
||
* @cfg {Array} [zoomSprites=["","","","",""]] Sprites to be applied to the
|
||
* layer according to a zoom scale
|
||
*/
|
||
var Layer = function (options) {
|
||
|
||
// TODO: check elementClass and bpmnClass removal impact on the layers
|
||
//Layer = function (parent, name, elementClass, priority, bpmnClass, visible) {
|
||
|
||
Layer.superclass.call(this, options);
|
||
|
||
/**
|
||
* The name of the layer
|
||
* @property {String}
|
||
*/
|
||
this.layerName = null;
|
||
|
||
/**
|
||
* The priority of the layer, determines which layer should be on top
|
||
* @property {number}
|
||
*/
|
||
this.priority = null;
|
||
|
||
/**
|
||
* The bpmnShape that this layer belongs too.
|
||
* Extremely important since some data will be strictly drawn by its parent
|
||
* @property {Object}
|
||
*/
|
||
this.parent = null;
|
||
|
||
/**
|
||
* Determines when a layer is visible or not
|
||
* @property boolean
|
||
*/
|
||
this.visible = null;
|
||
|
||
/**
|
||
* Determines when a layer is resizable or not
|
||
* @property boolean
|
||
*/
|
||
this.resizable = null;
|
||
|
||
/**
|
||
* The current Sprite applied in the zoom scale
|
||
* @property {String}
|
||
*/
|
||
this.currentZoomClass = "";
|
||
/**
|
||
* Sprites for the layer in each zoom scale
|
||
* @property {Array}
|
||
*/
|
||
this.zoomSprites = [];
|
||
|
||
Layer.prototype.initObject.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Core', Layer);
|
||
|
||
/**
|
||
* Type of an instance of this class
|
||
* @property {String}
|
||
*/
|
||
Layer.prototype.type = "Layer";
|
||
|
||
/**
|
||
* Object init method (internal)
|
||
* @param {Object} options
|
||
*/
|
||
Layer.prototype.initObject = function (options) {
|
||
/**
|
||
* Default options for the object
|
||
* @property {Object}
|
||
*/
|
||
var defaults = {
|
||
x: 0,
|
||
y: 0,
|
||
parent: null,
|
||
layerName: "defaultLayerName",
|
||
resizable: true,
|
||
priority: 0,
|
||
visible: true,
|
||
zoomSprites: ["", "", "", "", ""]
|
||
};
|
||
|
||
// extend recursively the defaultOptions with the given options
|
||
$.extend(true, defaults, options);
|
||
|
||
// call setters using the defaults object
|
||
this.setParent(defaults.parent)
|
||
.setPosition(defaults.x, defaults.y)
|
||
.setLayerName(defaults.layerName)
|
||
.setPriority(defaults.priority)
|
||
.setVisible(defaults.visible)
|
||
.setZoomSprites(defaults.zoomSprites)
|
||
.setProperties()
|
||
.setResizable(defaults.resizable);
|
||
|
||
};
|
||
/**
|
||
* Updates the properties in order to change zoom scales
|
||
*/
|
||
Layer.prototype.applyZoom = function () {
|
||
this.setProperties();
|
||
};
|
||
|
||
/**
|
||
* Updates the property resizable
|
||
*/
|
||
Layer.prototype.setResizable = function (option) {
|
||
this.resizable = option;
|
||
};
|
||
|
||
/**
|
||
* Comparison function for ordering layers according to priority
|
||
* @param {PMUI.draw.Layer} layer1
|
||
* @param {PMUI.draw.Layer} layer2
|
||
* @returns {boolean}
|
||
*/
|
||
Layer.prototype.comparisonFunction = function (layer1, layer2) {
|
||
if (layer1.priority > layer2.priority) {
|
||
return -1;
|
||
} else if (layer1.priority > layer2.priority) {
|
||
return 1;
|
||
}
|
||
return 0;
|
||
};
|
||
/**
|
||
* Creates the HTML representation of the layer
|
||
* @returns {HTMLElement}
|
||
*/
|
||
Layer.prototype.createHTML = function (modifying) {
|
||
this.setProperties();
|
||
Layer.superclass.prototype.createHTML.call(this, modifying);
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Paints the corresponding layer, in this case adds the
|
||
* corresponding css classes
|
||
* @chainable
|
||
*/
|
||
Layer.prototype.paint = function () {
|
||
|
||
var $layer = $(this.html),
|
||
newSprite;
|
||
this.style.removeClasses([this.currentZoomClass]);
|
||
newSprite = this.zoomSprites[this.canvas.zoomPropertiesIndex];
|
||
this.style.addClasses([newSprite]);
|
||
this.currentZoomClass = newSprite;
|
||
this.style.applyStyle();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* This method will set the parent necessary properties for the layer to work
|
||
* @chainable
|
||
*/
|
||
Layer.prototype.setProperties = function () {
|
||
|
||
if (!this.parent) {
|
||
return this;
|
||
}
|
||
//generates an id for the layer
|
||
this.id = this.parent.getID() + "Layer-" + this.layerName;
|
||
if ((typeof this.width !== "number") && (typeof this.height !== "number")) {
|
||
this.setDimension(this.parent.getWidth(), this.parent.getHeight());
|
||
} else {
|
||
this.setDimension(this.width, this.height);
|
||
}
|
||
|
||
if (this.resizable)
|
||
this.setDimension(this.parent.getWidth(), this.parent.getHeight());
|
||
|
||
// DO NOT ASSUME THAT THE POSITION OF THE LAYER IS 0,0 BECAUSE OF THE
|
||
// BORDERS IT MAY HAVE
|
||
this.canvas = this.parent.canvas;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns the layer name
|
||
* @returns {String}
|
||
*/
|
||
Layer.prototype.getLayerName = function () {
|
||
return this.layerName;
|
||
};
|
||
|
||
/**
|
||
* Returns the priority of the layer
|
||
* @returns {number}
|
||
*/
|
||
Layer.prototype.getPriority = function () {
|
||
return this.priority;
|
||
};
|
||
|
||
/**
|
||
* Sets the layer name
|
||
* @param {String} newLayerName
|
||
* @chainable
|
||
*/
|
||
Layer.prototype.setLayerName = function (newLayerName) {
|
||
if (typeof newLayerName === "string" && newLayerName !== "") {
|
||
this.layerName = newLayerName;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the priority of the layer
|
||
* @param {number} newPriority
|
||
* @chainable
|
||
*/
|
||
Layer.prototype.setPriority = function (newPriority) {
|
||
if (typeof newPriority === "number") {
|
||
this.priority = newPriority;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the parent of this layer
|
||
* @param {PMUI.draw.CustomShape} newParent
|
||
* @chainable
|
||
*/
|
||
Layer.prototype.setParent = function (newParent) {
|
||
if (newParent) {
|
||
this.parent = newParent;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the parent of this layer
|
||
* @return {PMUI.draw.Shape}
|
||
*/
|
||
Layer.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
|
||
/**
|
||
* Sets the css classes for the zoom scales
|
||
* @param {Array} zoomSprites
|
||
* @chainable
|
||
*/
|
||
Layer.prototype.setZoomSprites = function (zoomSprites) {
|
||
var i;
|
||
this.zoomSprites = ["", "", "", "", ""];
|
||
for (i = 0; i < zoomSprites.length; i += 1) {
|
||
this.zoomSprites[i] = zoomSprites[i];
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Serializes this object
|
||
* @return {Object}
|
||
*/
|
||
Layer.prototype.stringify = function () {
|
||
/**
|
||
* inheritedJSON = {
|
||
* id: #
|
||
* x: #,
|
||
* y: #,
|
||
* width: #,
|
||
* height: #
|
||
* }
|
||
* @property {Object}
|
||
*/
|
||
var inheritedJSON = {},
|
||
thisJSON = {
|
||
id: this.getID(),
|
||
x: this.getX(),
|
||
y: this.getY(),
|
||
layerName: this.getLayerName(),
|
||
priority: this.getPriority(),
|
||
style: {
|
||
cssClasses: this.style.getClasses()
|
||
},
|
||
zoomSprites: this.zoomSprites
|
||
};
|
||
$.extend(true, inheritedJSON, thisJSON);
|
||
return inheritedJSON;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Layer', Layer);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Layer;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @abstract
|
||
* @class PMUI.draw.Handler
|
||
* Abstract class which provides methods to represent a handler.
|
||
* @extends PMUI.draw.Core
|
||
*
|
||
* @constructor Creates an instance of the class Handler (for inheritance purposes only).
|
||
* @param {Object} options Initialization options.
|
||
*/
|
||
var Handler = function (options) {
|
||
|
||
Handler.superclass.call(this, options);
|
||
|
||
/**
|
||
* Representation of this handler.
|
||
* @property {Object}
|
||
*/
|
||
this.representation = null;
|
||
|
||
/**
|
||
* The parent of this handler.
|
||
* @property {PMUI.draw.Shape}
|
||
*/
|
||
this.parent = null;
|
||
|
||
/**
|
||
* Color of this handler.
|
||
* @property {PMUI.util.Color}
|
||
*/
|
||
this.color = null;
|
||
|
||
/**
|
||
* The orientation of this handler.
|
||
* @property {string}
|
||
*/
|
||
this.orientation = null;
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Core', Handler);
|
||
|
||
/**
|
||
* Sets the parent of this handler
|
||
* @param newParent
|
||
* @chainable
|
||
*/
|
||
Handler.prototype.setParent = function (newParent) {
|
||
this.parent = newParent;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the parent of this handler
|
||
* @return {PMUI.draw.Shape}
|
||
*/
|
||
Handler.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
|
||
/**
|
||
* Sets the representation of this handler
|
||
* @param representation
|
||
* @chainable
|
||
*/
|
||
Handler.prototype.setRepresentation = function (representation) {
|
||
this.representation = representation;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the representation of this handler
|
||
* @return {Object}
|
||
*/
|
||
Handler.prototype.getRepresentation = function () {
|
||
return this.representation;
|
||
};
|
||
|
||
/**
|
||
* Sets the orientation of this handler
|
||
* @param newOrientation
|
||
* @chainable
|
||
*/
|
||
Handler.prototype.setOrientation = function (newOrientation) {
|
||
this.orientation = newOrientation;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the orientation of this handler
|
||
* @return {string}
|
||
*/
|
||
Handler.prototype.getOrientation = function () {
|
||
return this.orientation;
|
||
};
|
||
|
||
/**
|
||
* Paint the handler method which will call `this.representation.paint()`
|
||
* @chainable
|
||
*/
|
||
Handler.prototype.paint = function () {
|
||
this.representation.paint.call(this);
|
||
this.style.applyStyle();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* The color representation of this object
|
||
* @param {PMUI.util.Color} newColor
|
||
* @chainable
|
||
*/
|
||
Handler.prototype.setColor = function (newColor) {
|
||
this.color = newColor;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Get the color representation of this object
|
||
* @return {PMUI.util.Color}
|
||
*/
|
||
Handler.prototype.getColor = function () {
|
||
return this.color;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Handler', Handler);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Handler;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.ResizeHandler
|
||
* Defines a class resize handler to represent handlers used with jQueryUI' resizable plugin, currently
|
||
* it has only support for rectangle resize handler (oval resize handlers were implemented but apparently
|
||
* jQueryUI won't accept a child of the designated HTMLElement to be used as the resize handler).
|
||
*
|
||
* An example of use:
|
||
*
|
||
* // e.g.
|
||
* // let's assume that shape is an instance of the class Shape
|
||
* // let's assume that rectangle is an instance of the class Rectangle
|
||
*
|
||
* var resizableStyle = {
|
||
* cssProperties: {
|
||
* 'background-color': "rgb(0, 255, 0)",
|
||
* 'border': '1px solid black'
|
||
* }
|
||
* },
|
||
* nonResizableStyle = {
|
||
* cssProperties: {
|
||
* 'background-color': "white",
|
||
* 'border': '1px solid black'
|
||
* }
|
||
* },
|
||
* resizeHandler;
|
||
*
|
||
* resizeHandler = new PMUI.draw.ResizeHandler({
|
||
* width: 8,
|
||
* height: 8,
|
||
* parent: shape,
|
||
* orientation: 'nw' // see jQueryUI's resizable plugin 'handles' option
|
||
* representation: rectangle,
|
||
* resizableStyle: resizableStyle,
|
||
* nonResizableStyle: nonResizableStyle,
|
||
* zOrder: 2
|
||
* });
|
||
*
|
||
* @extend PMUI.draw.Handler
|
||
* @constructor Creates an instance of resize handler.
|
||
* @param {Object} options
|
||
* @cfg {number} [width=4] The width of this resize handler.
|
||
* @cfg {number} [height=4] The height of this resize handler.
|
||
* @cfg {PMUI.draw.Shape} [parent=null] The parent of this resize handler.
|
||
* @cfg {string} [orientation=null] The orientation of this resize handler.
|
||
* @cfg {string} [representation=null] The representation of this resize handler.
|
||
* @cfg {Object} [resizableStyle={}] The parameters to create an instance of the class Style used
|
||
* when the object is resizable.
|
||
* @cfg {Object} [nonResizableStyle={}] The parameters to create an instance of the class Style used
|
||
* when the object is not resizable.
|
||
* @cfg {number} [zOrder=2] The z-index of this resize handler.
|
||
*/
|
||
var ResizeHandler = function (options) {
|
||
|
||
ResizeHandler.superclass.call(this, options);
|
||
|
||
/**
|
||
* Category of this resize handler
|
||
* @type {"resizable"/"nonresizable"}
|
||
*/
|
||
this.category = null;
|
||
|
||
/**
|
||
* Denotes whether the resize handle is visible or not.
|
||
* @property boolean
|
||
*/
|
||
this.visible = false;
|
||
|
||
/**
|
||
* JSON used to create an instance of the class Style used when the object is resizable.
|
||
* @property {Object}
|
||
*/
|
||
this.resizableStyle = null;
|
||
|
||
/**
|
||
* JSON used to create an instance of the class Style used when the object is not resizable.
|
||
* @property {Object}
|
||
*/
|
||
this.nonResizableStyle = null;
|
||
|
||
// set defaults
|
||
ResizeHandler.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Handler', ResizeHandler);
|
||
|
||
/**
|
||
* The type of each instance of this class.
|
||
* @property {String}
|
||
*/
|
||
ResizeHandler.prototype.type = "ResizeHandler";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance
|
||
* @param {Object} options The object that contains the config
|
||
* @private
|
||
*/
|
||
ResizeHandler.prototype.init = function (options) {
|
||
|
||
var defaults = {
|
||
width: 4,
|
||
height: 4,
|
||
parent: null,
|
||
orientation: null,
|
||
representation: null,
|
||
resizableStyle: {},
|
||
nonResizableStyle: {},
|
||
zOrder: 2
|
||
};
|
||
|
||
// extend recursively the defaultOptions with the given options
|
||
$.extend(true, defaults, options);
|
||
|
||
// add default zIndex to this handler
|
||
if (defaults.resizableStyle.cssProperties) {
|
||
defaults.resizableStyle.cssProperties.zIndex = defaults.zOrder;
|
||
}
|
||
if (defaults.nonResizableStyle.cssProperties) {
|
||
defaults.nonResizableStyle.cssProperties.zIndex = defaults.zOrder;
|
||
}
|
||
|
||
// init
|
||
this.setParent(defaults.parent)
|
||
.setWidth(defaults.width)
|
||
.setHeight(defaults.height)
|
||
.setOrientation(defaults.orientation)
|
||
.setRepresentation(defaults.representation)
|
||
.setResizableStyle(defaults.resizableStyle)
|
||
.setNonResizableStyle(defaults.nonResizableStyle);
|
||
|
||
// create the id
|
||
this.id = defaults.orientation + defaults.parent.id + "resizehandler";
|
||
};
|
||
|
||
/**
|
||
* Sets the parent of this handler
|
||
* @param {PMUI.draw.Shape} newParent
|
||
* @chainable
|
||
*/
|
||
ResizeHandler.prototype.setParent = function (newParent) {
|
||
this.parent = newParent;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the parent of this handler.
|
||
* @return {PMUI.draw.Shape}
|
||
*/
|
||
ResizeHandler.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
|
||
/**
|
||
* Paints this resize handler by calling it's parent's `paint` and setting
|
||
* the visibility of this resize handler
|
||
* @chainable
|
||
*/
|
||
ResizeHandler.prototype.paint = function () {
|
||
if (!this.html) {
|
||
throw new Error("paint(): This handler has no html");
|
||
}
|
||
|
||
// this line paints the representation (by default a rectangle)
|
||
ResizeHandler.superclass.prototype.paint.call(this);
|
||
|
||
this.setVisible(this.visible);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the category of the resizeHandler (also adds the needed class to
|
||
* make the element resizable)
|
||
* @param newCategory
|
||
* @chainable
|
||
*/
|
||
ResizeHandler.prototype.setCategory = function (newCategory) {
|
||
if (typeof newCategory === "string") {
|
||
this.category = newCategory;
|
||
}
|
||
if (this.category === "resizable") {
|
||
this.color = new PMUI.util.Color(0, 255, 0);
|
||
this.style.addClasses([
|
||
"ui-resizable-handle", "ui-resizable-" + this.orientation
|
||
]);
|
||
} else {
|
||
this.color = new PMUI.util.Color(255, 255, 255);
|
||
this.style.removeClasses([
|
||
"ui-resizable-handle", "ui-resizable-" + this.orientation
|
||
]);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
|
||
/**
|
||
* Sets the resizable style of this shape by creating an instance of the class Style
|
||
* @param {Object} style
|
||
* @chainable
|
||
*/
|
||
ResizeHandler.prototype.setResizableStyle = function (style) {
|
||
this.resizableStyle = new PMUI.util.Style({
|
||
belongsTo: this,
|
||
cssProperties: style.cssProperties,
|
||
cssClasses: style.cssClasses
|
||
});
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the non resizable style for this shape by creating an instance of the class Style
|
||
* @param {Object} style
|
||
* @chainable
|
||
*/
|
||
ResizeHandler.prototype.setNonResizableStyle = function (style) {
|
||
this.nonResizableStyle = new PMUI.util.Style({
|
||
belongsTo: this,
|
||
cssProperties: style.cssProperties,
|
||
cssClasses: style.cssClasses
|
||
});
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.ResizeHandler', ResizeHandler);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = ResizeHandler;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.SegmentMoveHandler
|
||
* Represents the handler to move a segment (the handlers are visible when a decorator of the parent of this
|
||
* segment is clicked on)
|
||
*
|
||
* An example of use:
|
||
*
|
||
* // e.g.
|
||
* // let's assume that segment is an instance of the class Segment
|
||
* // let's assume that rectangle is an instance of the class Rectangle
|
||
*
|
||
* segmentMoveHandler = new PMUI.draw.SegmentMoveHandler({
|
||
* width: 8,
|
||
* height: 8,
|
||
* parent: segment,
|
||
* orientation: 0 // corresponds to a vertical segment
|
||
* representation: rectangle,
|
||
* color: new Color(255, 0, 0) // red !!
|
||
* });
|
||
* @extend PMUI.draw.Handler
|
||
* @constructor Creates an instance of the class SegmentMoveHandler
|
||
* @param {Object} options
|
||
* @cfg {number} [width=4] The width of this segment move handler.
|
||
* @cfg {number} [height=4] The height of this segment move handler.
|
||
* @cfg {PMUI.draw.Shape} [parent=null] The parent of this segment move handler.
|
||
* @cfg {number} [orientation=null] The orientation of this segment move handler.
|
||
* @cfg {string} [representation=null] The representation of this segment move handler.
|
||
* @cfg {number} [color=new Color(0, 255, 0)] The color of this segment move handler (green).
|
||
*/
|
||
var SegmentMoveHandler = function (options) {
|
||
|
||
SegmentMoveHandler.superclass.call(this, options);
|
||
|
||
/**
|
||
* Orientation of this segment move handler (useful to do the drag).
|
||
* @property {number}
|
||
*/
|
||
this.orientation = null;
|
||
|
||
/**
|
||
* Denotes whether the SegmentMove point is visible or not.
|
||
* @property {boolean} [visible=false]
|
||
*/
|
||
this.visible = false;
|
||
|
||
/**
|
||
* The default zOrder of this handler.
|
||
* @property {number} [zOrder=2]
|
||
*/
|
||
this.zOrder = 2;
|
||
|
||
// set defaults
|
||
SegmentMoveHandler.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Handler', SegmentMoveHandler);
|
||
|
||
/**
|
||
* Type of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
SegmentMoveHandler.prototype.type = "SegmentMoveHandler";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance
|
||
* @param {Object} options The object that contains the config
|
||
* @private
|
||
*/
|
||
SegmentMoveHandler.prototype.init = function (options) {
|
||
|
||
var defaults = {
|
||
width: 4,
|
||
height: 4,
|
||
parent: null,
|
||
orientation: null,
|
||
representation: new PMUI.draw.Rectangle(),
|
||
color: new PMUI.util.Color(0, 255, 0)
|
||
};
|
||
|
||
// extend recursively the defaultOptions with the given options
|
||
$.extend(true, defaults, options);
|
||
|
||
// init
|
||
this.setWidth(defaults.width)
|
||
.setHeight(defaults.height)
|
||
.setParent(defaults.parent)
|
||
.setColor(defaults.color)
|
||
.setOrientation(defaults.orientation)
|
||
.setRepresentation(defaults.representation);
|
||
};
|
||
|
||
/**
|
||
* Paints this resize handler by calling it's parent's `paint` and setting
|
||
* the visibility of this resize handler.
|
||
* @chainable
|
||
*/
|
||
SegmentMoveHandler.prototype.paint = function () {
|
||
// before it was: Rectangle.prototype.paint.call(this);
|
||
SegmentMoveHandler.superclass.prototype.paint.call(this);
|
||
this.setVisible(this.visible);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Attaches listeners to the segmentMoveHandler, by default it creates the click,
|
||
* mouseDown and draggable events.
|
||
* @param {PMUI.draw.SegmentMoveHandler} handler
|
||
* @chainable
|
||
*/
|
||
SegmentMoveHandler.prototype.attachListeners = function (handler) {
|
||
var $handler = $(handler.html);
|
||
$handler.on('click', handler.onClick(handler));
|
||
$handler.on('mousedown', handler.onMouseDown(handler));
|
||
$handler.draggable({
|
||
start: handler.onDragStart(handler),
|
||
drag: handler.onDrag(handler),
|
||
stop: handler.onDragEnd(handler),
|
||
axis: (handler.orientation === handler.HORIZONTAL) ? "y" : "x"
|
||
//containment: handler.parent.parent.html
|
||
});
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* @event mousedown
|
||
* MouseDown callback fired when the user mouse downs on the `handler`
|
||
* @param {PMUI.draw.SegmentMoveHandler} handler
|
||
*/
|
||
SegmentMoveHandler.prototype.onMouseDown = function (handler) {
|
||
return function (e, ui) {
|
||
// This is done to avoid the start of a selection in the canvas
|
||
// handler > segment > connection > canvas
|
||
handler.parent.parent.canvas.draggingASegmentHandler = true;
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event click
|
||
* Click callback fired when the user clicks on the handler
|
||
* @param {PMUI.draw.SegmentMoveHandler} handler
|
||
*/
|
||
SegmentMoveHandler.prototype.onClick = function (handler) {
|
||
return function (e, ui) {
|
||
e.stopPropagation();
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event dragStart
|
||
* DragStart callback fired when the handler is dragged (it's executed only once).
|
||
* It does the following:
|
||
*
|
||
* 1. Gather the connection by calling the handler's grandparent
|
||
* 2. Save the state if the connection (for the undo-redo stack)
|
||
* 3. Clear all the intersections of each segment of the connection
|
||
*
|
||
* @param {PMUI.draw.SegmentMoveHandler} handler
|
||
*/
|
||
SegmentMoveHandler.prototype.onDragStart = function (handler) {
|
||
return function (e, ui) {
|
||
var parentSegment = handler.parent,
|
||
segment,
|
||
connection = parentSegment.getParent(),
|
||
i;
|
||
|
||
// TESTING:
|
||
// save values for the undo-redo stack
|
||
connection.savePoints({
|
||
saveToOldPoints: true
|
||
});
|
||
|
||
// clear all intersections that exists in
|
||
// parentSegment.parent (connection)
|
||
for (i = 0; i < parentSegment.parent.lineSegments.getSize(); i += 1) {
|
||
segment = parentSegment.parent.lineSegments.get(i);
|
||
segment.clearIntersections();
|
||
}
|
||
// clear all intersections that exists among other connections and
|
||
// parentSegment (the ones that exists in the other connections)
|
||
parentSegment.parent.clearAllIntersections();
|
||
e.stopPropagation();
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event drag
|
||
* Drag callback fired when the handler is being dragged.
|
||
* It only moves the segment vertically or horizontally.
|
||
*
|
||
* @param {PMUI.draw.SegmentMoveHandler} handler
|
||
*/
|
||
SegmentMoveHandler.prototype.onDrag = function (handler) {
|
||
return function (e, ui) {
|
||
var parentSegment = handler.parent;
|
||
parentSegment.moveSegment(ui.position.left, ui.position.top);
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event dragEnd
|
||
* DragEnd callback fired when the handler stops being dragged.
|
||
* It does the following:
|
||
*
|
||
* 1. Gather the connection by calling the handler's grandparent
|
||
* 2. Save the state if the connection (for the undo-redo stack)
|
||
* 3. Create a command for the undo-redo stack
|
||
*
|
||
* @param {PMUI.draw.SegmentMoveHandler} handler
|
||
*/
|
||
SegmentMoveHandler.prototype.onDragEnd = function (handler) {
|
||
return function (e, ui) {
|
||
var parentSegment = handler.parent,
|
||
connection = parentSegment.getParent(),
|
||
canvas = connection.canvas,
|
||
command;
|
||
|
||
canvas.draggingASegmentHandler = false;
|
||
handler.onDrag(handler)(e, ui);
|
||
|
||
// LOGIC: connection.points is an array of points that is not updated
|
||
// automatically when a connection is painted, it must be
|
||
// explicitly called as connection.savePoints()
|
||
connection.savePoints();
|
||
command = new PMUI.command.CommandSegmentMove(connection, {
|
||
oldPoints: connection.getOldPoints(),
|
||
newPoints: connection.getPoints()
|
||
});
|
||
command.execute();
|
||
canvas.commandStack.add(command);
|
||
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.SegmentMoveHandler', SegmentMoveHandler);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = SegmentMoveHandler;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Port
|
||
* Class Port represent a special point in a shape where each point is one end point of a connection
|
||
* (a customShape has many ports and each port has a reference to the connection it belongs to).
|
||
*
|
||
* The relation of this class with customShape and connections are described below:
|
||
*
|
||
* - Each port is one end point of a connection (the connection has links to the start port and the end port,
|
||
* the port has a link to the connection)
|
||
* - A custom shape might have *n* ports (the parent of the port is the custom shape)
|
||
* so the custom shape has the HTML of the port on it.
|
||
*
|
||
* Some examples of usage:
|
||
*
|
||
* // let's assume the connection is an instance of the class Connection
|
||
* // let's assume the customShape is an instance of the class CustomShape
|
||
* var port = new PMUI.draw.Port({
|
||
* width: 8,
|
||
* height: 8,
|
||
* visible: true,
|
||
* parent: customShape
|
||
* })
|
||
*
|
||
* // after a port is created, it need to be added to the customShape
|
||
* // let's add it at position [100, 100]
|
||
* customShape.addPort(port, 100, 100)
|
||
*
|
||
* // finally when a connection is created it needs to have links to the ports
|
||
* // let's assume that another port is an instance of the class Port
|
||
* // i.e
|
||
* connection = new PMUI.draw.Connection({
|
||
* srcPort: port,
|
||
* destPort: anotherPort,
|
||
* segmentColor: new PMUI.util.Color(0, 200, 0),
|
||
* segmentStyle: "regular"
|
||
* });
|
||
*
|
||
* @extend PMUI.draw.Core
|
||
*
|
||
*
|
||
* @param {Object} options Initialization options
|
||
* @cfg {number} [width=4] The width of this port
|
||
* @cfg {number} [height=4] The height of this port
|
||
* @cfg {boolean} [visible=false] The visibility of this port
|
||
* @cfg {PMUI.draw.CustomShape} [parent=null] The parent of this port
|
||
*
|
||
* @constructor Creates an instance of the class Port
|
||
*/
|
||
var Port = function (options) {
|
||
|
||
Port.superclass.call(this);
|
||
|
||
/**
|
||
* Connection to whom this port belongs to
|
||
* @property {PMUI.draw.Connection}
|
||
*/
|
||
this.connection = null;
|
||
|
||
/**
|
||
* Representation (Shape) of the port when it is connected (currently it's represented as an
|
||
{@link PMUI.draw.Oval})
|
||
* @property {PMUI.draw.Shape}
|
||
*/
|
||
this.representation = null;
|
||
|
||
/**
|
||
* Parent of this port.
|
||
* @property {PMUI.draw.CustomShape}
|
||
*/
|
||
this.parent = null;
|
||
|
||
/**
|
||
* Old parent of this port.
|
||
* @property {PMUI.draw.CustomShape}
|
||
*/
|
||
this.oldParent = null;
|
||
|
||
/**
|
||
* Port direction respect to its parent (its parent is an instance of {@link PMUI.draw.CustomShape}).
|
||
* @property {number}
|
||
*/
|
||
this.direction = null;
|
||
|
||
/**
|
||
* The percentage relative to where the port is located regarding one of
|
||
* the shape dimensions (useful to recalculate the ports position while resizing).
|
||
* @property {number}
|
||
*/
|
||
this.percentage = null;
|
||
|
||
/**
|
||
* Current zIndex of the port.
|
||
* @property {number} [zOrder=1]
|
||
*/
|
||
this.zOrder = 1;
|
||
|
||
/**
|
||
* Default zIndex of the ports.
|
||
* @property {number} [defaultZOrder=1]
|
||
*/
|
||
this.defaultZOrder = 1;
|
||
|
||
/**
|
||
* X coordinate sent to the database
|
||
* @property {number} [realX=0]
|
||
*/
|
||
this.realX = 0;
|
||
/**
|
||
* Y coordinate sent to the database
|
||
* @property {number} [realY=0]
|
||
*/
|
||
this.realY = 0;
|
||
|
||
Port.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.RegularShape', Port);
|
||
|
||
/**
|
||
* The distance moved when a connection is selected (when a connection is
|
||
* selected the ports move towards the center of the shape so that it's
|
||
* easier to drag the ports)
|
||
* @property {number} [TOWARDS_CENTER=5]
|
||
*/
|
||
Port.prototype.TOWARDS_CENTER = 5;
|
||
|
||
/**
|
||
* Type of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
Port.prototype.type = "Port";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance.
|
||
* @param {Object} options The object that contains the config
|
||
* @private
|
||
*/
|
||
Port.prototype.init = function (options) {
|
||
/**
|
||
* Default options for the object
|
||
* @property {Object}
|
||
*/
|
||
var defaults = {
|
||
width: 4,
|
||
height: 4,
|
||
visible: false,
|
||
parent: null
|
||
};
|
||
|
||
// extend recursively the defaultOptions with the given options
|
||
$.extend(true, defaults, options);
|
||
$.extend(true, defaults, {
|
||
// oval is initialized with default values
|
||
representation: new PMUI.draw.Oval({
|
||
width: defaults.width,
|
||
height: defaults.height,
|
||
center: new PMUI.util.Point(0, 0),
|
||
visible: true
|
||
})
|
||
});
|
||
|
||
// call setters using the defaults object
|
||
this.setVisible(defaults.visible)
|
||
.setParent(defaults.parent)
|
||
.setDimension(defaults.width, defaults.height)
|
||
.setRepresentation(defaults.representation);
|
||
};
|
||
|
||
/**
|
||
* Creates the HTML Representation of the Port
|
||
* @returns {HTMLElement}
|
||
*/
|
||
Port.prototype.createHTML = function () {
|
||
Port.superclass.prototype.createHTML.call(this);
|
||
this.style.addClasses(["port"]);
|
||
this.setPosition(this.x, this.y);
|
||
return this.html;
|
||
};
|
||
|
||
/**
|
||
* Sets the x coordinate of this port
|
||
* @param {number} newX
|
||
* @chainable
|
||
*/
|
||
Port.prototype.setX = function (newX) {
|
||
if (this.canvas) {
|
||
this.realX = newX / this.canvas.zoomFactor;
|
||
} else {
|
||
this.realX = newX;
|
||
}
|
||
this.x = this.zoomX = Math.round(newX);
|
||
this.setAbsoluteX();
|
||
if (this.html) {
|
||
this.style.addProperties({left: this.zoomX});
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the y coordinate of this port
|
||
* @param {number} newY
|
||
* @chainable
|
||
*/
|
||
Port.prototype.setY = function (newY) {
|
||
this.y = this.zoomY = Math.round(newY);
|
||
this.setAbsoluteY();
|
||
if (this.canvas) {
|
||
this.realY = newY / this.canvas.zoomFactor;
|
||
} else {
|
||
this.realY = newY;
|
||
}
|
||
if (this.html) {
|
||
this.style.addProperties({top: this.zoomY});
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the width of this port
|
||
* @param {number} newWidth
|
||
* @chainable
|
||
*/
|
||
Port.prototype.setWidth = function (newWidth) {
|
||
this.width = newWidth;
|
||
this.zoomWidth = this.width;
|
||
if (this.html) {
|
||
this.style.addProperties({width: this.zoomWidth});
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the height of this port
|
||
* @param {number} newHeight
|
||
* @chainable
|
||
*/
|
||
Port.prototype.setHeight = function (newHeight) {
|
||
this.height = newHeight;
|
||
this.zoomHeight = this.height;
|
||
if (this.html) {
|
||
this.style.addProperties({height: this.zoomHeight});
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Paint the port appending its `representation` HTML to `this` HTML.
|
||
* @chainable
|
||
*/
|
||
Port.prototype.paint = function () {
|
||
|
||
this.html.appendChild(this.representation.getHTML());
|
||
this.representation.paint();
|
||
|
||
// sets the visibility of this port
|
||
this.setVisible(this.visible);
|
||
this.style.applyStyle();
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Repaints the port re-applying its left and top position.
|
||
* @param {PMUI.draw.Port} port
|
||
* @chainable
|
||
*/
|
||
Port.prototype.repaint = function (port) {
|
||
|
||
port.style.addProperties({
|
||
left: port.x,
|
||
top: port.y
|
||
});
|
||
port.connection.connect();
|
||
port.connection.setSegmentMoveHandlers();
|
||
port.connection.checkAndCreateIntersectionsWithAll();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* @event dragStart
|
||
* DragStart callback fired when the port is dragged (it's executed only once).
|
||
* It does the following:
|
||
*
|
||
* 1. Moves the port away from the center
|
||
* 2. Moves the otherPort away from the center
|
||
* 3. Disconnects the connection
|
||
*
|
||
* @param {PMUI.draw.Port} port
|
||
* @param {PMUI.draw.Port} otherPort
|
||
*/
|
||
Port.prototype.onDragStart = function (port, otherPort) {
|
||
return function (e, ui) {
|
||
|
||
// move the ports off the center, they'll be correctly repositioned
|
||
// later (in "onDragEnd")
|
||
otherPort.moveTowardsTheCenter(true);
|
||
port.moveTowardsTheCenter(true);
|
||
|
||
port.connection.disconnect();
|
||
return true;
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event drag
|
||
* Drag callback fired when the port is being dragged.
|
||
* It makes a new segment from the other port to the current position of the mouse.
|
||
*
|
||
* @param {PMUI.draw.Port} port
|
||
* @param {PMUI.util.Point} endPoint
|
||
* @param {PMUI.draw.Port} otherPort
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
*/
|
||
Port.prototype.onDrag = function (port, endPoint, otherPort, canvas) {
|
||
return function (e, ui) {
|
||
var startPoint;
|
||
if (canvas.connectionSegment) {
|
||
$(canvas.connectionSegment.getHTML()).remove();
|
||
}
|
||
|
||
endPoint.x = e.pageX - canvas.getX() + canvas.getLeftScroll() - canvas.getAbsoluteX();
|
||
endPoint.y = e.pageY - canvas.getY() + canvas.getTopScroll() - canvas.getAbsoluteY();
|
||
//make connection segment
|
||
startPoint = otherPort.getPoint(false);
|
||
startPoint.x = startPoint.x - canvas.getAbsoluteX();
|
||
startPoint.y = startPoint.y - canvas.getAbsoluteY();
|
||
canvas.connectionSegment = new PMUI.draw.Segment({
|
||
startPoint: startPoint,
|
||
endPoint: endPoint,
|
||
parent: canvas
|
||
});
|
||
canvas.connectionSegment.pointsTo = port;
|
||
canvas.connectionSegment.createHTML();
|
||
canvas.connectionSegment.paint();
|
||
};
|
||
};
|
||
|
||
/**
|
||
* @event dragEnd
|
||
* DragEnd callback fired when the port stops being dragged.
|
||
* It does the following:
|
||
*
|
||
* 1. Repaints the port
|
||
* 2. Moves otherPort towards the center of the shape
|
||
* 3. Moves port towards the center of the shape
|
||
* 4. Shows the handlers of the connection
|
||
*
|
||
* @param {PMUI.draw.Port} port
|
||
* @param {PMUI.draw.Port} otherPort
|
||
* @param {PMUI.draw.Canvas} canvas
|
||
*/
|
||
Port.prototype.onDragEnd = function (port, otherPort, canvas) {
|
||
return function (e, ui) {
|
||
|
||
if (canvas.connectionSegment) {
|
||
$(canvas.connectionSegment.getHTML()).remove();
|
||
}
|
||
port.repaint(port);
|
||
|
||
// move the ports towards the center of its parent
|
||
// (they were moved off the center in "onDragStart")
|
||
otherPort.moveTowardsTheCenter();
|
||
port.moveTowardsTheCenter();
|
||
|
||
// show the segmentMoveHandlers
|
||
port.connection.showMoveHandlers();
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Determine the percentage relative to the shape where the port is located.
|
||
* The range of `this.percentage` is from 0 to 1 (inclusive).
|
||
* @return {boolean}
|
||
*/
|
||
Port.prototype.determinePercentage = function () {
|
||
//Shape and port dimension to consider, it can be either width or height
|
||
var shapeDimension,
|
||
portDimension;
|
||
if (!this.parent) {
|
||
return false;
|
||
}
|
||
if (this.direction === this.TOP || this.direction === this.BOTTOM) {
|
||
shapeDimension = this.parent.getZoomWidth();
|
||
portDimension = this.x + (5 * this.canvas.getZoomFactor());
|
||
} else {
|
||
shapeDimension = this.parent.getZoomHeight();
|
||
portDimension = this.y + (5 * this.canvas.getZoomFactor());
|
||
}
|
||
|
||
this.percentage = Math.round((portDimension / shapeDimension) * 100.0);
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* Shows this port (moving it's HTML representation towards the center for easy dragging).
|
||
* @chainable
|
||
*/
|
||
Port.prototype.show = function () {
|
||
this.visible = true;
|
||
this.paint();
|
||
this.html.style.zIndex = 3;
|
||
// move the ports towards the center
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Hides this port (moving it's HTML representation off the center of the shape).
|
||
* @chainable
|
||
*/
|
||
Port.prototype.hide = function () {
|
||
this.visible = false;
|
||
this.paint();
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Detaches the HTML of the port from the DOM (saving it in `this.html`), it also removes the port
|
||
* from its parent.
|
||
* @chainable
|
||
*/
|
||
Port.prototype.saveAndDestroy = function () {
|
||
this.parent.removePort(this); //remove from shape
|
||
|
||
// save the html but detach it from the DOM
|
||
this.html = $(this.html).detach()[0];
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Attaches event listeners to this port, currently it has the draggable and mouse over events.
|
||
* @param {PMUI.draw.Port} currPort
|
||
* @return {PMUI.draw.Port}
|
||
*/
|
||
Port.prototype.attachListeners = function (currPort) {
|
||
var otherPort,
|
||
portDragOptions;
|
||
otherPort = currPort.connection.srcPort.getPoint(false)
|
||
.equals(currPort.getPoint(false)) ? currPort.connection.destPort :
|
||
currPort.connection.srcPort;
|
||
|
||
portDragOptions = {
|
||
//containment : "parent"
|
||
start: currPort.onDragStart(currPort, otherPort),
|
||
drag: currPort.onDrag(currPort, currPort.getPoint(false),
|
||
otherPort, currPort.parent.canvas),
|
||
stop: currPort.onDragEnd(currPort, otherPort, currPort.parent.canvas)
|
||
};
|
||
$(currPort.html).draggable(portDragOptions);
|
||
$(currPort.html).mouseover(
|
||
function () {
|
||
$(currPort.html).css('cursor', 'Move');
|
||
}
|
||
);
|
||
return currPort;
|
||
};
|
||
|
||
/**
|
||
* Moves a port towards or off the center (for easy dragging).
|
||
* @param {boolean} reverse If it's set to true then it will move it off the center
|
||
* @chainable
|
||
*/
|
||
Port.prototype.moveTowardsTheCenter = function (reverse) {
|
||
var towardsCenterDistance = Port.prototype.TOWARDS_CENTER,
|
||
dx = [0, -towardsCenterDistance, 0, towardsCenterDistance],
|
||
dy = [towardsCenterDistance, 0, -towardsCenterDistance, 0],
|
||
multiplier = 1;
|
||
|
||
if (reverse) {
|
||
multiplier = -1;
|
||
}
|
||
this.setPosition(this.x + dx[this.direction] * multiplier,
|
||
this.y + dy[this.direction] * multiplier);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the Direction to the port.
|
||
* @param {number} newDirection
|
||
* @chainable
|
||
*/
|
||
Port.prototype.setDirection = function (newDirection) {
|
||
if (newDirection >= 0 && newDirection < 4) {
|
||
this.direction = newDirection;
|
||
} else {
|
||
throw new Error("setDirection(): parameter '" + newDirection +
|
||
"'is not valid");
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Get the direction to the port. (0 = TOP, 1 = RIGHT, 2 = BOTTOM, 3 = LEFT)
|
||
* @returns {number}
|
||
*/
|
||
Port.prototype.getDirection = function () {
|
||
return this.direction;
|
||
};
|
||
|
||
/**
|
||
* Sets the parent of the port.
|
||
* @param {PMUI.draw.Shape} newParent
|
||
* @param {boolean} triggerChange If set to true it'll fire {@link PMUI.draw.Canvas#event-changeelement}
|
||
* @chainable
|
||
*/
|
||
Port.prototype.setParent = function (newParent, triggerChange) {
|
||
if (this.canvas && triggerChange) {
|
||
this.canvas.updatedElement = {
|
||
"id": this.id,
|
||
"type": this.type,
|
||
"fields": [
|
||
{
|
||
"field": "parent",
|
||
"oldVal": this.parent,
|
||
"newVal": newParent
|
||
}
|
||
]
|
||
};
|
||
$(this.canvas.html).trigger("changeelement");
|
||
}
|
||
this.parent = newParent;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the parent of the port.
|
||
* @return {PMUI.draw.Port}
|
||
*/
|
||
Port.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
|
||
/**
|
||
* Sets the old parent of this port
|
||
* @param {PMUI.draw.CustomShape} parent
|
||
* @chainable
|
||
*/
|
||
Port.prototype.setOldParent = function (parent) {
|
||
this.oldParent = parent;
|
||
return this;
|
||
};
|
||
/**
|
||
* Gets the old parent of this port.
|
||
* @return {PMUI.draw.Port}
|
||
*/
|
||
Port.prototype.getOldParent = function () {
|
||
return this.oldParent;
|
||
};
|
||
|
||
/**
|
||
* Sets the connection associated with this port.
|
||
* @param {PMUI.draw.Connection} newConn
|
||
* @chainable
|
||
*/
|
||
Port.prototype.setConnection = function (newConn) {
|
||
if (newConn && newConn.family === "Connection") {
|
||
this.connection = newConn;
|
||
} else {
|
||
throw new Error("setConnection(): parameter is not valid");
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the connection associated with this port
|
||
* @returns {PMUI.draw.Connection}
|
||
*/
|
||
Port.prototype.getConnection = function () {
|
||
return this.connection;
|
||
};
|
||
|
||
/**
|
||
* Returns the representation of the port (currently an instance of the class {@link PMUI.draw.Oval})
|
||
* @returns {PMUI.draw.Oval}
|
||
*/
|
||
Port.prototype.getRepresentation = function () {
|
||
return this.representation;
|
||
};
|
||
|
||
/**
|
||
* Sets the representation of this port (not supported yet)
|
||
* @param {PMUI.draw.Shape} newRep
|
||
* @chainable
|
||
*/
|
||
Port.prototype.setRepresentation = function (newRep) {
|
||
if (newRep instanceof PMUI.draw.RegularShape) {
|
||
this.representation = newRep;
|
||
} else {
|
||
throw new Error("setRepresentation(): parameter must be an instance" +
|
||
" of any regularShape");
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Gets the ports position (if `relativeToShape` is set to true it'll return the position
|
||
* respect to the shape, otherwise it'll return its position respect to the canvas)
|
||
* @param {boolean} relativeToShape
|
||
* @returns {PMUI.util.Point}
|
||
*/
|
||
Port.prototype.getPoint = function (relativeToShape) {
|
||
var border = parseInt(this.parent.style.getProperty('border'), 10) || 0;
|
||
if (relativeToShape) {
|
||
return new PMUI.util.Point(this.getX() + Math.round(this.getWidth() / 2),
|
||
this.getY() + Math.round(this.getHeight() / 2));
|
||
}
|
||
return new PMUI.util.Point(
|
||
this.getAbsoluteX() + Math.round(this.getWidth() / 2),
|
||
this.getAbsoluteY() + Math.round(this.getHeight() / 2)
|
||
);
|
||
|
||
};
|
||
|
||
/**
|
||
* Gets the percentage of this port relative to its parent.
|
||
* @return {number}
|
||
*/
|
||
Port.prototype.getPercentage = function () {
|
||
return this.percentage;
|
||
};
|
||
|
||
/**
|
||
* Serializes this port.
|
||
* @return {Object}
|
||
* @return {number} return.x
|
||
* @return {number} return.y
|
||
* @return {number} return.realX
|
||
* @return {number} return.realY
|
||
* @return {string} return.parent The ID of its parent.
|
||
*/
|
||
Port.prototype.stringify = function () {
|
||
var inheritedJSON = {},
|
||
thisJSON = {
|
||
x: this.getX(),
|
||
y: this.getY(),
|
||
realX: this.realX,
|
||
realY: this.realY,
|
||
parent: this.getParent().getID()
|
||
};
|
||
$.extend(true, inheritedJSON, thisJSON);
|
||
return inheritedJSON;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Port', Port);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Port;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.Segment
|
||
* A class that represents a segment, a segment is defined with two points
|
||
(`startPoint` and `enPoint`).
|
||
* In the PMDraw library a segment is used as a the key part of connections,
|
||
it has also the following characteristics:
|
||
*
|
||
* - Since a segment is used as part of a connection, it has neighbors (`previousNeighbor` and `nextNeighbor`).
|
||
* - A segment is parallel to an axis if it forms part of a connection.
|
||
* - A segment has a move handler to move the segment.
|
||
* - A segment has info of other connections it has intersections with
|
||
*
|
||
* Some examples of usage:
|
||
*
|
||
* // let's assume that we want to connect two shapes, the shapes are connected
|
||
* // through the creation of a segment (the start point is the mouse position where
|
||
* // the user fired the mouse down event and the end point is the mouse position where the user
|
||
* // fired the mouse up event)
|
||
* // let's assume that canvas is an instance of the class Canvas and it's creating the segment
|
||
* var redSegment = new PMUI.draw.Segment({
|
||
* startPoint: new PMUI.util.Point(100, 100), // a random point
|
||
* endPoint: new PMUI.util.Point(200, 200), // a random point
|
||
* parent: canvas,
|
||
* color: new PMUI.util.Color(255, 0, 0) // red !!
|
||
* });
|
||
*
|
||
* @extend PMUI.draw.Core
|
||
*
|
||
* @constructor Creates an instance of the class Segment
|
||
* @param {Object} options Initialization options
|
||
* @cfg {PMUI.util.Point} [startPoint=new Point(0, 0)] The start point of the segment
|
||
* @cfg {PMUI.util.Point} [endPoint=new Point(0, 0)] The end point of the segment
|
||
* @cfg {PMUI.draw.Canvas / PMUI.draw.Connection} [parent=null] The parent of the segment
|
||
* @cfg {PMUI.util.Color} [color=new Color(0, 0, 0)] The color of this segment
|
||
*/
|
||
var Segment = function (options) {
|
||
Segment.superclass.call(this, options);
|
||
|
||
/**
|
||
* The parent of the segment.
|
||
* @property {PMUI.draw.Canvas / PMUI.draw.Connection} [parent=null]
|
||
*/
|
||
this.parent = null;
|
||
/**
|
||
* The start point of the segment.
|
||
* @property {PMUI.util.Point} [startPoint=null]
|
||
*/
|
||
this.startPoint = null;
|
||
|
||
/**
|
||
* The end point of the segment.
|
||
* @property {PMUI.util.Point} [endPoint=null]
|
||
*/
|
||
this.endPoint = null;
|
||
|
||
/**
|
||
* zOrder of the segment.
|
||
* @property {number} [zOrder=Shape.prototype.MAX_ZINDEX]
|
||
*/
|
||
this.zOrder = PMUI.draw.Shape.prototype.MAX_ZINDEX;
|
||
|
||
/**
|
||
* The segment to the left of this segment.
|
||
* @property {PMUI.draw.Segment} [previousNeighbor=null]
|
||
*/
|
||
this.previousNeighbor = null;
|
||
|
||
/**
|
||
* The segment to the right of this segment.
|
||
* @property {PMUI.draw.Segment} [nextNeighbor=null]
|
||
*/
|
||
this.nextNeighbor = null;
|
||
|
||
/**
|
||
* Orientation of the segment, the possible values are:
|
||
*
|
||
* - Vertical
|
||
* - Horizontal
|
||
*
|
||
* @property {String} [orientation=""]
|
||
*/
|
||
this.orientation = "";
|
||
|
||
/**
|
||
* The width of the segment.
|
||
* @property {number} [width=1]
|
||
*/
|
||
this.width = 1;
|
||
|
||
/**
|
||
* Graphics object
|
||
* @property {PMUI.draw.Graphics} [graphics=null]
|
||
*/
|
||
this.graphics = null;
|
||
|
||
/**
|
||
* This segment style, the possible values are:
|
||
*
|
||
* - "dotted"
|
||
* - "segmented"
|
||
* - "segmentdot"
|
||
* @property {string} [segmentStyle=null]
|
||
*/
|
||
this.segmentStyle = null;
|
||
|
||
/**
|
||
* This segment color.
|
||
* @property {PMUI.util.Color} [segmentColor=null]
|
||
*/
|
||
this.segmentColor = null;
|
||
|
||
/**
|
||
* The move handler is the segment move handler of this segment.
|
||
* @property {PMUI.draw.SegmentMoveHandler} [moveHandler=null]
|
||
*/
|
||
this.moveHandler = null;
|
||
|
||
/**
|
||
* Creates an ArrayList of the intersections with other connections.
|
||
*
|
||
* // the structure is like:
|
||
* //intersections = [
|
||
* // {
|
||
* // center: point of intersection,
|
||
* // IdOtherConnection: id of the other connection
|
||
* // }
|
||
* //]
|
||
* @property {PMUI.util.ArrayList} [intersections=new PMUI.ArrayList()]
|
||
*/
|
||
this.intersections = new PMUI.util.ArrayList();
|
||
|
||
/**
|
||
* True if this segment has a move handler.
|
||
* @property {boolean} [hasMoveHandler=false]
|
||
*/
|
||
this.hasMoveHandler = false;
|
||
|
||
// set defaults
|
||
Segment.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Core', Segment);
|
||
|
||
/**
|
||
* The type of each instance of this class
|
||
* @property {String}
|
||
*/
|
||
Segment.prototype.type = "Segment";
|
||
|
||
/**
|
||
* Instance initializer which uses options to extend the config options to initialize the instance.
|
||
* @param {Object} options The object that contains the config
|
||
* @private
|
||
*/
|
||
Segment.prototype.init = function (options) {
|
||
/**
|
||
* Default options for the constructor
|
||
* @property {Object}
|
||
*/
|
||
var defaults = {
|
||
startPoint: new PMUI.util.Point(0, 0),
|
||
endPoint: new PMUI.util.Point(0, 0),
|
||
parent: null,
|
||
color: new PMUI.util.Color(0, 0, 0),
|
||
zOrder: 10
|
||
};
|
||
|
||
// extend recursively the defaultOptions with the given options
|
||
$.extend(true, defaults, options);
|
||
|
||
// init
|
||
this.setStartPoint(defaults.startPoint)
|
||
.setEndPoint(defaults.endPoint)
|
||
.setColor(defaults.color)
|
||
.setParent(defaults.parent)
|
||
.setZOrder(defaults.zOrder);
|
||
};
|
||
|
||
/**
|
||
* Creates the HTML Representation of the Segment.
|
||
* @returns {HTMLElement}
|
||
*/
|
||
Segment.prototype.createHTML = function () {
|
||
this.html = document.createElement('div');
|
||
this.html.id = this.id;
|
||
this.html.style.position = "absolute";
|
||
this.html.style.left = "0px";
|
||
this.html.style.top = "0px";
|
||
this.html.style.height = "0px";
|
||
this.html.style.width = "0px";
|
||
this.html.style.zIndex = this.zOrder;
|
||
return this.html;
|
||
};
|
||
|
||
/**
|
||
* Paints a segment by creating an instance of the class {@link PMUI.draw.Graphics} and
|
||
* calling {@link PMUI.draw.Graphics#drawLine}, it also append it's HTML to its parent's HTML.
|
||
* @chainable
|
||
*/
|
||
Segment.prototype.paint = function () {
|
||
if (this.getHTML() === null) {
|
||
return this;
|
||
}
|
||
if (this.graphics === null) {
|
||
this.graphics = new PMUI.draw.Graphics(this.html);
|
||
}
|
||
//dibujas linea llamar a drawLine de la clase graphics con los puntos
|
||
this.graphics.drawLine(this.startPoint.x, this.startPoint.y,
|
||
this.endPoint.x, this.endPoint.y, this.segmentStyle, this.segmentColor);
|
||
this.parent.html.appendChild(this.html);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Removes its HTML from the DOM.
|
||
* @chainable
|
||
*/
|
||
Segment.prototype.destroy = function () {
|
||
$(this.html).remove();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Paint this segment with the intersections it has stored (this method is called from
|
||
* {@link PMUI.draw.Connection#checkAndCreateIntersectionsWithAll}), it also append it's HTML to its parent's HTML.
|
||
* @chainable
|
||
*/
|
||
Segment.prototype.paintWithIntersections = function () {
|
||
|
||
// we have to paint the segment again so destroy the previous one
|
||
this.destroy();
|
||
|
||
var startPoint,
|
||
endPoint,
|
||
diff,
|
||
i,
|
||
reverse = false;
|
||
|
||
if (this.getHTML() === null) {
|
||
return this;
|
||
}
|
||
if (this.graphics === null) {
|
||
this.graphics = new PMUI.draw.Graphics(this.html);
|
||
}
|
||
|
||
//console.log(this.hasMoveHandler);
|
||
if (this.hasMoveHandler) {
|
||
$(this.moveHandler.html).remove();
|
||
this.addSegmentMoveHandler();
|
||
}
|
||
|
||
|
||
// default differentials to split the segment
|
||
if (this.orientation === this.HORIZONTAL) {
|
||
diff = new PMUI.util.Point(PMUI.draw.Shape.prototype.DEFAULT_RADIUS, 0);
|
||
if (this.startPoint.x > this.endPoint.x) {
|
||
reverse = true;
|
||
}
|
||
|
||
// for this to work we need to sort the intersections
|
||
this.intersections.sort(function (i, j) {
|
||
return i.center.x - j.center.x;
|
||
});
|
||
|
||
} else {
|
||
diff = new PMUI.util.Point(0, PMUI.draw.Shape.prototype.DEFAULT_RADIUS);
|
||
if (this.startPoint.y > this.endPoint.y) {
|
||
reverse = true;
|
||
}
|
||
|
||
// for this to work we need to sort the intersections
|
||
this.intersections.sort(function (i, j) {
|
||
return i.center.y - j.center.y;
|
||
});
|
||
}
|
||
this.graphics.graphics.clear();
|
||
|
||
startPoint = this.startPoint.clone();
|
||
for (i = 0; i < this.intersections.getSize(); i += 1) {
|
||
// if the direction is reverse then we get the
|
||
// inverse position for i in the array
|
||
if (reverse) {
|
||
endPoint = this.intersections
|
||
.get(this.intersections.getSize() - i - 1).center;
|
||
} else {
|
||
endPoint = this.intersections.get(i).center;
|
||
}
|
||
|
||
if (reverse) {
|
||
endPoint = endPoint.add(diff);
|
||
} else {
|
||
endPoint = endPoint.subtract(diff);
|
||
}
|
||
this.graphics.drawLine(startPoint.x, startPoint.y,
|
||
endPoint.x, endPoint.y, this.segmentStyle,
|
||
this.segmentColor, 0, 0, true);
|
||
if (reverse) {
|
||
startPoint = endPoint.subtract(diff.multiply(2));
|
||
} else {
|
||
startPoint = endPoint.add(diff.multiply(2));
|
||
}
|
||
}
|
||
|
||
// draw last segment
|
||
endPoint = this.endPoint.clone();
|
||
this.graphics.drawLine(startPoint.x, startPoint.y,
|
||
endPoint.x, endPoint.y, this.segmentStyle, this.segmentColor,
|
||
0, 0, true);
|
||
this.parent.html.appendChild(this.html);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Adds a segmentMoveHandler to this segment, it also append the segmentMoveHandler instance HTML to this HTML
|
||
* @chainable
|
||
*/
|
||
Segment.prototype.addSegmentMoveHandler = function () {
|
||
var midX = (this.startPoint.x + this.endPoint.x) / 2,
|
||
midY = (this.startPoint.y + this.endPoint.y) / 2;
|
||
this.moveHandler = new PMUI.draw.SegmentMoveHandler({
|
||
parent: this,
|
||
orientation: this.orientation,
|
||
style: {
|
||
cssProperties: {
|
||
border: "1px solid black"
|
||
}
|
||
}
|
||
});
|
||
midX -= this.moveHandler.width / 2;
|
||
midY -= this.moveHandler.height / 2;
|
||
this.moveHandler.setPosition(midX, midY);
|
||
this.html.appendChild(this.moveHandler.getHTML());
|
||
this.moveHandler.paint();
|
||
this.moveHandler.attachListeners(this.moveHandler);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns the parent of the segment
|
||
* @returns {PMUI.draw.Canvas / PMUI.draw.Connection}
|
||
*/
|
||
Segment.prototype.getParent = function () {
|
||
return this.parent;
|
||
};
|
||
|
||
/**
|
||
* Returns the start point of the segment.
|
||
* @returns {PMUI.util.Point}
|
||
*/
|
||
Segment.prototype.getStartPoint = function () {
|
||
return this.startPoint;
|
||
};
|
||
|
||
/**
|
||
* Returns the end point of the segment.
|
||
* @returns {PMUI.util.Point}
|
||
*/
|
||
Segment.prototype.getEndPoint = function () {
|
||
return this.endPoint;
|
||
};
|
||
|
||
/**
|
||
* Sets the parent of the segment.
|
||
* @param {Object} newParent
|
||
* @chainable
|
||
*/
|
||
Segment.prototype.setParent = function (newParent) {
|
||
this.parent = newParent;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the start point of the segment.
|
||
* @param {PMUI.util.Point} newPoint
|
||
* @chainable
|
||
*/
|
||
Segment.prototype.setStartPoint = function (newPoint) {
|
||
this.startPoint = newPoint;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the end point of the segment.
|
||
* @param {PMUI.util.Point} newPoint
|
||
* @chainable
|
||
*/
|
||
Segment.prototype.setEndPoint = function (newPoint) {
|
||
this.endPoint = newPoint;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the segmentStyle of this segment
|
||
* @param {string} newStyle
|
||
* @chainable
|
||
*
|
||
*/
|
||
Segment.prototype.setStyle = function (newStyle) {
|
||
this.segmentStyle = newStyle;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the color of this segment
|
||
* @param {PMUI.util.Color} newColor
|
||
* @chainable
|
||
*/
|
||
Segment.prototype.setColor = function (newColor) {
|
||
this.segmentColor = newColor;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Creates an intersection with `otherSegment` and saves it in `this.intersections`.
|
||
* If it doesn't have an intersection point passed as a parameter it will determine the
|
||
* intersection point and add it to `this.intersections` (`this.intersections` considers only unique points)
|
||
* @param {PMUI.draw.Segment} otherSegment
|
||
* @param {PMUI.util.Point} [ip] Intersection Point
|
||
* @chainable
|
||
*/
|
||
Segment.prototype.createIntersectionWith = function (otherSegment, ip) {
|
||
var intersectionObject,
|
||
intersectionPoint,
|
||
i,
|
||
goodToInsert = true;
|
||
if (ip) {
|
||
intersectionPoint = ip;
|
||
} else {
|
||
intersectionPoint = PMUI.draw.Geometry.segmentIntersectionPoint(this.startPoint,
|
||
this.endPoint, otherSegment.startPoint, otherSegment.endPoint);
|
||
}
|
||
|
||
// let's consider the case when an intersection point is the same e.g. when a segment crosses two
|
||
// other segments in the same point
|
||
for (i = 0; i < this.intersections.getSize(); i += 1) {
|
||
if (ip.equals(this.intersections.get(i).center)) {
|
||
goodToInsert = false;
|
||
}
|
||
}
|
||
|
||
if (goodToInsert) {
|
||
intersectionObject = new PMUI.draw.Intersection(intersectionPoint,
|
||
otherSegment.parent.getID(), this);
|
||
this.html.appendChild(intersectionObject.getHTML());
|
||
intersectionObject.paint();
|
||
this.intersections.insert(intersectionObject);
|
||
}
|
||
|
||
//console.log(intersectionObject);
|
||
//console.log(this.intersections);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Clear all the intersections in this segment.
|
||
* @chainable
|
||
*/
|
||
Segment.prototype.clearIntersections = function () {
|
||
var i,
|
||
intersection,
|
||
size = this.intersections.getSize();
|
||
while (size > 0) {
|
||
intersection = this.intersections.get(size - 1);
|
||
$(intersection.html).remove();
|
||
this.intersections.popLast();
|
||
size -= 1;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Moves the segment either to x or y but not both
|
||
(this method is called from {@link PMUI.draw.SegmentMoveHandler#event-drag}).
|
||
* @param {number} x new x coordinate of the segment in the canvas
|
||
* @param {number} y new y coordinate of the segment in the canvas
|
||
*/
|
||
Segment.prototype.moveSegment = function (x, y) {
|
||
var handler = this.moveHandler,
|
||
prevNeighbor = this.previousNeighbor,
|
||
nextNeighbor = this.nextNeighbor,
|
||
midX,
|
||
midY;
|
||
|
||
if (handler.orientation === handler.VERTICAL) {
|
||
this.startPoint.x = x
|
||
+ handler.width / 2;
|
||
this.endPoint.x = x
|
||
+ handler.width / 2;
|
||
prevNeighbor.endPoint.x =
|
||
this.startPoint.x;
|
||
nextNeighbor.startPoint.x =
|
||
this.endPoint.x;
|
||
} else {
|
||
this.startPoint.y = y
|
||
+ handler.height / 2;
|
||
this.endPoint.y = y
|
||
+ handler.height / 2;
|
||
prevNeighbor.endPoint.y =
|
||
this.startPoint.y;
|
||
nextNeighbor.startPoint.y =
|
||
this.endPoint.y;
|
||
}
|
||
|
||
// fix handler for the this segment
|
||
if (this.moveHandler) { // of course yes!
|
||
midX = (this.startPoint.x + this.endPoint.x) / 2
|
||
- this.moveHandler.width / 2;
|
||
midY = (this.startPoint.y + this.endPoint.y) / 2
|
||
- this.moveHandler.height / 2;
|
||
this.moveHandler.setPosition(midX, midY);
|
||
}
|
||
|
||
// paint the previous segment
|
||
prevNeighbor.paint();
|
||
// fix handler for the prev segment if possible
|
||
if (prevNeighbor.moveHandler) {
|
||
midX = (prevNeighbor.startPoint.x + prevNeighbor.endPoint.x) / 2
|
||
- prevNeighbor.moveHandler.width / 2;
|
||
midY = (prevNeighbor.startPoint.y + prevNeighbor.endPoint.y) / 2
|
||
- prevNeighbor.moveHandler.height / 2;
|
||
prevNeighbor.moveHandler.setPosition(midX, midY);
|
||
}
|
||
|
||
// paint the next segment
|
||
nextNeighbor.paint();
|
||
// fix moveHandler for the next segment if possible
|
||
if (nextNeighbor.moveHandler) {
|
||
midX = (nextNeighbor.startPoint.x + nextNeighbor.endPoint.x) / 2
|
||
- nextNeighbor.moveHandler.width / 2;
|
||
midY = (nextNeighbor.startPoint.y + nextNeighbor.endPoint.y) / 2
|
||
- nextNeighbor.moveHandler.height / 2;
|
||
nextNeighbor.moveHandler.setPosition(midX, midY);
|
||
}
|
||
|
||
this.paint();
|
||
return this;
|
||
};
|
||
|
||
Segment.prototype.hit = function (coronaWidth, point) {
|
||
var dotprod, projlenSq;
|
||
// Adjust vectors relative to X1,Y1
|
||
// X2,Y2 becomes relative vector from X1,Y1 to end of segment
|
||
X1 = this.startPoint.x;
|
||
Y1 = this.startPoint.y;
|
||
X2 = this.endPoint.x;
|
||
Y2 = this.endPoint.y;
|
||
px = point.x;
|
||
py = point.y
|
||
|
||
X2 -= X1;
|
||
Y2 -= Y1;
|
||
|
||
px -= X1;
|
||
py -= Y1;
|
||
|
||
dotprod = px * X2 + py * Y2;
|
||
if (dotprod <= 0.0) {
|
||
projlenSq = 0.0;
|
||
} else {
|
||
px = X2 - px;
|
||
py = Y2 - py;
|
||
dotprod = px * X2 + py * Y2;
|
||
if (dotprod <= 0.0) {
|
||
projlenSq = 0.0;
|
||
} else {
|
||
projlenSq = dotprod * dotprod / (X2 * X2 + Y2 * Y2);
|
||
}
|
||
}
|
||
|
||
var lenSq = px * px + py * py - projlenSq;
|
||
if (lenSq < 0) {
|
||
lenSq = 0;
|
||
}
|
||
return Math.sqrt(lenSq) < coronaWidth;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.Segment', Segment);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = Segment;
|
||
}
|
||
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.draw.ReadOnlyLayer
|
||
* Layer used to give the canvas a readonly state so that the user can just look
|
||
* at the diagram and not be able to perform any modification,
|
||
* the canvas is in charge of instantiating this object when its property
|
||
* readOnly is set to true, there is no need to instance this object
|
||
* independently
|
||
* @extends PMUI.draw.Core
|
||
*
|
||
* @constructor
|
||
* Creates an instance of this class
|
||
* @param {Object} options configuration options inherited from Core
|
||
*/
|
||
|
||
var ReadOnlyLayer = function (options) {
|
||
ReadOnlyLayer.superclass.call(this, options);
|
||
ReadOnlyLayer.prototype.initObject.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.draw.Core', ReadOnlyLayer);
|
||
|
||
/**
|
||
* Creates the HTML and attach the event listeners
|
||
* @param options
|
||
*/
|
||
ReadOnlyLayer.prototype.initObject = function (options) {
|
||
this.createHTML();
|
||
this.attachListeners();
|
||
};
|
||
/**
|
||
* Attach the event listeners necessary for blocking interactions
|
||
*/
|
||
ReadOnlyLayer.prototype.attachListeners = function () {
|
||
var $layer = $(this.html);
|
||
$layer.on('mousedown', this.onMouseDown(this))
|
||
.on('mouseup', this.onMouseUp(this))
|
||
.on('mousemove', this.onMouseMove(this))
|
||
.on('click', this.onClick(this))
|
||
.droppable({
|
||
accept: "*",
|
||
greedy: true,
|
||
onDrop: function () {
|
||
return false;
|
||
}
|
||
});
|
||
};
|
||
/**
|
||
* Stops the propagation of the mousedown event
|
||
* @param {PMUI.draw.ReadOnlyLayer} layer
|
||
* @return {Function}
|
||
*/
|
||
ReadOnlyLayer.prototype.onMouseDown = function (layer) {
|
||
return function (e, ui) {
|
||
e.stopPropagation();
|
||
};
|
||
};
|
||
/**
|
||
* Stops the propagation of the mouseup event
|
||
* @param {PMUI.draw.ReadOnlyLayer} layer
|
||
* @return {Function}
|
||
*/
|
||
ReadOnlyLayer.prototype.onMouseUp = function (layer) {
|
||
return function (e, ui) {
|
||
e.stopPropagation();
|
||
};
|
||
};
|
||
/**
|
||
* Stops the propagation of the click event
|
||
* @param {PMUI.draw.ReadOnlyLayer}layer
|
||
* @return {Function}
|
||
*/
|
||
ReadOnlyLayer.prototype.onClick = function (layer) {
|
||
return function (e, ui) {
|
||
e.stopPropagation();
|
||
};
|
||
};
|
||
/**
|
||
* Stops the propagation of the mousemove event
|
||
* @param {PMUI.draw.ReadOnlyLayer} layer
|
||
* @return {Function}
|
||
*/
|
||
ReadOnlyLayer.prototype.onMouseMove = function (layer) {
|
||
return function (e, ui) {
|
||
e.stopPropagation();
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.draw.ReadOnlyLayer', ReadOnlyLayer);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = ReadOnlyLayer;
|
||
}
|
||
|
||
}());
|
||
|
||
|
||
(function () {
|
||
var DataItem = function (key, value) {
|
||
this.id = PMUI.generateUniqueId();
|
||
this.val = value;
|
||
this.key = key;
|
||
};
|
||
|
||
DataItem.prototype.type = 'DataItem';
|
||
|
||
DataItem.prototype.family = 'DataItem';
|
||
|
||
DataItem.prototype.getKey = function () {
|
||
return this.key;
|
||
};
|
||
|
||
DataItem.prototype.getValue = function () {
|
||
return this.val;
|
||
};
|
||
|
||
DataItem.prototype.setKey = function (key) {
|
||
this.key = key;
|
||
return this;
|
||
};
|
||
|
||
DataItem.prototype.setValue = function (value) {
|
||
this.val = value;
|
||
return this;
|
||
};
|
||
|
||
DataItem.prototype.set = function (key, value) {
|
||
this.key = key;
|
||
this.val = value;
|
||
return this;
|
||
};
|
||
|
||
DataItem.prototype.get = function () {
|
||
var aux = {};
|
||
aux[this.key] = this.val;
|
||
return aux;
|
||
};
|
||
|
||
DataItem.prototype.getRecord = function () {
|
||
return {
|
||
key: this.key,
|
||
value: this.val
|
||
};
|
||
};
|
||
|
||
DataItem.prototype.clear = function () {
|
||
this.val = null;
|
||
this.key = null;
|
||
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.data.DataItem', DataItem);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = DataItem;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
var DataField = function (options) {
|
||
options = options || {};
|
||
DataField.superclass.call(this, options.key, options.value);
|
||
this.typeField = null;
|
||
this.custom = null;
|
||
this.customKeys = {};
|
||
DataField.prototype.init.call(this, options);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.data.DataItem', DataField);
|
||
|
||
DataField.prototype.type = "DataField";
|
||
|
||
DataField.prototype.dataTypes = {
|
||
"string": "native",
|
||
"number": "native",
|
||
"date": "native",
|
||
"boolean": "native",
|
||
"object": "native"
|
||
};
|
||
|
||
DataField.prototype.basicKeys = {
|
||
"key": "native",
|
||
"value": "native",
|
||
"type": "class",
|
||
"val": "private",
|
||
"custom": "native",
|
||
"customKeys": "native",
|
||
"typeField": "native",
|
||
"family": "class"
|
||
};
|
||
|
||
DataField.prototype.defaultType = "string";
|
||
|
||
DataField.prototype.init = function (options) {
|
||
var that = this;
|
||
if (options) {
|
||
this.setKey(options.key || null);
|
||
this.setValue(options.value || null);
|
||
this.setType(options.type || null);
|
||
}
|
||
jQuery.each(options, function (k, v) {
|
||
if (!that.basicKeys[k]) {
|
||
if (typeof v !== 'object' && typeof v !== 'function') {
|
||
that[k] = v;
|
||
that.customKeys[k] = 'custom';
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
DataField.prototype.setType = function (type) {
|
||
if (type) {
|
||
if (this.dataTypes[type]) {
|
||
this.typeField = type;
|
||
this.custom = false;
|
||
} else {
|
||
this.typeField = type;
|
||
this.custom = true;
|
||
}
|
||
} else {
|
||
this.custom = false;
|
||
this.typeField = this.defaultType;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
DataField.prototype.addAttribute = function (key, value) {
|
||
this.customKeys[key] = value;
|
||
return this;
|
||
};
|
||
|
||
DataField.prototype.getAttribute = function (key) {
|
||
if (key === 'val' || key === 'key') {
|
||
return this[key];
|
||
}
|
||
return this.customKeys[key];
|
||
};
|
||
|
||
DataField.prototype.existsKey = function (key) {
|
||
if (key === "val" || key === "key") {
|
||
return true;
|
||
}
|
||
return this.customKeys.hasOwnProperty(key);
|
||
};
|
||
|
||
DataField.prototype.getRecord = function (format) {
|
||
var castType = format || this.typeField,
|
||
out = {
|
||
key: this.key,
|
||
type: this.typeField,
|
||
value: PMUI.castValue(this.val, castType)
|
||
};
|
||
jQuery.each(this.customKeys, function (key, value) {
|
||
out[key] = value;
|
||
});
|
||
return out;
|
||
};
|
||
|
||
DataField.prototype.clear = function () {
|
||
var key;
|
||
DataField.superclass.prototype.clear.call(this);
|
||
for (key in this.customKeys) {
|
||
if (this.customKeys.hasOwnProperty(key)) {
|
||
delete this.customKeys[key];
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.data.DataField', DataField);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = DataField;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
var DataSet = function (options) {
|
||
this.items = null;
|
||
this.factory = null;
|
||
DataSet.prototype.init.call(this, options);
|
||
};
|
||
|
||
DataSet.prototype.type = "DataSet";
|
||
|
||
DataSet.prototype.family = "DataSet";
|
||
|
||
DataSet.prototype.init = function (options) {
|
||
var defaults = {
|
||
factory: {
|
||
products: {
|
||
"datafield": PMUI.data.DataField,
|
||
"dataitem": PMUI.data.DataItem
|
||
},
|
||
defaultProduct: "dataitem"
|
||
},
|
||
items: []
|
||
};
|
||
jQuery.extend(true, defaults, options);
|
||
this.items = new PMUI.util.ArrayList();
|
||
this.factory = new PMUI.util.Factory(defaults.factory);
|
||
this.setItems(defaults.items);
|
||
};
|
||
|
||
DataSet.prototype.setItems = function (items) {
|
||
var that = this;
|
||
jQuery.each(items, function (k, item) {
|
||
that.items.insert(that.factory.make(item));
|
||
});
|
||
return this;
|
||
};
|
||
|
||
DataSet.prototype.addItem = function (item) {
|
||
if (item) {
|
||
this.items.insert(this.factory.make(item));
|
||
}
|
||
return this;
|
||
};
|
||
|
||
DataSet.prototype.getData = function () {
|
||
var items,
|
||
that = this,
|
||
out = [];
|
||
items = this.items.asArray();
|
||
jQuery.each(items, function (k, item) {
|
||
out.push(item.getRecord());
|
||
});
|
||
return out;
|
||
};
|
||
|
||
DataSet.prototype.getJSON = function () {
|
||
return JSON.stringify(this.getData());
|
||
};
|
||
|
||
DataSet.prototype.getXML = function () {
|
||
return PMUI.json2xml(this.getJSON());
|
||
};
|
||
|
||
DataSet.prototype.removeItem = function (item) {
|
||
this.items.remove(item);
|
||
};
|
||
|
||
DataSet.prototype.getValue = function (key) {
|
||
var item = this.items.find('key', key);
|
||
return item.getValue();
|
||
};
|
||
|
||
DataSet.prototype.setValue = function (key, value) {
|
||
var item = this.items.find('key', key);
|
||
item.setValue(value);
|
||
return this;
|
||
};
|
||
|
||
DataSet.prototype.keys = function () {
|
||
var items,
|
||
out = [];
|
||
items = this.items.asArray();
|
||
jQuery.each(items, function (k, item) {
|
||
out.push(item.getKey());
|
||
});
|
||
return out;
|
||
};
|
||
|
||
DataSet.prototype.values = function () {
|
||
var items,
|
||
out = [];
|
||
items = this.items.asArray();
|
||
jQuery.each(items, function (k, item) {
|
||
out.push(item.getValue());
|
||
});
|
||
return out;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.data.DataSet', DataSet);
|
||
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = DataSet;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.control.OptionsSelectorItemControl
|
||
* @extends PMUI.control.HTMLControl
|
||
*
|
||
* The class is the basic element for {@link PMUI.control.OptionsSelectorControl OptionsSelectorControl} class.
|
||
*
|
||
* For instance the class, the sentences below show how do it.
|
||
*
|
||
* @example
|
||
* new PMUI.control.OptionsSelectorItemControl({
|
||
* text: ....
|
||
* });
|
||
*
|
||
* @cfg {Boolean} selected Sets an item as selected inside of the {@link PMUI.control.OptionsSelectorControl component}
|
||
* @cfg {String} text Defines the label for the component, the text that appear inside of the component
|
||
*
|
||
*/
|
||
var OptionsSelectorItemControl = function (settings) {
|
||
OptionsSelectorItemControl.superclass.call(this, settings);
|
||
/**
|
||
* @property {Boolean} [selected=false]
|
||
* Sets an item as selected inside of the {@link PMUI.control.OptionsSelectorControl component}
|
||
*/
|
||
this.selected = null;
|
||
/**
|
||
* @property {String} [cls='pmui-switch-buttonitem']
|
||
* Sets the class name for the component. It is related to the styles for the element
|
||
*/
|
||
this.cls = null;
|
||
/**
|
||
* @property {String} [iconCls]
|
||
* Sets the class name for the icon of the component.
|
||
*/
|
||
this.iconCls = null;
|
||
/**
|
||
* @property {String} [clsSelected= 'pmui-switch-buttonitem-selected']
|
||
* Sets the class name when an item is selected
|
||
*/
|
||
this.clsSelected = null;
|
||
/**
|
||
* @property {Object} [dom=null]
|
||
* Represents the DOM of the component
|
||
*/
|
||
this.dom = null;
|
||
/**
|
||
* @property {Object} [disabled=false]
|
||
* Defines whether the item is disabled or enabled
|
||
*/
|
||
this.disabled = null;
|
||
/**
|
||
* @property {String} [text=null]
|
||
* Defines the label for the component, the text that appear inside of the component
|
||
*/
|
||
this.text = null;
|
||
|
||
OptionsSelectorItemControl.prototype.init.call(this, settings);
|
||
};
|
||
PMUI.inheritFrom("PMUI.control.HTMLControl", OptionsSelectorItemControl);
|
||
/**
|
||
*
|
||
*
|
||
*/
|
||
OptionsSelectorItemControl.prototype.type = "button";
|
||
/**
|
||
*
|
||
*
|
||
*/
|
||
OptionsSelectorItemControl.prototype.family = "Item";
|
||
|
||
OptionsSelectorItemControl.prototype.init = function (settings) {
|
||
var defaults = {
|
||
selected: false,
|
||
disabled: false,
|
||
cls: 'pmui-switch-buttonitem',
|
||
iconCls: 'pmui-switch-buttonitem-icon',
|
||
clsSelected: 'pmui-switch-buttonitem-selected',
|
||
items: [],
|
||
text: '',
|
||
value: ''
|
||
};
|
||
jQuery.extend(true, defaults, settings);
|
||
this.setSelected(defaults.selected)
|
||
.setCls(defaults.cls)
|
||
.setClsSelected(defaults.clsSelected)
|
||
.setIconClass(defaults.iconCls)
|
||
.setText(defaults.text)
|
||
.setDisable(defaults.disabled)
|
||
.setValue(defaults.value);
|
||
};
|
||
/**
|
||
*
|
||
*
|
||
*/
|
||
OptionsSelectorItemControl.prototype.setSelected = function (status) {
|
||
var otherElements,
|
||
i,
|
||
that = this;
|
||
this.selected = (typeof status === 'boolean') ? status : false;
|
||
return this;
|
||
};
|
||
/**
|
||
*
|
||
*
|
||
*/
|
||
OptionsSelectorItemControl.prototype.setCls = function (className) {
|
||
this.cls = (typeof className === 'string') ? className : '';
|
||
return this;
|
||
};
|
||
/**
|
||
*
|
||
*
|
||
*/
|
||
OptionsSelectorItemControl.prototype.setClsSelected = function (className) {
|
||
this.clsSelected = (typeof className === 'string') ? className : '';
|
||
return this;
|
||
};
|
||
/**
|
||
*
|
||
*
|
||
*/
|
||
OptionsSelectorItemControl.prototype.setIconClass = function (className) {
|
||
this.iconCls = (typeof className === 'string') ? className : '';
|
||
return this;
|
||
};
|
||
/**
|
||
*
|
||
*
|
||
*/
|
||
OptionsSelectorItemControl.prototype.setText = function (text) {
|
||
this.text = (typeof text === 'string') ? text : '';
|
||
return this;
|
||
};
|
||
OptionsSelectorItemControl.prototype.setValue = function (value) {
|
||
value = value.toString();
|
||
if (typeof value === 'string') {
|
||
if (value.length === 0) {
|
||
this.value = this.text;
|
||
} else {
|
||
this.value = value;
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
*
|
||
*
|
||
*/
|
||
OptionsSelectorItemControl.prototype.activeElement = function (that) {
|
||
var i;
|
||
|
||
if (typeof that === "undefined") {
|
||
that = this;
|
||
}
|
||
if (!that.disabled) {
|
||
if (!that.parent.itemsSelected.contains(that)) {
|
||
that.parent.itemsSelected.insert(that);
|
||
}
|
||
that.setSelected(true);
|
||
if (this.dom) {
|
||
that.dom.container.className = that.clsSelected;
|
||
for (i = 0; i < that.style.getClasses().length; i += 1) {
|
||
that.dom.container.className += " " + that.style.getClasses()[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
*
|
||
*
|
||
*/
|
||
OptionsSelectorItemControl.prototype.desactiveElement = function (that) {
|
||
var i;
|
||
if (typeof that === "undefined") {
|
||
that = this;
|
||
}
|
||
if (!that.disabled) {
|
||
that.parent.itemsSelected.remove(that);
|
||
that.setSelected(false);
|
||
if (this.dom) {
|
||
that.dom.container.className = that.cls;
|
||
for (i = 0; i < that.style.getClasses().length; i += 1) {
|
||
that.dom.container.className += " " + that.style.getClasses()[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Disables/enables the control
|
||
* @param {Boolean} setDisable If the value is evaluated as true then the control is disabled,
|
||
* otherwise the control is enabled.
|
||
* @chainable
|
||
*/
|
||
OptionsSelectorItemControl.prototype.setDisable = function (disable) {
|
||
if (typeof disable === 'boolean') {
|
||
this.disabled = disable;
|
||
if (this.html) {
|
||
if (disable) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* [disable description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
OptionsSelectorItemControl.prototype.disable = function () {
|
||
if (arguments[0] === undefined) {
|
||
this.disabled = true;
|
||
if (this.html) {
|
||
jQuery(this.html).unbind("click");
|
||
this.html.setAttribute("class", "pmui-switch-buttonitem-disabled");
|
||
}
|
||
} else {
|
||
if (arguments[0]) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* [enable description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
OptionsSelectorItemControl.prototype.enable = function () {
|
||
if (arguments[0] === undefined) {
|
||
this.disabled = false;
|
||
if (this.html) {
|
||
this.html.setAttribute("class", this.cls);
|
||
this.defineEvents();
|
||
}
|
||
} else {
|
||
if (arguments[0]) {
|
||
this.disable();
|
||
} else {
|
||
this.enable();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
*
|
||
*
|
||
*/
|
||
OptionsSelectorItemControl.prototype.selectItem = function () {
|
||
var that = this,
|
||
otherElements;
|
||
|
||
if (this.selected) {
|
||
that.desactiveElement(that);
|
||
} else {
|
||
that.activeElement(that);
|
||
if (this.parent.multipleSelection === false) {
|
||
otherElements = this.parent.items.asArray();
|
||
for (i = 0; i < otherElements.length; i += 1) {
|
||
if (that.id !== otherElements[i].id) {
|
||
that.desactiveElement(otherElements[i]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
*
|
||
*
|
||
*/
|
||
OptionsSelectorItemControl.prototype.createHTML = function () {
|
||
var li,
|
||
display,
|
||
button,
|
||
icon,
|
||
text,
|
||
i;
|
||
|
||
OptionsSelectorItemControl.superclass.prototype.setElementTag.call(this, "a");
|
||
OptionsSelectorItemControl.superclass.prototype.createHTML.call(this);
|
||
|
||
//button = PMUI.createHTMLElement("a");
|
||
//button.id = PMUI.generateUniqueId()
|
||
if (this.disabled) {
|
||
this.html.className = "pmui-switch-buttonitem-disabled";
|
||
} else {
|
||
this.html.className = this.cls;
|
||
for (i = 0; i < this.style.getClasses().length; i += 1) {
|
||
this.html.className += " " + this.style.getClasses()[i];
|
||
}
|
||
}
|
||
|
||
this.html.href = '#';
|
||
if (this.parent.orientation === 'vertical') {
|
||
this.html.setAttribute("style", "display: block;");
|
||
}
|
||
icon = PMUI.createHTMLElement("span");
|
||
icon.className = this.iconCls;
|
||
text = PMUI.createHTMLElement("span");
|
||
text.innerHTML = this.text;
|
||
this.html.appendChild(icon);
|
||
this.html.appendChild(text);
|
||
|
||
this.dom = {
|
||
container: this.html,
|
||
items: [
|
||
{
|
||
icon: icon
|
||
},
|
||
{
|
||
text: text
|
||
}
|
||
]
|
||
};
|
||
if (this.selected) {
|
||
this.activeElement(this);
|
||
}
|
||
this.html.id = this.id;
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Defines events related to the object.
|
||
*/
|
||
OptionsSelectorItemControl.prototype.defineEvents = function () {
|
||
var j,
|
||
fnSelect,
|
||
children,
|
||
that = this;
|
||
this.removeEvents().eventsDefined = true;
|
||
if (!this.disabled) {
|
||
that.addEvent('click').listen(this.html, function (e) {
|
||
e.preventDefault();
|
||
that.selectItem();
|
||
fnSelect = that.parent.listeners.select;
|
||
fnSelect(that, e);
|
||
e.stopPropagation();
|
||
});
|
||
if (e.which === PMUI.keyCodeF5) {
|
||
this.blur();
|
||
e.preventDefault();
|
||
window.location.reload(true);
|
||
}
|
||
}
|
||
};
|
||
PMUI.extendNamespace("PMUI.control.OptionsSelectorItemControl", OptionsSelectorItemControl);
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = OptionsSelectorItemControl;
|
||
}
|
||
}());
|
||
|
||
(function () {
|
||
/**
|
||
* @class PMUI.control.OptionsSelectorControl
|
||
* @extends PMUI.control.HTMLControl
|
||
* Class to handle the Select HTML form element.
|
||
*
|
||
* Example usage:
|
||
*
|
||
* @example
|
||
* OptionsSelectorControl = new PMUI.control.OptionsSelectorControl({
|
||
* items: [
|
||
* {
|
||
* text: "First option"
|
||
* },
|
||
* {
|
||
* text: "Second option",
|
||
* selected: true
|
||
* },
|
||
* {
|
||
* text: "Third option"
|
||
* }
|
||
* ],
|
||
* listeners: {
|
||
* select: function (item, event) {
|
||
* console.log("selected", item);
|
||
* }
|
||
* }
|
||
* });
|
||
* document.body.appendChild(OptionsSelectorControl.getHTML());
|
||
* OptionsSelectorControl.defineEvents();
|
||
*
|
||
* @cfg {Array} items Defines the data items as an array objects.
|
||
*
|
||
* items: [
|
||
* {
|
||
* ...
|
||
* },
|
||
* {
|
||
* text: "Item1",
|
||
* selected: true
|
||
* },
|
||
* {
|
||
* ...
|
||
* }
|
||
* ]
|
||
*
|
||
* @cfg {Boolean} multipleSelection Defines wether the component will support the behavior of the check group.
|
||
*
|
||
*
|
||
*/
|
||
var OptionsSelectorControl = function (settings) {
|
||
OptionsSelectorControl.superclass.call(this, settings);
|
||
/**
|
||
* @property {Boolean} [multipleSelection=false] If the property is enabled, the items can be
|
||
* selected like checkGroup otherwise is like to radioGroup
|
||
*/
|
||
this.multipleSelection = null;
|
||
/**
|
||
* @property {String} [orientation=null]
|
||
*
|
||
*/
|
||
this.orientation = null;
|
||
/**
|
||
* @property {Object} [container=null]
|
||
* @private
|
||
*/
|
||
this.container = null;
|
||
/**
|
||
* @property {Object} [listeners] A config object containing one or more handlers to be added
|
||
* to this object during initialization. By default the 'select' handler is enabled
|
||
* @readOnly
|
||
*/
|
||
this.listeners = {
|
||
/**
|
||
* @event select
|
||
* Fires when the component has been selected. Returning the current object and the event.
|
||
* @return {Object} {@link PMUI.control.OptionsSelectorItemControl OptionsSelectorItemControl}
|
||
* @return {Object} event
|
||
*/
|
||
select: function () {
|
||
}
|
||
};
|
||
/**
|
||
* @property {@link PMUI.util.ArrayList ArrayList}
|
||
*
|
||
*/
|
||
this.itemsSelected = null;
|
||
|
||
this.items = new PMUI.util.ArrayList();
|
||
OptionsSelectorControl.prototype.init.call(this, settings);
|
||
};
|
||
PMUI.inheritFrom('PMUI.control.HTMLControl', OptionsSelectorControl);
|
||
OptionsSelectorControl.prototype.type = "control";
|
||
OptionsSelectorControl.prototype.family = "control";
|
||
|
||
OptionsSelectorControl.prototype.init = function (settings) {
|
||
var defaults = {
|
||
multipleSelection: false,
|
||
orientation: 'horizontal',
|
||
items: [],
|
||
iconClass: '',
|
||
listeners: {
|
||
select: function () {
|
||
}
|
||
}
|
||
};
|
||
jQuery.extend(true, defaults, settings);
|
||
this.setMultipleSelection(defaults.multipleSelection)
|
||
.setOrientation(defaults.orientation)
|
||
.setChildren(defaults.items)
|
||
.setIconClass(defaults.iconClass)
|
||
.setListeners(defaults.listeners);
|
||
|
||
this.itemsSelected = new PMUI.util.ArrayList();
|
||
|
||
};
|
||
/**
|
||
* Sets the value whether the {@link PMUI.control.OptionsSelectorItemControl items} can be selected
|
||
* at the same time
|
||
* @param {Boolean} status
|
||
*/
|
||
OptionsSelectorControl.prototype.setMultipleSelection = function (status) {
|
||
this.multipleSelection = (typeof status === 'boolean') ? status : false;
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the orientation for every {@link PMUI.control.OptionsSelectorItemControl element}
|
||
* There are two possibilities:
|
||
* - horizontal, the elements will appear horizontally
|
||
* - vertical, the elements will appear vertically
|
||
* @param {String} orientation
|
||
*/
|
||
OptionsSelectorControl.prototype.setOrientation = function (orientation) {
|
||
var i,
|
||
items,
|
||
options = {
|
||
horizontal: true,
|
||
vertical: true
|
||
},
|
||
layout;
|
||
this.orientation = (options[orientation]) ? orientation : 'horizontal';
|
||
if (this.html) {
|
||
items = this.items.asArray();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
if (this.orientation === "vertical") {
|
||
items[i].html.setAttribute("style", "display:block;");
|
||
this.html.setAttribute("style", "display:inline-table;");
|
||
} else {
|
||
items[i].html.removeAttribute("style");
|
||
this.html.removeAttribute("style");
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the {@link PMUI.control.OptionsSelectorItemControl elements} child inside of
|
||
* {@link PMUI.control.OptionsSelectorControl container}
|
||
* @param {Array} items Represents to children
|
||
*/
|
||
OptionsSelectorControl.prototype.setChildren = function (items) {
|
||
var i;
|
||
if (items instanceof Array) {
|
||
this.items.clear();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
this.addItem(items[i]);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* SetValue method
|
||
* @param {String} values Defines the current values of the items
|
||
*/
|
||
OptionsSelectorControl.prototype.setValue = function (values) {
|
||
var options,
|
||
items,
|
||
i,
|
||
separator;
|
||
|
||
if (values) {
|
||
if (values.length > 0) {
|
||
//options = JSON.parse(values);
|
||
separator = this.field.separator;
|
||
options = values.split(separator);
|
||
items = this.items.asArray();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
if (jQuery.inArray(items[i].getValue(), options) !== -1) {
|
||
items[i].selected = false;
|
||
items[i].selectItem();
|
||
}
|
||
}
|
||
|
||
if (this.multipleSelection === false && options.length > 1) {
|
||
throw new Error("Is not possible sets more than one when the multipleSelection property is false.")
|
||
}
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the class name for the icon that appears in the header
|
||
* @param {String} class name
|
||
*/
|
||
OptionsSelectorControl.prototype.setIconClass = function (className) {
|
||
this.iconClass = (typeof className === 'string') ? className : '';
|
||
return this;
|
||
};
|
||
/**
|
||
* Gets items selected
|
||
* @return {Object} this
|
||
*/
|
||
OptionsSelectorControl.prototype.getItemsSelected = function () {
|
||
return this.itemsSelected.asArray()
|
||
};
|
||
/**
|
||
* Sets listeners to object
|
||
* @param {Object} listeners
|
||
*/
|
||
OptionsSelectorControl.prototype.setListeners = function (listeners) {
|
||
if (typeof listeners === 'object') {
|
||
this.listeners = listeners;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Adds new items to the component
|
||
* @param {Object|{@link PMUI.control.OptionsSelectorItemControl OptionsSelectorItemControl}} item Represents the item
|
||
* for the parent container.
|
||
* @return {PMUI.control.OptionsSelectorControl} this
|
||
*/
|
||
OptionsSelectorControl.prototype.addItem = function (item) {
|
||
var factory,
|
||
itemToBeAdded;
|
||
factory = new PMUI.behavior.BehaviorFactory({
|
||
products: {
|
||
"optionsSelectorItem": PMUI.control.OptionsSelectorItemControl
|
||
},
|
||
defaultProduct: "optionsSelectorItem"
|
||
});
|
||
if (typeof item === "object") {
|
||
itemToBeAdded = factory.make(item);
|
||
}
|
||
|
||
itemToBeAdded.parent = this;
|
||
this.items.insert(itemToBeAdded);
|
||
if (this.html) {
|
||
this.html.appendChild(itemToBeAdded.getHTML());
|
||
itemToBeAdded.defineEvents();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes and item
|
||
* @param {[type]} item [description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
OptionsSelectorControl.prototype.removeOption = function (position) {
|
||
var items = this.items.asArray(),
|
||
item;
|
||
if (items[position]) {
|
||
item = items[position];
|
||
this.items.remove(item);
|
||
this.html.removeChild(item.html);
|
||
}
|
||
return item;
|
||
};
|
||
/**
|
||
* [disableOption description]
|
||
* @param {[type]} position [description]
|
||
* @param {[type]} disabled [description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
OptionsSelectorControl.prototype.disableOption = function (position, disable) {
|
||
var items = this.items.asArray(),
|
||
item;
|
||
|
||
if (items[position]) {
|
||
item = items[position];
|
||
item.setDisable(disable)
|
||
}
|
||
|
||
return item;
|
||
};
|
||
OptionsSelectorControl.prototype.getOptions = function () {
|
||
return this.items.asArray();
|
||
};
|
||
OptionsSelectorControl.prototype.clearOptions = function () {
|
||
var items = this.items.asArray(),
|
||
i;
|
||
for (i = 0; i < items.length; i += 1) {
|
||
this.html.removeChild(items[i].html);
|
||
}
|
||
|
||
this.items.clear();
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Creates the HTML elements
|
||
* @return {HTMLElement} Returns the HTMLElement of the current component
|
||
*/
|
||
OptionsSelectorControl.prototype.createHTML = function () {
|
||
var container,
|
||
items,
|
||
i;
|
||
container = PMUI.createHTMLElement("span");
|
||
container.className = "pmui-field-control-container";
|
||
if (this.orientation === "vertical") {
|
||
container.setAttribute("style", "display:inline-table;");
|
||
}
|
||
|
||
items = this.items.asArray();
|
||
if (typeof items.length === 'number') {
|
||
for (i = 0; i < items.length; i += 1) {
|
||
container.appendChild(items[i].getHTML());
|
||
}
|
||
}
|
||
container.id = this.id;
|
||
this.html = container;
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Defines and active all the events related to the object
|
||
*/
|
||
OptionsSelectorControl.prototype.defineEvents = function () {
|
||
var that = this,
|
||
items,
|
||
i;
|
||
|
||
this.eventsDefined = true;
|
||
if (that.items.getSize() > 0) {
|
||
items = that.items.asArray();
|
||
for (i = 0; i < items.length; i += 1) {
|
||
items[i].defineEvents();
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
|
||
PMUI.extendNamespace("PMUI.control.OptionsSelectorControl", OptionsSelectorControl);
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = OptionsSelectorControl;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.field.OptionsSelectorField
|
||
* @extends PMUI.form.Field
|
||
*
|
||
* How use the class.
|
||
* The component represents basically two types of known controls, those are the radio group and check group fields.
|
||
* By default the component has the functionality to the radio group field with a better look and feel.
|
||
*
|
||
* The example below shows the parameters (config options) for build an field of options selector (radio group).
|
||
*
|
||
* @example
|
||
* OptionsSelectorControl = new PMUI.field.OptionsSelectorField({
|
||
* label: "radiogroup",
|
||
* items: [
|
||
* {
|
||
* text: "First option"
|
||
* },
|
||
* {
|
||
* text: "Second option",
|
||
* selected: true
|
||
* },
|
||
* {
|
||
* text: "Third option"
|
||
* }
|
||
* ],
|
||
* listeners: {
|
||
* select: function (item, event) {
|
||
* console.log("selected", item);
|
||
* }
|
||
* }
|
||
* });
|
||
* document.body.appendChild(OptionsSelectorControl.getHTML());
|
||
* OptionsSelectorControl.defineEvents();
|
||
*
|
||
*
|
||
* The otherwise is posible create a check group field applying the following sentence on the JSON config:
|
||
*
|
||
* { ...
|
||
* multipleSelection: true
|
||
* ...
|
||
* }
|
||
*
|
||
* With the above parameter the component will have the behavior of the check group field.
|
||
*
|
||
* @example
|
||
* checkboxGroup = new PMUI.field.OptionsSelectorField({
|
||
* label: "radiogroup",
|
||
* multipleSelection: true,
|
||
* items: [
|
||
* {
|
||
* text: "First option"
|
||
* },
|
||
* {
|
||
* text: "Second option",
|
||
* selected: true
|
||
* },
|
||
* {
|
||
* text: "Third option"
|
||
* }
|
||
* ],
|
||
* listeners: {
|
||
* select: function (item, event) {
|
||
* console.log("selected", item);
|
||
* }
|
||
* }
|
||
* });
|
||
* document.body.appendChild(checkboxGroup.getHTML());
|
||
* checkboxGroup.defineEvents();
|
||
*
|
||
*
|
||
* @cfg {Array} items Defines the data items as an array objects.
|
||
*
|
||
* items: [
|
||
* {
|
||
* ...
|
||
* },
|
||
* {
|
||
* text: "Item1",
|
||
* selected: true
|
||
* },
|
||
* {
|
||
* ...
|
||
* }
|
||
* ]
|
||
*
|
||
* @cfg {Boolean} [multipleSelection=false] Defines wether the component will support the behavior of the check group.
|
||
* @cfg {String} [orientation="horizontal"] Defines the orientation of the component, it means if the orientation is vertical or
|
||
* horizontal
|
||
*
|
||
*
|
||
*/
|
||
var OptionsSelectorField = function (settings) {
|
||
OptionsSelectorField.superclass.call(this, settings);
|
||
/**
|
||
* @property {Boolean} [disabled=false] If the field is disabled or not.
|
||
* @readonly
|
||
*/
|
||
|
||
this.listWidth = null;
|
||
/**
|
||
* @property {String} controlPositioning The direction for the options to be added in the field.
|
||
* @readonly
|
||
*/
|
||
this.controlPositioning = null;
|
||
/**
|
||
* @property {String} [separator=","]
|
||
* Defines the separator between every item selected on the field
|
||
*/
|
||
this.separator = null;
|
||
OptionsSelectorField.prototype.init.call(this, settings);
|
||
|
||
};
|
||
|
||
PMUI.inheritFrom("PMUI.form.Field", OptionsSelectorField);
|
||
|
||
OptionsSelectorField.prototype.type = "OptionsSelectorField";
|
||
|
||
OptionsSelectorField.prototype.init = function (settings) {
|
||
var defaults = {
|
||
options: [],
|
||
listWidth: 'auto',
|
||
separator: ",",
|
||
controlPositioning: "vertical"
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setConfigControl(defaults);
|
||
this.setSeparator(defaults.separator);
|
||
this.setListWidth(defaults.listWidth);
|
||
this.setControlPositioning(defaults.controlPositioning);
|
||
};
|
||
|
||
/**
|
||
* Set if the HTML element is visible or not.
|
||
* @param {Boolean} visible
|
||
* @chainable
|
||
*/
|
||
OptionsSelectorField.prototype.setVisible = function (visible) {
|
||
var j,
|
||
k;
|
||
|
||
visible = !!visible;
|
||
this.visible = visible;
|
||
|
||
if (this.controls) {
|
||
for (j = 0; j < this.controls.length; j += 1) {
|
||
this.controls[j].visible = visible;
|
||
}
|
||
}
|
||
|
||
if (this.html) {
|
||
this.style.addProperties({"display": this.visible ? this.display : "none"});
|
||
if (this.controls) {
|
||
for (k = 0; k < this.controls.length; k += 1) {
|
||
this.controls[k].style.addProperties({"display": this.visible ? this.display : "none"});
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the separator for the item when use the {@link PMUI.field.OptionsSelectorField#setValue setvalue} method
|
||
* or the {@link PMUI.field.OptionsSelectorField#getValue getvalue} method
|
||
* @param {String} type
|
||
* It is a string that represent the separator. For example: '#', '|', ',', ...
|
||
*
|
||
*/
|
||
OptionsSelectorField.prototype.setSeparator = function (type) {
|
||
if (typeof type === "string") {
|
||
this.separator = type;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the options/option groups for the control.
|
||
* @param {Array} options An array with the same structure that the
|
||
* {@link PMUI.field.OptionsSelectorField#cfg-options "options"} property in the
|
||
* Config settings section.
|
||
*/
|
||
OptionsSelectorField.prototype.setOptions = function (options) {
|
||
var i = 0,
|
||
c,
|
||
j,
|
||
that = this,
|
||
controls,
|
||
k;
|
||
|
||
if (jQuery.isArray(options)) {
|
||
for (j = 0; j < that.controls.length; j += 1) {
|
||
that.dom.controlContainer.removeChild(that.controls[j].html);
|
||
}
|
||
;
|
||
that.setConfigControl({
|
||
items: options
|
||
});
|
||
controls = this.controls.slice();
|
||
for (k = 0; k < controls.length; k += 1) {
|
||
if (controls[k] !== null) {
|
||
if (that.dom.controlContainer) {
|
||
that.dom.controlContainer.appendChild(controls[k].getHTML());
|
||
controls[k].defineEvents();
|
||
controls[k] = null;
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
throw new Error("setOptions(): the supplied argument must be an array.");
|
||
}
|
||
|
||
return this;
|
||
};
|
||
OptionsSelectorField.prototype.setConfigControl = function (options) {
|
||
var newControl;
|
||
newControl = new PMUI.control.OptionsSelectorControl(options);
|
||
newControl.setField(this);
|
||
this.controls = [];
|
||
this.controls.push(newControl);
|
||
return this;
|
||
};
|
||
OptionsSelectorField.prototype.setControlPositioning = function (positioning) {
|
||
var that = this,
|
||
k;
|
||
if (typeof positioning === 'string') {
|
||
this.controlPositioning = positioning;
|
||
controls = this.controls.slice();
|
||
for (k = 0; k < controls.length; k += 1) {
|
||
if (controls[k] !== null) {
|
||
if (that.dom.controlContainer) {
|
||
that.dom.controlContainer.appendChild(controls[k].getHTML());
|
||
controls[k] = null;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
OptionsSelectorField.prototype.setOnChangeHandler = function () {
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the value for the field
|
||
* If the parameter is simple string like to
|
||
*
|
||
* "myoption" || "1"
|
||
*
|
||
* the value will be assigned to all the items.
|
||
*
|
||
* Otherwise the parameter must have the follow structure
|
||
*
|
||
* "1,2,3" || "first,second,third, ...]"
|
||
*
|
||
* @param {String} value
|
||
*/
|
||
OptionsSelectorField.prototype.setValue = function (value) {
|
||
value = value.toString();
|
||
if (typeof value === 'string') {
|
||
controls = this.controls[0];
|
||
|
||
this.value = value;
|
||
this.data.setValue(value);
|
||
this.setValueToControls(value);
|
||
} else {
|
||
throw new Error("The setValue() method only accepts string values!");
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Gets the value for the item
|
||
* @return {[type]} [description]
|
||
*/
|
||
OptionsSelectorField.prototype.getValue = function () {
|
||
var controls,
|
||
values,
|
||
i;
|
||
|
||
controls = this.controls[0];
|
||
items = this.getItemsSelected();
|
||
if (controls.multipleSelection) {
|
||
values = [];
|
||
for (i = 0; i < items.length; i += 1) {
|
||
values.push(items[i].getValue());
|
||
}
|
||
values.sort();
|
||
values = values.join(this.separator);
|
||
} else {
|
||
values = items[0].getValue();
|
||
}
|
||
this.value = values
|
||
return this.value;
|
||
};
|
||
/**
|
||
* Adds a new item to current options of the OptionsSelector field
|
||
* @param {Boolean} option This is a basic {@link PMUI.control.OptionsSelectorItemControl element} for the field.
|
||
*/
|
||
OptionsSelectorField.prototype.addOption = function (option) {
|
||
var newOption,
|
||
control;
|
||
|
||
control = this.controls[0];
|
||
if (control.html) {
|
||
control.addItem(jQuery.extend(true, option, {name: this.controls.length + 1}));
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Gets the options or items of the field
|
||
* @return {Array} options Items of the field
|
||
*/
|
||
OptionsSelectorField.prototype.getOptions = function (includeGroups) {
|
||
return this.controls[0].getOptions(includeGroups);
|
||
};
|
||
/**
|
||
* Clear all the options from the control.
|
||
* @chainable
|
||
*/
|
||
OptionsSelectorField.prototype.clearOptions = function () {
|
||
this.controls[0].clearOptions();
|
||
return this;
|
||
};
|
||
/**
|
||
* [disableOption description]
|
||
* @param {[type]} position [description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
OptionsSelectorField.prototype.disableOption = function (position) {
|
||
this.controls[0].disableOption(position, true);
|
||
return this;
|
||
};
|
||
/**
|
||
* [enableOption description]
|
||
* @param {[type]} position [description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
OptionsSelectorField.prototype.enableOption = function (position) {
|
||
this.controls[0].disableOption(position, false);
|
||
return this;
|
||
};
|
||
/**
|
||
* Removes an option of the field
|
||
* @param {Number} position Represent the index of the options array
|
||
*
|
||
* For example if the options array is:
|
||
*
|
||
* options = [a, b, c, d]
|
||
*
|
||
* And the option 'b' has to be removed, the method will be:
|
||
*
|
||
* obj.removeOption(2);
|
||
*
|
||
* @return {Object} this
|
||
*/
|
||
OptionsSelectorField.prototype.removeOption = function (position) {
|
||
this.controls[0].removeOption(position);
|
||
return this;
|
||
};
|
||
OptionsSelectorField.prototype.getSelectedLabel = function () {
|
||
this.controls[0].getSelectedLabel();
|
||
return this;
|
||
};
|
||
/**
|
||
* Disables the field, the label and the control of the field are disabled
|
||
* @return {Object} this
|
||
*/
|
||
OptionsSelectorField.prototype.disable = function () {
|
||
var items,
|
||
i;
|
||
this.disabled = true;
|
||
OptionsSelectorField.superclass.prototype.disable.call(this);
|
||
if (jQuery.isArray(this.controls)) {
|
||
if (this.controls[0]) {
|
||
control = this.controls[0];
|
||
for (i = 0; i < control.items.getSize(); i += 1) {
|
||
control.disableOption(i, true);
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* This method enable the field if the label and the control of the item are disabled.
|
||
* @return {Object} this
|
||
*/
|
||
OptionsSelectorField.prototype.enable = function () {
|
||
var control,
|
||
i;
|
||
this.disabled = false;
|
||
OptionsSelectorField.superclass.prototype.enable.call(this);
|
||
if (jQuery.isArray(this.controls)) {
|
||
if (this.controls[0]) {
|
||
control = this.controls[0];
|
||
for (i = 0; i < control.items.getSize(); i += 1) {
|
||
control.disableOption(i, false);
|
||
}
|
||
}
|
||
|
||
}
|
||
return this;
|
||
};
|
||
|
||
OptionsSelectorField.prototype.setListWidth = function (width) {
|
||
var items,
|
||
i;
|
||
|
||
if (typeof this.width === "number") {
|
||
this.listWidth = width;
|
||
if (jQuery.isArray(this.controls)) {
|
||
items = this.controls;
|
||
for (i = 0; i < items.length; i += 1) {
|
||
items[i].setWidth(this.listWidth);
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
OptionsSelectorField.prototype.getListWidth = function (width) {
|
||
return this.listWidth;
|
||
};
|
||
/**
|
||
* Gets all items selected on the OptionsSelector
|
||
* @return {Array} items Represent all the items selected on the Field
|
||
*/
|
||
OptionsSelectorField.prototype.getItemsSelected = function () {
|
||
var items,
|
||
i,
|
||
selected = [];
|
||
|
||
if (jQuery.isArray(this.controls)) {
|
||
items = this.controls;
|
||
for (i = 0; i < items.length; i += 1) {
|
||
selected = jQuery.merge(selected, items[i].getItemsSelected());
|
||
}
|
||
}
|
||
return selected;
|
||
};
|
||
/**
|
||
* Sets the orientation for every {@link PMUI.control.OptionsSelectorItemControl element}
|
||
* There are two possibilities:
|
||
*
|
||
* - horizontal, the elements will be aligned horizontally
|
||
* - vertical, the elements will be aligned vertically
|
||
*
|
||
* @param {String} orientation
|
||
* @return {Object} this
|
||
*/
|
||
OptionsSelectorField.prototype.setOrientation = function (orientation) {
|
||
var items,
|
||
i;
|
||
|
||
if (typeof orientation === "string" && jQuery.isArray(this.controls) === true) {
|
||
items = this.controls;
|
||
for (i = 0; i < items.length; i += 1) {
|
||
items[i].setOrientation(orientation);
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
OptionsSelectorField.prototype.setLabel = function (label) {
|
||
|
||
if (typeof label === 'string') {
|
||
this.label = label;
|
||
} else {
|
||
throw new Error("The setLabel() method only accepts string values!");
|
||
}
|
||
if (this.dom.labelTextContainer) {
|
||
if (label === '[field]' || label === '') {
|
||
this.label = '';
|
||
this.dom.labelTextContainer.textContent = this.label;
|
||
|
||
} else {
|
||
this.dom.labelTextContainer.textContent = this.label + (this.colonVisible ? ':' : '');
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.field.OptionsSelectorField', OptionsSelectorField);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = OptionsSelectorField;
|
||
}
|
||
|
||
}());
|
||
(function () {
|
||
var UploadControl = function (settings) {
|
||
UploadControl.superclass.call(this, settings);
|
||
this.accept = null;
|
||
this.multiple = null;
|
||
this.files = null;
|
||
UploadControl.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.control.HTMLControl', UploadControl);
|
||
|
||
UploadControl.prototype.type = 'UploadControl';
|
||
UploadControl.prototype.family = 'control';
|
||
|
||
UploadControl.prototype.init = function (settings) {
|
||
var defaults;
|
||
defaults = {
|
||
accept: "",
|
||
multiple: false,
|
||
height: '100%'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setAcceptedFiles(defaults.accept)
|
||
.setMultiple(defaults.multiple)
|
||
.setHeight(defaults.height);
|
||
};
|
||
|
||
/**
|
||
* @method setAccepted
|
||
* here we can define the type files our send, the valid types are MIME, separation with ","
|
||
* for more information go to http://reference.sitepoint.com/html/mime-types-full
|
||
* @param {String} accept MIME types are valid for our upload
|
||
*/
|
||
UploadControl.prototype.setAcceptedFiles = function (accept) {
|
||
if (!(typeof accept === "string")) {
|
||
throw new Error('setAcceptedFiles(): The parameter type is invalid, should be type string');
|
||
}
|
||
this.accept = '';
|
||
this.accept = accept;
|
||
if (this.html) {
|
||
this.html.accept = accept;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
UploadControl.prototype.defineEvents = function () {
|
||
var that = this;
|
||
UploadControl.superclass.prototype.defineEvents.call(this);
|
||
this.html.addEventListener("click", function (e) {
|
||
e.stopPropagation();
|
||
});
|
||
return this;
|
||
};
|
||
|
||
UploadControl.prototype.setMultiple = function (value) {
|
||
if (!(typeof value === 'boolean')) {
|
||
throw new Error('setMultiple(): The parameter type is invalid, should be type string');
|
||
}
|
||
this.multiple = value;
|
||
if (this.html) {
|
||
this.html.multiple = value;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
UploadControl.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
UploadControl.superclass.prototype.createHTML.call(this);
|
||
this.html.type = 'file';
|
||
this.setMultiple(this.multiple);
|
||
this.setAcceptedFiles(this.accept);
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.control.UploadControl', UploadControl);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = UploadControl;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.control.ButtonControl
|
||
* @extends PMUI.control.Control
|
||
*
|
||
* this button is a control, the config options is not equal to button of UI
|
||
* the use of this control is for a field
|
||
*/
|
||
var ButtonControl = function (settings) {
|
||
ButtonControl.superclass.call(this, settings);
|
||
/**
|
||
* this a PMUI.ui.Button object
|
||
* @type {PMUI.ui.Button}
|
||
*/
|
||
this.button = null;
|
||
ButtonControl.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.control.Control', ButtonControl);
|
||
|
||
ButtonControl.prototype.type = "ButtonControl";
|
||
|
||
ButtonControl.prototype.init = function (settings) {
|
||
var defaults = {
|
||
handler: null
|
||
};
|
||
jQuery.extend(true, defaults, settings);
|
||
this.button = new PMUI.ui.Button();
|
||
this.setHandler(defaults.handler);
|
||
};
|
||
/**
|
||
* diabled the buttonControl
|
||
* @param {Boolean} value if true disable button, default value false
|
||
* @chainable
|
||
*/
|
||
ButtonControl.prototype.setDisabled = function (value) {
|
||
if (this.button) {
|
||
this.button.setDisabled(value);
|
||
}
|
||
|
||
return this;
|
||
}
|
||
/**
|
||
* disable Button
|
||
* @chainable
|
||
*/
|
||
ButtonControl.prototype.disable = function () {
|
||
if (this.button) {
|
||
this.button.disable();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* ebable button
|
||
* @chainable
|
||
*/
|
||
ButtonControl.prototype.enable = function () {
|
||
this.button.enable();
|
||
return this;
|
||
};
|
||
/**
|
||
* set bordet for Button
|
||
* @chainable
|
||
*/
|
||
ButtonControl.prototype.setBorder = function (border) {
|
||
this.button.setBorder(border);
|
||
return this;
|
||
};
|
||
/**
|
||
* this click is established with jQuery, simulate the behavior click
|
||
* @chainable
|
||
*/
|
||
ButtonControl.prototype.click = function () {
|
||
this.button.click();
|
||
return this;
|
||
};
|
||
/**
|
||
* set handler for button
|
||
* @param {Function} handle the event to trigger
|
||
* @chainable
|
||
*/
|
||
ButtonControl.prototype.setHandler = function (handler) {
|
||
this.button.setHandler(handler);
|
||
return this;
|
||
};
|
||
/**
|
||
* remove one event of the events
|
||
* @param {String} type It is an event that is stored in an object event
|
||
* @chainable
|
||
*/
|
||
ButtonControl.prototype.removeEvent = function (type) {
|
||
this.button.removeEvent(type);
|
||
return this;
|
||
};
|
||
/**
|
||
* removes all events
|
||
* @return {[type]}
|
||
*/
|
||
ButtonControl.prototype.removeEvents = function () {
|
||
this.button.removeEvents();
|
||
return this;
|
||
};
|
||
/**
|
||
* fix the text for the button
|
||
* @param {String} text
|
||
*/
|
||
ButtonControl.prototype.setText = function (text) {
|
||
this.button.setText(text);
|
||
return this;
|
||
};
|
||
ButtonControl.prototype.setIcon = function (iconClass) {
|
||
this.button.setIcon(iconClass);
|
||
return this;
|
||
};
|
||
ButtonControl.prototype.setAliasButton = function (alias) {
|
||
this.button.setAliasButton(alias);
|
||
return this;
|
||
};
|
||
ButtonControl.prototype.setParent = function (parent) {
|
||
this.button.setParent(parent);
|
||
return this;
|
||
};
|
||
ButtonControl.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
this.html = this.button.getHTML();
|
||
|
||
return this.html;
|
||
};
|
||
ButtonControl.prototype.defineEvents = function () {
|
||
this.button.defineEvents();
|
||
return this;
|
||
};
|
||
ButtonControl.prototype.setHeight = function (height) {
|
||
if (this.button) {
|
||
this.button.setHeight(height);
|
||
}
|
||
return this;
|
||
};
|
||
ButtonControl.prototype.setIconPosition = function (position) {
|
||
this.setIconPosition(position);
|
||
return this;
|
||
};
|
||
/**
|
||
* fix a message for button
|
||
* @param {String} messageTooltip
|
||
*/
|
||
ButtonControl.prototype.setTooltipMessage = function (messageTooltip) {
|
||
this.button.setTooltipMessage(messageTooltip);
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.control.ButtonControl', ButtonControl);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ButtonControl;
|
||
}
|
||
}());
|
||
(function () {
|
||
|
||
var NumberControl = function (settings) {
|
||
NumberControl.superclass.call(this, settings);
|
||
/**
|
||
* @event onKeyUp
|
||
* Fired when a pressed key is released.
|
||
* @param {Object} event The event object.
|
||
*/
|
||
this.onKeyUp = null;
|
||
this.mask = null;
|
||
this.percentage = null;
|
||
this.filterKey = null;
|
||
this.maskList = [];
|
||
this.expRegList = [];
|
||
this.expRegMask = [];
|
||
this.optionDecimal = null;
|
||
this.decimals = null;
|
||
this.valueInit = null;
|
||
this.onlyNumber = null;
|
||
|
||
this.onHandlerMaskKeyDown = null;
|
||
this.onHandlerMaskKeyPress = null;
|
||
NumberControl.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.control.TextControl', NumberControl);
|
||
|
||
NumberControl.prototype.type = "TextControl";
|
||
/**
|
||
* Initializes the object.
|
||
* @param {Object} [settings=null] A JSON object with the config options.
|
||
* @private
|
||
*/
|
||
NumberControl.prototype.init = function (settings) {
|
||
var defaults = {
|
||
placeholder: "",
|
||
maxLength: 524288,
|
||
onKeyUp: null,
|
||
optionDecimal: null,
|
||
valueInit: "",
|
||
mask: "###,###,###,###.###########"
|
||
};
|
||
|
||
$.extend(true, defaults, settings);
|
||
this.setMaskDefault();
|
||
this.setPlaceholder(defaults.placeholder)
|
||
.setMaxLength(defaults.maxLength)
|
||
.setOnKeyUpHandler(defaults.onKeyUp)
|
||
.setOptionDecimal(defaults.optionDecimal)
|
||
.setMask(defaults.mask);
|
||
|
||
this.mask = defaults.mask;
|
||
|
||
};
|
||
|
||
/**
|
||
* Sets the callback function to be called when the keyup event occurs.
|
||
* @chainable
|
||
*/
|
||
|
||
NumberControl.prototype.evalMask = function (textvalue) {
|
||
var i;
|
||
|
||
for (i = 0; i < this.expRegList.length; i += 1) {
|
||
if (this.expRegList[i].test(textvalue))
|
||
return true;
|
||
}
|
||
return false;
|
||
};
|
||
|
||
NumberControl.prototype.setOptionDecimal = function (option) {
|
||
if (typeof option === "string")
|
||
this.optionDecimal = option;
|
||
return this;
|
||
};
|
||
|
||
|
||
NumberControl.prototype.evalMaskNumeric = function (textvalue) {
|
||
var sw = true,
|
||
i;
|
||
|
||
if (this.expRegMask === undefined) {
|
||
return true;
|
||
}
|
||
else {
|
||
for (i = 0; i < this.expRegMask.length; i += 1) {
|
||
if (this.expRegMask[i][2] != null) {
|
||
if (!this.expRegMask[i][2].test(textvalue))
|
||
sw = false;
|
||
}
|
||
|
||
}
|
||
return sw;
|
||
}
|
||
};
|
||
|
||
NumberControl.prototype.truncate = function (number, digits) {
|
||
var multiplier = Math.pow(10, digits),
|
||
adjustedNum = number * multiplier,
|
||
truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum);
|
||
return truncatedNum / multiplier;
|
||
};
|
||
|
||
|
||
NumberControl.prototype.setValue = function (strControl) {
|
||
var strAux;
|
||
this.valueInit = strControl;
|
||
if (this.isNumber(strControl)) {
|
||
if (strControl != null && strControl != "") {
|
||
if (this.evalMaskNumeric(strControl) || strControl == "") {
|
||
NumberControl.superclass.prototype.setValue.call(this, strControl);
|
||
//this.setValue(strControl);
|
||
}
|
||
else {
|
||
if (this.optionDecimal == "truncate") {
|
||
|
||
}
|
||
|
||
strControl = this.removeNumberCommas(strControl);
|
||
|
||
if (this.optionDecimal == "truncate")
|
||
strAux = this.truncate(parseFloat(strControl), this.decimals);
|
||
if (this.optionDecimal == "round")
|
||
strAux = Math.ceil(strControl * ('1e' + this.decimals)) / ('1e' + this.decimals);
|
||
|
||
|
||
strAux = this.setNumberCommas(strAux == undefined ? "" : strAux.toString());
|
||
if (this.evalMaskNumeric(strAux)) {
|
||
NumberControl.superclass.prototype.setValue.call(this, strAux);
|
||
// this.setValue(strAux);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
|
||
};
|
||
|
||
NumberControl.prototype.getValue = function (control) {
|
||
var value,
|
||
array,
|
||
result,
|
||
i;
|
||
|
||
if (this.valueInit != null) {
|
||
if (control)
|
||
return this.removeNumberCommas(this.valueInit);
|
||
else {
|
||
if (this.html)
|
||
return this.html.value;
|
||
else
|
||
return "";
|
||
}
|
||
}
|
||
if (control) {
|
||
value = this.getValue();
|
||
array = value.split(",");
|
||
result = "";
|
||
for (i = 0; i < array.length; i += 1) {
|
||
result = result + array[i];
|
||
}
|
||
return result;
|
||
}
|
||
|
||
return NumberControl.superclass.prototype.getValue.call(this);
|
||
};
|
||
|
||
NumberControl.prototype.isNumber = function (strControl) {
|
||
var validator = /^[\d\,\.]*$/;
|
||
if (validator.test(strControl))
|
||
return true;
|
||
else
|
||
return false;
|
||
};
|
||
|
||
NumberControl.prototype.removeNumberCommas = function (strControl) {
|
||
var pint = this.getParseInt(strControl),
|
||
pdec = this.getParseDec(strControl);
|
||
if (pdec != undefined)
|
||
strControl = pint + "." + pdec;
|
||
else
|
||
strControl = pint;
|
||
return strControl;
|
||
};
|
||
|
||
NumberControl.prototype.setNumberCommas = function (strControl) {
|
||
var pint = this.getParseInt(strControl),
|
||
pdec = this.getParseDec(strControl),
|
||
array,
|
||
arraypos,
|
||
a1,
|
||
a2,
|
||
strFinal = "",
|
||
i;
|
||
array = pint.split(",");
|
||
for (i = 0; i <= array.length - 1; i += 1) {
|
||
strFinal += array[i];
|
||
}
|
||
arraypos = strFinal.length;
|
||
while (arraypos > 3) {
|
||
a1 = strFinal.substr(0, arraypos - 3);
|
||
a2 = strFinal.substr(arraypos - 3, strFinal.length);
|
||
strFinal = a1 + "," + a2;
|
||
arraypos++;
|
||
arraypos = arraypos - 4;
|
||
}
|
||
if (pdec != undefined)
|
||
return strFinal + "." + pdec;
|
||
else
|
||
return strFinal;
|
||
};
|
||
|
||
NumberControl.prototype.setMaskDefault = function () {
|
||
this.expRegMask.push([/^\#{0,3}(\,\#{3})*\%{0,1}$/, '^\\d{0,3}(\\,\\d{3}){@n}\%{0,1}$', null, false]); // captura de numeros sin decimal con comas
|
||
this.expRegMask.push([/^[\#\,0]+(?:(\.)([\#0]*)){1}(\%){0,1}$/, '^[\\d\\,]+(\\.){0,1}(\\d{@n}){0,1}(\%){0,1}$', null, false]); // decimales
|
||
this.expRegMask.push([/^[\#0]{0,3}(\,[\#0]{3})*(?:(\.)([\#0]*))(\%){0,1}$/, '^\\d{@x}(\\,\\d{3}){@n}((\\.)(\\d*)){0,1}(\%){0,1}$', null, false]); // parte entera
|
||
this.expRegMask.push([/^[\#\,]*(0*)\.(0*)(\%){0,1}$/, '^[\\d\\,]*(0{@x})\\.([\\d]{@y})(\%){0,1}$', null, false]); // zeros fijos
|
||
this.expRegMask.push([/^[\#\,\.]*\%{1}$/, '^[\\d\\,\\.]*\\%{1}$', null, false]); // percentage
|
||
this.expRegMask.push([/^\#*\%{0,1}$/, '^\\d{@n}\%{0,1}$', null, false]); // captura de numeros sin decimal con comas
|
||
|
||
};
|
||
|
||
NumberControl.prototype.setMaskNumeric = function (mask) {
|
||
var array,
|
||
ngroups,
|
||
ini,
|
||
nreg,
|
||
nx,
|
||
ny,
|
||
a;
|
||
|
||
if (this.expRegMask[0][0].test(mask)) {
|
||
array = this.expRegMask[0][0].exec(mask);
|
||
ngroups = array[0].split(",").length - 1;
|
||
this.expRegMask[0][2] = new RegExp(this.expRegMask[0][1].replace(/@n/g, '0,' + ngroups.toString()));
|
||
this.expRegMask[0][3] = true;
|
||
}
|
||
if (this.expRegMask[1][0].test(mask)) {
|
||
array = this.expRegMask[1][0].exec(mask);
|
||
ngroups = array[2].length;
|
||
this.decimals = ngroups;
|
||
this.expRegMask[1][2] = new RegExp(this.expRegMask[1][1].replace(/@n/g, '0,' + ngroups.toString()));
|
||
this.expRegMask[1][3] = true;
|
||
}
|
||
if (this.expRegMask[2][0].test(mask)) {
|
||
array = this.expRegMask[2][0].exec(mask);
|
||
ngroups = array[0].split(",").length - 1;
|
||
ini = this.expRegMask[2][0].exec("##,###.##")[0].split(",")[0].length
|
||
nreg = this.expRegMask[2][1].replace(/@n/g, '0,' + ngroups.toString());
|
||
this.expRegMask[2][2] = new RegExp(nreg.replace(/@x/g, '0,3'));
|
||
this.expRegMask[2][3] = true;
|
||
}
|
||
if (this.expRegMask[3][0].test(mask)) {
|
||
array = this.expRegMask[3][0].exec(mask);
|
||
nx = array[1].length;
|
||
ny = array[2].length;
|
||
a = this.expRegMask[3][1].replace(/@x/g, '0,' + nx.toString());
|
||
a = a.replace(/@y/g, '0,' + ny.toString());
|
||
this.expRegMask[3][2] = new RegExp(a);
|
||
this.expRegMask[3][3] = true;
|
||
}
|
||
//percentage
|
||
if (this.expRegMask[4][0].test(mask)) {
|
||
this.expRegMask[4][2] = new RegExp(this.expRegMask[4][1]);
|
||
this.expRegMask[4][3] = true;
|
||
this.percentage = true;
|
||
}
|
||
//number not comas
|
||
if (this.expRegMask[5][0].test(mask)) {
|
||
array = this.expRegMask[5][0].exec(mask);
|
||
nx;
|
||
if (this.percentage)
|
||
nx = array[0].length - 1;
|
||
else
|
||
nx = array[0].length;
|
||
|
||
|
||
this.expRegMask[5][2] = new RegExp(this.expRegMask[5][1].replace(/@n/g, '0,' + nx.toString()));
|
||
this.expRegMask[5][3] = true;
|
||
this.onlyNumber = true;
|
||
}
|
||
|
||
|
||
};
|
||
|
||
NumberControl.prototype.setMaskHandlerNumeric = function (mask) {
|
||
//handler numeric
|
||
var that = this,
|
||
thatMask = mask;
|
||
handlerKeyDown = function (e) {
|
||
var pressKey,
|
||
textValue,
|
||
regResult,
|
||
selStart,
|
||
selEnd,
|
||
strStart,
|
||
strEnd,
|
||
strControl = "",
|
||
textLength,
|
||
strFinal,
|
||
pressKey = (window.event) ? window.event.keyCode : e.which,
|
||
onlynumbers,
|
||
dash,
|
||
flagequal,
|
||
flagZeros,
|
||
pint,
|
||
pdec;
|
||
|
||
textValue = that.html.value;
|
||
selStart = that.html.selectionStart;
|
||
selEnd = that.html.selectionEnd;
|
||
textLength = that.html.value.length;
|
||
onlynumbers = that.expRegMask[0][3];
|
||
dash = that.expRegMask[1][3];
|
||
flagequal = false;
|
||
flagZeros = that.expRegMask[3][3];
|
||
if (selStart == selEnd) {
|
||
flagequal = true;
|
||
}
|
||
|
||
if ((pressKey > 46 && pressKey <= 57) || (pressKey >= 96 && pressKey <= 105) || pressKey == 8 || pressKey == 190 || pressKey == 37 || pressKey == 39) {
|
||
this.valueInit = null;
|
||
//quitar porcentaje
|
||
if (this.percentage)
|
||
textValue = textValue.substr(0, textLength - 1);
|
||
|
||
|
||
if (pressKey >= 96 && pressKey <= 105)
|
||
pressKey = pressKey - 48;
|
||
if (pressKey > 45 && pressKey <= 57) {
|
||
if (selStart == textLength) {
|
||
strControl += textValue + String.fromCharCode(pressKey);
|
||
selStart = selStart + 1;
|
||
}
|
||
else {
|
||
strStart = textValue.substr(0, selStart);
|
||
strEnd = textValue.substr(selStart, textLength);
|
||
strControl = strStart + String.fromCharCode(pressKey) + strEnd;
|
||
selStart++;
|
||
}
|
||
}
|
||
if (pressKey == 8) {
|
||
if (flagequal && selStart == textLength) {
|
||
strControl = textValue.substr(0, selStart - 1);
|
||
}
|
||
else {
|
||
strStart = textValue.substr(0, selStart - 1);
|
||
strEnd = textValue.substr(selStart, textLength);
|
||
strControl = strStart + strEnd;
|
||
selStart--;
|
||
}
|
||
}
|
||
if (onlynumbers && pressKey == 190) {
|
||
strControl = textValue;
|
||
}
|
||
if (pressKey == 37) {
|
||
selStart = selStart - 1;
|
||
strControl = textValue;
|
||
|
||
}
|
||
if (pressKey == 39) {
|
||
if (selStart == selEnd) {
|
||
selEnd++;
|
||
}
|
||
selStart = selStart + 1;
|
||
strControl = textValue;
|
||
}
|
||
if (flagZeros) {
|
||
strControl = that.setZeros(strControl, thatMask);
|
||
}
|
||
|
||
//convierto con comas
|
||
if (this.onlyNumber) {
|
||
if (pressKey == 190) {
|
||
strFinal = textValue;
|
||
}
|
||
if (pressKey != 190) {
|
||
strFinal = strControl;
|
||
}
|
||
}
|
||
else {
|
||
pint = that.getParseInt(strControl);
|
||
pdec = that.getParseDec(strControl);
|
||
selStart = selStart - (strControl.split(",").length - 1);
|
||
strFinal = that.setComas(pint);
|
||
selStart = selStart + (strFinal.split(",").length - 1);
|
||
if (pdec != undefined) {
|
||
strFinal = strFinal + "." + pdec;
|
||
if (flagequal && selStart > selEnd)
|
||
selEnd = selStart;
|
||
else {
|
||
selEnd = selStart;
|
||
}
|
||
}
|
||
}
|
||
if (dash && pressKey == 190) {
|
||
strControl += textValue + ".";
|
||
strFinal = strControl;
|
||
selStart = selStart + 1;
|
||
}
|
||
}
|
||
else {
|
||
strFinal = this.html.value;
|
||
}
|
||
|
||
//agregar signo de porcentaje
|
||
if (this.percentage) {
|
||
strFinal += "%";
|
||
}
|
||
|
||
if (this.evalMaskNumeric(strFinal) || strFinal == "") {
|
||
that.html.value = strFinal;
|
||
that.html.selectionStart = selStart;
|
||
if (flagequal) {
|
||
that.html.selectionEnd = selStart;
|
||
}
|
||
}
|
||
e.preventDefault();
|
||
}
|
||
this.onHandlerMaskKeyDown = handlerKeyDown;
|
||
};
|
||
|
||
|
||
NumberControl.prototype.setComas = function (strControl) {
|
||
var array,
|
||
arraypos,
|
||
a1,
|
||
a2,
|
||
i,
|
||
strFinal = "";
|
||
|
||
array = strControl.split(",");
|
||
for (i = 0; i <= array.length - 1; i += 1) {
|
||
strFinal += array[i];
|
||
}
|
||
arraypos = strFinal.length;
|
||
while (arraypos > 3) {
|
||
a1 = strFinal.substr(0, arraypos - 3);
|
||
a2 = strFinal.substr(arraypos - 3, strFinal.length);
|
||
strFinal = a1 + "," + a2;
|
||
arraypos++;
|
||
arraypos = arraypos - 4;
|
||
}
|
||
return strFinal;
|
||
};
|
||
|
||
NumberControl.prototype.getParseInt = function (strControl) {
|
||
var aux1,
|
||
aux2,
|
||
array,
|
||
strFinal = "",
|
||
i;
|
||
|
||
aux1 = strControl.split(".")[0];
|
||
array = aux1.split(",");
|
||
for (i = 0; i <= array.length - 1; i += 1) {
|
||
strFinal += array[i];
|
||
}
|
||
return strFinal;
|
||
};
|
||
|
||
NumberControl.prototype.getParseDec = function (strControl) {
|
||
var aux1,
|
||
aux2,
|
||
array,
|
||
strFinal = "";
|
||
aux1 = strControl.split(".")[1];
|
||
return aux1;
|
||
}
|
||
|
||
NumberControl.prototype.setZeros = function (strControl, mask) {
|
||
var i,
|
||
aux1,
|
||
aux2,
|
||
array,
|
||
strFinal = "",
|
||
nZerosLeft,
|
||
nZerosRight,
|
||
nRightStr;
|
||
array = this.expRegMask[3][0].exec(mask);
|
||
nZerosLeft = array[1].length;
|
||
nZerosRight = array[2].length;
|
||
|
||
if (strControl.split(".").length != 1) {
|
||
nRightStr = strControl.split(".")[1].length;
|
||
if (nRightStr < nZerosRight) {
|
||
for (i = 0; i < nZerosRight - nRightStr; i += 1) {
|
||
strControl += "0";
|
||
}
|
||
return strControl;
|
||
}
|
||
if (nRightStr > nZerosRight) {
|
||
strControl = strControl.substr(0, strControl.length - 1);
|
||
}
|
||
return strControl;
|
||
}
|
||
else {
|
||
if (strControl == "")
|
||
return array[1] + "." + array[2];
|
||
else {
|
||
return strControl + "." + array[2];
|
||
}
|
||
}
|
||
return aux1;
|
||
}
|
||
|
||
NumberControl.prototype.setMask = function (mask) {
|
||
var expMaskPercentage = /^(\#+)(?:(\.)(\#*))?\%$/i,
|
||
expMaskNumber1 = /^(\#+)(?:(\.)(\#*))?$/i,
|
||
expMaskNumber2 = /^(\#{0,3})(?:(\,)(\#{3}))*(?:(\.)(\#*))?$/i;
|
||
this.onHandlerMaskKeyDown = null;
|
||
this.onHandlerMaskKeyPress = null;
|
||
this.maskList = [];
|
||
this.expRegMask[0][3] = false;
|
||
this.expRegMask[1][3] = false;
|
||
this.expRegMask[2][3] = false;
|
||
this.expRegMask[3][3] = false;
|
||
this.expRegMask[4][3] = false;
|
||
this.expRegMask[0][2] = null;
|
||
this.expRegMask[1][2] = null;
|
||
this.expRegMask[2][2] = null;
|
||
this.expRegMask[3][2] = null;
|
||
this.expRegMask[4][2] = null;
|
||
// Save the list of mask
|
||
if (typeof mask === "string") {
|
||
this.percentage = null;
|
||
this.onlyNumber = null;
|
||
this.maskList.push(mask);
|
||
this.setMaskNumeric(mask);
|
||
this.setMaskHandlerNumeric(mask);
|
||
}
|
||
};
|
||
/**
|
||
* Set the events for the object.
|
||
* @chainable
|
||
*/
|
||
NumberControl.prototype.defineEvents = function () {
|
||
var that = this;
|
||
|
||
if (this.html && !this.eventsDefined) {
|
||
NumberControl.superclass.prototype.defineEvents.call(this);
|
||
this.addEvent('keyup').listen(this.html, function (e) {
|
||
if (typeof that.onKeyUp === 'function') {
|
||
that.onKeyUp(e);
|
||
}
|
||
});
|
||
this.addEvent('keydown').listen(this.html, function (e) {
|
||
if (e.which === PMUI.keyCodeF5) {
|
||
this.blur();
|
||
e.preventDefault();
|
||
window.location.reload(true);
|
||
}
|
||
if (typeof that.onHandlerMaskKeyDown === 'function') {
|
||
that.onHandlerMaskKeyDown(e);
|
||
}
|
||
});
|
||
this.addEvent('keypress').listen(this.html, function (e) {
|
||
if (typeof that.onHandlerMaskKeyPress === 'function') {
|
||
that.onHandlerMaskKeyPress(e);
|
||
}
|
||
});
|
||
this.eventsDefined = true;
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* Creates the HTML element for the object
|
||
* @return {HTMLElement}
|
||
*/
|
||
NumberControl.prototype.createHTML = function () {
|
||
NumberControl.superclass.prototype.createHTML.call(this);
|
||
this.html.type = "text";
|
||
this.setPlaceholder(this.placeholder)
|
||
.setMaxLength(this.maxLength)
|
||
.setReadOnly(this.readonly);
|
||
|
||
//this.defineEvents();
|
||
this.setMask(this.maskList[0]);
|
||
|
||
return this.html;
|
||
};
|
||
/**
|
||
* Sets if the control will be enabled for read only.
|
||
* @param {Boolean}
|
||
* @chainable
|
||
*/
|
||
|
||
PMUI.extendNamespace('PMUI.control.NumberControl', NumberControl);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = NumberControl;
|
||
}
|
||
}());
|
||
(function () {
|
||
var NumberField = function (settings) {
|
||
NumberField.superclass.call(this, settings);
|
||
/**
|
||
* @property {Boolean} [trimOnBlur=true] If the field's value must be trimmed every time it loses focus.
|
||
*/
|
||
this.trimOnBlur = null;
|
||
|
||
NumberField.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.form.Field', NumberField);
|
||
|
||
NumberField.prototype.type = "NumberField";
|
||
|
||
NumberField.prototype.init = function (settings) {
|
||
var defaults = {
|
||
placeholder: "",
|
||
maxLength: 0,
|
||
trimOnBlur: true,
|
||
readOnly: false,
|
||
mask: "",
|
||
value: "",
|
||
optionDecimal: null
|
||
};
|
||
|
||
$.extend(true, defaults, settings);
|
||
|
||
this.setPlaceholder(defaults.placeholder)
|
||
.setMaxLength(defaults.maxLength)
|
||
.setTrimOnBlur(defaults.trimOnBlur)
|
||
.setReadOnly(defaults.readOnly)
|
||
.setOptionDecimal(defaults.optionDecimal)
|
||
.setMask(defaults.mask);
|
||
|
||
};
|
||
/**
|
||
* Sets the value for the field.
|
||
* @param {String} value
|
||
* @chainable
|
||
*/
|
||
NumberField.prototype.setValue = function (value) {
|
||
if (this.trimOnBlur) {
|
||
value = jQuery.trim(value);
|
||
}
|
||
NumberField.superclass.prototype.setValue.call(this, value);
|
||
//this.controls[0].setValue(value);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the value for the field.
|
||
* @param {String} value
|
||
* @chainable
|
||
*/
|
||
NumberField.prototype.setOptionDecimal = function (value) {
|
||
if (this.trimOnBlur) {
|
||
value = jQuery.trim(value);
|
||
}
|
||
this.controls[0].setOptionDecimal(value);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the value for the field.
|
||
* @param {String} value
|
||
* @chainable
|
||
*/
|
||
NumberField.prototype.setMask = function (value) {
|
||
if (this.trimOnBlur) {
|
||
value = jQuery.trim(value);
|
||
}
|
||
this.controls[0].setMask(value);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the placeholder for the control. Note that this feature is only supported
|
||
* by browsers which support the "placeholder" for input elements.
|
||
* @param {String} placeholder
|
||
* @chainable
|
||
*/
|
||
NumberField.prototype.setReadOnly = function (readonly) {
|
||
this.controls[0].setReadOnly(readonly);
|
||
return this;
|
||
};
|
||
/**
|
||
* [setPlaceholder description]
|
||
* @param {[type]} placeholder [description]
|
||
*/
|
||
NumberField.prototype.setPlaceholder = function (placeholder) {
|
||
this.controls[0].setPlaceholder(placeholder);
|
||
return this;
|
||
};
|
||
/**
|
||
* [getPlaceholder description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
NumberField.prototype.getPlaceholder = function () {
|
||
return this.controls[0].getPlaceholder();
|
||
};
|
||
/**
|
||
* [setMaxLength description]
|
||
* @param {[type]} maxLength [description]
|
||
*/
|
||
NumberField.prototype.setMaxLength = function (maxLength) {
|
||
this.controls[0].setMaxLength(maxLength);
|
||
return this;
|
||
};
|
||
/**
|
||
* [getMaxLength description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
NumberField.prototype.getMaxLength = function () {
|
||
return this.controls[0].getMaxLength();
|
||
};
|
||
/**
|
||
* [isReadOnly description]
|
||
* @return {Boolean} [description]
|
||
*/
|
||
NumberField.prototype.isReadOnly = function () {
|
||
return this.controls[0].isReadOnly();
|
||
};
|
||
/**
|
||
* Switches on/off the value trimming for the field's value when it loses focus.
|
||
* @param {Boolean} trimOnBlur Send true for switch on or false to switch off.
|
||
* @chainable
|
||
*/
|
||
NumberField.prototype.setTrimOnBlur = function (trimOnBlur) {
|
||
this.trimOnBlur = !!trimOnBlur;
|
||
return this;
|
||
};
|
||
/**
|
||
* Returns a boolean value that indicates if the trimming function is enabled/disabled
|
||
* @return {Boolean}
|
||
*/
|
||
NumberField.prototype.getTrimOnBlur = function () {
|
||
return this.trimOnBlur;
|
||
};
|
||
/**
|
||
* Sets the control for the NumberField
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
NumberField.prototype.setControls = function () {
|
||
if (this.controls.length) {
|
||
return this;
|
||
}
|
||
this.controls.push(new PMUI.control.NumberControl());
|
||
|
||
return this;
|
||
};
|
||
/**
|
||
* Sets the control for the NumberField
|
||
* @chainable
|
||
* @private
|
||
*/
|
||
NumberField.prototype.getValue = function (control) {
|
||
|
||
return this.controls[0].getValue(control);
|
||
};
|
||
/**
|
||
* Establish the handler function for the internal onChange event
|
||
* @return {Function}
|
||
* @private
|
||
*/
|
||
NumberField.prototype.onChangeHandler = function () {
|
||
var that = this;
|
||
|
||
return function () {
|
||
var previousValue = that.value,
|
||
value,
|
||
i;
|
||
|
||
if (that.trimOnBlur) {
|
||
value = that.controls[0].getValue();
|
||
value = jQuery.trim(value);
|
||
that.controls[0].setValue(value);
|
||
}
|
||
that.updateValueFromControls();
|
||
if (that.validAtChange) {
|
||
that.isValid();
|
||
}
|
||
if (typeof that.onChange === 'function') {
|
||
that.onChange(that.getValue(), previousValue);
|
||
}
|
||
if (that.form) {
|
||
(that.form.onChangeHandler())(that, that.getValue(), previousValue);
|
||
}
|
||
if (previousValue !== value) {
|
||
for (i = 0; i < that.dependentFields.getSize(); i += 1) {
|
||
that.dependentFields.get(i).dependencyHandler(that.dependentFields.get(i).dependencyFields.asArray().slice(0));
|
||
}
|
||
}
|
||
};
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.field.NumberField', NumberField);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = NumberField;
|
||
}
|
||
}());
|
||
(function () {
|
||
var UploadField = function (settings) {
|
||
UploadField.superclass.call(this, settings);
|
||
UploadField.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.form.Field', UploadField);
|
||
|
||
UploadField.prototype.type = 'UploadField';
|
||
UploadField.prototype.family = 'field';
|
||
|
||
UploadField.prototype.init = function (settings) {
|
||
var defaults;
|
||
defaults = {
|
||
accept: "",
|
||
multiple: false
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setAcceptedFiles(defaults.accept)
|
||
.setMultipleFiles(defaults.multiple);
|
||
};
|
||
|
||
/**
|
||
* @method setAccepted
|
||
* here we can define the type files our send, the valid types are MIME, separation with ","
|
||
* for more information go to http://reference.sitepoint.com/html/mime-types-full
|
||
* @param {String} accept MIME types are valid for our upload
|
||
*/
|
||
UploadField.prototype.setAcceptedFiles = function (accept) {
|
||
this.controls[0].setAcceptedFiles(accept);
|
||
return this;
|
||
};
|
||
|
||
UploadField.prototype.setMultipleFiles = function (value) {
|
||
this.controls[0].setMultiple(value);
|
||
return this;
|
||
};
|
||
|
||
UploadField.prototype.setControls = function () {
|
||
if (this.controls.length) {
|
||
return this;
|
||
}
|
||
this.controls.push(new PMUI.control.UploadControl());
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.field.UploadField', UploadField);
|
||
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = UploadField;
|
||
}
|
||
}());
|
||
(function () {
|
||
/**
|
||
* @class PMUI.field.ButtonField
|
||
* @extends PMUI.form.Field
|
||
* is a special field not return a value unlike other fields it is not
|
||
* equal intanciacion a button PMUI.ui.Button, new properties tine see examples:
|
||
*
|
||
* @example
|
||
* var b1,b2,b3;
|
||
* $(function() {
|
||
* b1 = new PMUI.field.ButtonField({
|
||
* value : "button1",
|
||
* handler : function () {
|
||
* alert("hi! I 'm Button 1")
|
||
* },
|
||
* name : 'button1'
|
||
* });
|
||
*
|
||
* document.body.appendChild(b1.getHTML());
|
||
* b1.defineEvents();
|
||
*
|
||
*
|
||
* b2 = new PMUI.field.ButtonField({
|
||
* value : "button2",
|
||
* handler : function () {
|
||
* alert("hi! I 'm Button 2")
|
||
* },
|
||
* name : 'button2',
|
||
* labelVisible : false,
|
||
* style : {
|
||
* cssClasses : ['customButton']
|
||
* },
|
||
* buttonAlign : 'center'
|
||
* });
|
||
*
|
||
* document.body.appendChild(b2.getHTML());
|
||
* b2.defineEvents();
|
||
*
|
||
* b3 = new PMUI.field.ButtonField({
|
||
* value : "button3",
|
||
* handler : function () {
|
||
* alert("hi! I 'm Button 3")
|
||
* },
|
||
* name : 'button3',
|
||
* labelVisible : false,
|
||
* buttonAlign : 'center'
|
||
* });
|
||
*
|
||
* document.body.appendChild(b3.getHTML());
|
||
* b3.defineEvents();
|
||
* });
|
||
*
|
||
*
|
||
* @cfg {Boolean} [disableButtonControl = [false]] button will be disabled if
|
||
* @cfg {String} [value = "[button-field]"] be the value with the button as text, this value does not reflect data on a form
|
||
* @cfg {String} [tooltipMessage = [""]] message will have the button
|
||
* @cfg {String} [controlIconClass = [""]] icon wearing this button is a class
|
||
* @cfg {Function} [handler = function(){}] the handler of button in the field
|
||
* @cfg {String} [buttonAlign = [""]] the position will have the pin is reflected when the label of the field is hidden
|
||
*/
|
||
var ButtonField = function (settings) {
|
||
ButtonField.superclass.call(this, settings);
|
||
this.buttonAlign = null;
|
||
this.handler = null;
|
||
ButtonField.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.form.Field', ButtonField);
|
||
|
||
ButtonField.prototype.type = "ButtonField";
|
||
|
||
ButtonField.prototype.init = function (settings) {
|
||
var defaults = {
|
||
disableButtonControl: false,
|
||
value: '[button-field]',
|
||
tooltipMessage: "",
|
||
controlIconClass: '',
|
||
handler: function () {
|
||
},
|
||
buttonAlign: '',
|
||
handler: null
|
||
}
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
|
||
this.setHandler(defaults.handler);
|
||
this.setControls();
|
||
this.setDisabled(defaults.disableButtonControl);
|
||
this.setValue(defaults.value);
|
||
this.setTooltipMessage(defaults.tooltipMessage);
|
||
this.setButtonAlign(defaults.buttonAlign);
|
||
};
|
||
/**
|
||
* The callback function to be executed when the the field's button is clicked.
|
||
* @return {Function} The callback function.
|
||
* @private
|
||
*/
|
||
ButtonField.prototype.onButtonClickHandler = function () {
|
||
var that = this;
|
||
return function (button) {
|
||
if (typeof that.handler === 'function') {
|
||
that.handler(that, button);
|
||
}
|
||
};
|
||
};
|
||
/**
|
||
* fix the control PMUI.control.ButtonControl
|
||
* @chainable
|
||
*/
|
||
ButtonField.prototype.setControls = function () {
|
||
var that = this;
|
||
if (this.handler === undefined || this.controls.length) {
|
||
return this;
|
||
}
|
||
this.controls.push(new PMUI.control.ButtonControl({
|
||
handler: that.onButtonClickHandler()
|
||
}));
|
||
return this;
|
||
};
|
||
/**
|
||
* diabled the Buttonfield
|
||
* @param {Boolean} value if true disable button, default value false
|
||
* @chainable
|
||
*/
|
||
ButtonField.prototype.setDisabled = function (value) {
|
||
this.controls[0].setDisabled(value);
|
||
return this;
|
||
}
|
||
/**
|
||
* disable Button
|
||
* @chainable
|
||
*/
|
||
ButtonField.prototype.disable = function () {
|
||
if (this.controls[0]) {
|
||
this.controls[0].disable();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* ebable button
|
||
* @chainable
|
||
*/
|
||
ButtonField.prototype.enable = function () {
|
||
if (this.controls[0]) {
|
||
this.controls[0].enable();
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ButtonField.prototype.click = function () {
|
||
if (this.controls[0].click) {
|
||
this.controls[0].click();
|
||
}
|
||
return this;
|
||
};
|
||
/**
|
||
* this click is established with jQuery, simulate the behavior click
|
||
* @chainable
|
||
*/
|
||
ButtonField.prototype.setHandler = function (handler) {
|
||
if (!(handler === null || typeof handler === 'function')) {
|
||
throw new Error("setHandler(): The parameter must be a function or null.");
|
||
}
|
||
this.handler = handler;
|
||
return this;
|
||
};
|
||
/**
|
||
* remove one event of the events
|
||
* @param {String} type It is an event that is stored in an object event
|
||
* @chainable
|
||
*/
|
||
ButtonField.prototype.removeEvent = function (type) {
|
||
this.controls[0].removeEvent(type);
|
||
return this;
|
||
};
|
||
/**
|
||
* removes all events
|
||
* @return {[type]}
|
||
*/
|
||
ButtonField.prototype.removeEvents = function () {
|
||
this.controls[0].removeEvents();
|
||
return this;
|
||
};
|
||
/**
|
||
* fix the text for the button
|
||
* @param {String} value
|
||
*/
|
||
ButtonField.prototype.setValue = function (value) {
|
||
this.value = value;
|
||
if (this.controls[0]) {
|
||
this.controls[0].setText(value);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ButtonField.prototype.setIcon = function (iconClass) {
|
||
this.controls[0].setIcon(iconClass);
|
||
return this;
|
||
};
|
||
ButtonField.prototype.setAliasButton = function (alias) {
|
||
this.controls[0].setAliasButton(alias);
|
||
return this;
|
||
};
|
||
ButtonField.prototype.setParent = function (parent) {
|
||
this.controls[0].setParent(parent);
|
||
return this;
|
||
};
|
||
ButtonField.prototype.defineEvents = function () {
|
||
ButtonField.superclass.prototype.defineEvents.call(this);
|
||
this.controls[0].defineEvents();
|
||
return this;
|
||
};
|
||
/**
|
||
* fix a message for button
|
||
* @param {String} messageTooltip
|
||
*/
|
||
ButtonField.prototype.setTooltipMessage = function (messageTooltip) {
|
||
this.controls[0].setTooltipMessage(messageTooltip);
|
||
return this;
|
||
};
|
||
/**
|
||
* the value return is forever null
|
||
* @return {object}
|
||
*/
|
||
ButtonField.prototype.getValue = function () {
|
||
return null;
|
||
}
|
||
/**
|
||
* hide label of the field, display none
|
||
* @chainable
|
||
*/
|
||
ButtonField.prototype.hideLabel = function () {
|
||
jQuery(this.dom.labelTextContainer).hide();
|
||
this.labelVisible = false;
|
||
return this;
|
||
}
|
||
/**
|
||
* hide label of the field, display inline-block
|
||
* @chainable
|
||
*/
|
||
ButtonField.prototype.showLabel = function () {
|
||
jQuery(this.dom.labelTextContainer).show();
|
||
this.labelVisible = true;
|
||
return this;
|
||
}
|
||
|
||
ButtonField.prototype.setButtonAlign = function (position) {
|
||
if (position == "left" || position == 'center' || position == "right" || position == '') {
|
||
this.buttonAlign = position;
|
||
}
|
||
if (this.html) {
|
||
this.style.addProperties({'textAlign': position});
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ButtonField.prototype.createHTML = function () {
|
||
ButtonField.superclass.prototype.createHTML.call(this);
|
||
this.setButtonAlign(this.buttonAlign);
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.field.ButtonField', ButtonField);
|
||
|
||
if (typeof exports !== "undefined") {
|
||
module.exports = ButtonField;
|
||
}
|
||
}());
|
||
(function () {
|
||
var ToolbarItem = function (settings) {
|
||
ToolbarItem.superclass.call(this, settings);
|
||
this.text = null;
|
||
this.dom = {};
|
||
ToolbarItem.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Item', ToolbarItem);
|
||
|
||
ToolbarItem.prototype.type = 'ToolbarItem';
|
||
|
||
ToolbarItem.prototype.init = function (settings) {
|
||
var defaults = {
|
||
text: ''
|
||
};
|
||
jQuery.extend(true, defaults, settings);
|
||
this.setText(defaults.text);
|
||
};
|
||
|
||
ToolbarItem.prototype.setText = function (text) {
|
||
if (typeof text !== 'string') {
|
||
throw new Error('setText(): The parameter must be a string.');
|
||
}
|
||
this.text = text;
|
||
if (this.dom.textContainer) {
|
||
this.dom.textContainer = text;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ToolbarItem.prototype.createHTML = function () {
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
ToolbarItem.superclass.prototype.createHTML.call(this);
|
||
this.dom.textContainer = this.html;
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.toolbar.ToolbarItem', ToolbarItem);
|
||
}());
|
||
(function () {
|
||
var ToolbarAction = function (settings) {
|
||
ToolbarAction.superclass.call(this, settings);
|
||
this.action = null;
|
||
this.visibleIcon = null;
|
||
this.iconClass = null;
|
||
ToolbarAction.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.toolbar.ToolbarItem', ToolbarAction);
|
||
|
||
ToolbarAction.prototype.init = function (settings) {
|
||
var defaults = {
|
||
action: null,
|
||
visibleIcon: true,
|
||
iconClass: null,
|
||
elementTag: 'li'
|
||
};
|
||
|
||
jQuery.extend(true, defaults, settings);
|
||
this.setElementTag(defaults.elementTag)
|
||
.setAction(defaults.action)
|
||
.setIconClass(defaults.iconClass);
|
||
if (defaults.visibleIcon) {
|
||
this.showIcon();
|
||
} else {
|
||
this.hideIcon();
|
||
}
|
||
};
|
||
|
||
ToolbarAction.prototype.setIconClass = function (iconClass) {
|
||
if (!(iconClass === null || typeof iconClass === 'string')) {
|
||
throw new Error("setIconClass(): the parameter must be a string or null.");
|
||
}
|
||
this.iconClass = iconClass;
|
||
if (this.dom.iconContainer) {
|
||
this.dom.iconContainer.className = 'pmui-toolbaraction-icon ' + (iconClass || "");
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ToolbarAction.prototype.setText = function (text) {
|
||
if (typeof text !== 'string') {
|
||
throw new Error('setText(): The parameter must be a string.');
|
||
}
|
||
this.text = text;
|
||
if (this.dom.textContainer) {
|
||
this.dom.textContainer.textContent = text;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ToolbarAction.prototype.setAction = function (action) {
|
||
if (!(action === null || typeof action === 'function')) {
|
||
throw new Error("setAction(): the parameter must be a function or null.");
|
||
}
|
||
this.action = action;
|
||
return this;
|
||
};
|
||
|
||
ToolbarAction.prototype.showIcon = function () {
|
||
this.visibleIcon = true;
|
||
if (this.dom.iconContainer) {
|
||
this.dom.iconContainer.style.display = '';
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ToolbarAction.prototype.hideIcon = function () {
|
||
this.visibleIcon = false;
|
||
if (this.dom.iconContainer) {
|
||
this.dom.iconContainer.style.display = 'none';
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ToolbarAction.prototype.attachEventListeners = function () {
|
||
var that = this;
|
||
|
||
if (this.html) {
|
||
this.removeEvents();
|
||
this.addEvent('click').listen(this.dom.link, function (e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
if (typeof that.action === 'function') {
|
||
that.action(that);
|
||
}
|
||
});
|
||
}
|
||
return this;
|
||
};
|
||
|
||
ToolbarAction.prototype.createHTML = function () {
|
||
var link,
|
||
iconContainer,
|
||
textContainer;
|
||
|
||
if (this.html) {
|
||
return this.html;
|
||
}
|
||
|
||
ToolbarAction.superclass.prototype.createHTML.call(this);
|
||
link = PMUI.createHTMLElement('a');
|
||
link.className = 'pmui-toolbaraction-link';
|
||
link.href = "#";
|
||
iconContainer = PMUI.createHTMLElement('i');
|
||
iconContainer.className = 'pmui-toolbaraction-icon';
|
||
textContainer = PMUI.createHTMLElement('span');
|
||
textContainer.className = 'pmui-toolbaraction-text';
|
||
|
||
link.appendChild(iconContainer);
|
||
link.appendChild(textContainer);
|
||
|
||
this.dom.iconContainer = iconContainer;
|
||
this.dom.link = link;
|
||
this.dom.textContainer = textContainer;
|
||
|
||
this.html.appendChild(link);
|
||
|
||
this.setText(this.text)
|
||
.setIconClass(this.iconClass);
|
||
|
||
this.attachEventListeners();
|
||
|
||
return this.html;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.toolbar.ToolbarAction', ToolbarAction);
|
||
}());
|
||
(function () {
|
||
var Toolbar = function (settings) {
|
||
Toolbar.superclass.call(this, settings);
|
||
Toolbar.prototype.init.call(this, settings);
|
||
};
|
||
|
||
PMUI.inheritFrom('PMUI.core.Container', Toolbar);
|
||
|
||
Toolbar.prototype.type = "Toolbar";
|
||
|
||
Toolbar.prototype.init = function (settings) {
|
||
var defaults = {
|
||
elementTag: 'ul'
|
||
};
|
||
|
||
jQuery(true, defaults, settings);
|
||
|
||
this.setElementTag(defaults.elementTag);
|
||
};
|
||
|
||
Toolbar.prototype.setFactory = function () {
|
||
this.factory = new PMUI.util.Factory({
|
||
products: {
|
||
'toolbaraction': PMUI.toolbar.ToolbarAction
|
||
},
|
||
defaultProduct: 'toolbaraction'
|
||
});
|
||
return this;
|
||
};
|
||
|
||
PMUI.extendNamespace('PMUI.toolbar.Toolbar', Toolbar);
|
||
}());
|
||
(function () {
|
||
|
||
var I18N = {
|
||
indexes: {},
|
||
repository: {},
|
||
observers: [],
|
||
defaultLanguage: 'en',
|
||
currentLanguage: 'en',
|
||
contextIndex: {},
|
||
setDefaultLanguage: function (lang) {
|
||
this.defaultLanguage = lang;
|
||
},
|
||
MD5: function (string) {
|
||
|
||
function RotateLeft(lValue, iShiftBits) {
|
||
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
|
||
}
|
||
|
||
function AddUnsigned(lX, lY) {
|
||
var lX4,
|
||
lY4,
|
||
lX8,
|
||
lY8,
|
||
lResult;
|
||
|
||
lX8 = (lX & 0x80000000);
|
||
lY8 = (lY & 0x80000000);
|
||
lX4 = (lX & 0x40000000);
|
||
lY4 = (lY & 0x40000000);
|
||
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
|
||
if (lX4 & lY4) {
|
||
return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
|
||
}
|
||
if (lX4 | lY4) {
|
||
if (lResult & 0x40000000) {
|
||
return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
|
||
} else {
|
||
return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
|
||
}
|
||
} else {
|
||
return (lResult ^ lX8 ^ lY8);
|
||
}
|
||
}
|
||
|
||
function F(x, y, z) {
|
||
return (x & y) | ((~x) & z);
|
||
}
|
||
|
||
function G(x, y, z) {
|
||
return (x & z) | (y & (~z));
|
||
}
|
||
|
||
function H(x, y, z) {
|
||
return (x ^ y ^ z);
|
||
}
|
||
|
||
function I(x, y, z) {
|
||
return (y ^ (x | (~z)));
|
||
}
|
||
|
||
function FF(a, b, c, d, x, s, ac) {
|
||
a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
|
||
return AddUnsigned(RotateLeft(a, s), b);
|
||
};
|
||
|
||
function GG(a, b, c, d, x, s, ac) {
|
||
a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
|
||
return AddUnsigned(RotateLeft(a, s), b);
|
||
};
|
||
|
||
function HH(a, b, c, d, x, s, ac) {
|
||
a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
|
||
return AddUnsigned(RotateLeft(a, s), b);
|
||
};
|
||
|
||
function II(a, b, c, d, x, s, ac) {
|
||
a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
|
||
return AddUnsigned(RotateLeft(a, s), b);
|
||
};
|
||
|
||
function ConvertToWordArray(string) {
|
||
var lWordCount,
|
||
lMessageLength = string.length,
|
||
lNumberOfWords_temp1 = lMessageLength + 8,
|
||
lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64,
|
||
lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16,
|
||
lWordArray = Array(lNumberOfWords - 1),
|
||
lBytePosition = 0,
|
||
lByteCount = 0;
|
||
|
||
while (lByteCount < lMessageLength) {
|
||
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
|
||
lBytePosition = (lByteCount % 4) * 8;
|
||
lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
|
||
lByteCount++;
|
||
}
|
||
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
|
||
lBytePosition = (lByteCount % 4) * 8;
|
||
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
|
||
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
|
||
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
|
||
|
||
return lWordArray;
|
||
};
|
||
|
||
function WordToHex(lValue) {
|
||
var WordToHexValue = "",
|
||
WordToHexValue_temp = "",
|
||
lByte,
|
||
lCount;
|
||
|
||
for (lCount = 0; lCount <= 3; lCount += 1) {
|
||
lByte = (lValue >>> (lCount * 8)) & 255;
|
||
WordToHexValue_temp = "0" + lByte.toString(16);
|
||
WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
|
||
}
|
||
return WordToHexValue;
|
||
};
|
||
|
||
function Utf8Encode(string) {
|
||
var utftext = "",
|
||
n,
|
||
c;
|
||
|
||
string = string.replace(/\r\n/g, "\n");
|
||
for (n = 0; n < string.length; n += 1) {
|
||
c = string.charCodeAt(n);
|
||
if (c < 128) {
|
||
utftext += String.fromCharCode(c);
|
||
}
|
||
else if ((c > 127) && (c < 2048)) {
|
||
utftext += String.fromCharCode((c >> 6) | 192);
|
||
utftext += String.fromCharCode((c & 63) | 128);
|
||
}
|
||
else {
|
||
utftext += String.fromCharCode((c >> 12) | 224);
|
||
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||
utftext += String.fromCharCode((c & 63) | 128);
|
||
}
|
||
}
|
||
|
||
return utftext;
|
||
};
|
||
|
||
var x,
|
||
k,
|
||
AA,
|
||
BB,
|
||
CC,
|
||
DD,
|
||
a,
|
||
b,
|
||
c,
|
||
d,
|
||
S11 = 7,
|
||
S12 = 12,
|
||
S13 = 17,
|
||
S14 = 22,
|
||
S21 = 5,
|
||
S22 = 9,
|
||
S23 = 14,
|
||
S24 = 20,
|
||
S31 = 4,
|
||
S32 = 11,
|
||
S33 = 16,
|
||
S34 = 23,
|
||
S41 = 6,
|
||
S42 = 10,
|
||
S43 = 15,
|
||
S44 = 21,
|
||
temp;
|
||
|
||
string = Utf8Encode(string);
|
||
|
||
x = ConvertToWordArray(string);
|
||
|
||
a = 0x67452301;
|
||
b = 0xEFCDAB89;
|
||
c = 0x98BADCFE;
|
||
d = 0x10325476;
|
||
|
||
for (k = 0; k < x.length; k += 16) {
|
||
AA = a;
|
||
BB = b;
|
||
CC = c;
|
||
DD = d;
|
||
a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
|
||
d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
|
||
c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
|
||
b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
|
||
a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
|
||
d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
|
||
c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
|
||
b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
|
||
a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
|
||
d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
|
||
c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
|
||
b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
|
||
a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
|
||
d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
|
||
c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
|
||
b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
|
||
a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
|
||
d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
|
||
c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
|
||
b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
|
||
a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
|
||
d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
|
||
c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
|
||
b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
|
||
a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
|
||
d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
|
||
c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
|
||
b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
|
||
a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
|
||
d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
|
||
c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
|
||
b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
|
||
a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
|
||
d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
|
||
c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
|
||
b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
|
||
a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
|
||
d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
|
||
c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
|
||
b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
|
||
a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
|
||
d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
|
||
c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
|
||
b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
|
||
a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
|
||
d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
|
||
c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
|
||
b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
|
||
a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
|
||
d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
|
||
c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
|
||
b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
|
||
a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
|
||
d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
|
||
c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
|
||
b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
|
||
a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
|
||
d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
|
||
c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
|
||
b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
|
||
a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
|
||
d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
|
||
c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
|
||
b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
|
||
a = AddUnsigned(a, AA);
|
||
b = AddUnsigned(b, BB);
|
||
c = AddUnsigned(c, CC);
|
||
d = AddUnsigned(d, DD);
|
||
}
|
||
|
||
temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d);
|
||
|
||
return temp.toLowerCase();
|
||
}
|
||
};
|
||
|
||
I18N.setDefaultLanguage = function (lang) {
|
||
this.defaultLanguage = lang;
|
||
if (this.repository[lang]) {
|
||
this.loadDefaultLanguege(this.repository[lang]);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
I18N.loadLanguage = function (data, lang, loaded) {
|
||
if (typeof data != 'object') {
|
||
throw new Error("loadLanguage(): the first parameter is not valid, should be 'object'");
|
||
}
|
||
if (typeof lang != 'string') {
|
||
throw new Error("loadLanguage(): the second parameter is not valid, should be 'string'");
|
||
}
|
||
if (this.defaultLanguage == lang) {
|
||
this.loadDefaultLanguege(data);
|
||
}
|
||
if (!loaded) {
|
||
this.repository[lang] = data;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
I18N.loadDefaultLanguege = function (data) {
|
||
var label,
|
||
value;
|
||
|
||
this.indexes = {};
|
||
this.contextIndex = {};
|
||
for (label in data) {
|
||
if (!this.indexes[data[label]]) {
|
||
this.indexes[data[label]] = label;
|
||
} else {
|
||
if (!this.contextIndex[data[label]]) {
|
||
value = this.indexes[data[label]];
|
||
this.contextIndex[data[label]] = {};
|
||
this.contextIndex[data[label]]['0'] = value;
|
||
this.contextIndex[data[label]]['1'] = label;
|
||
} else {
|
||
var n = this.getSizeJson(this.contextIndex[data[label]]);
|
||
this.contextIndex[data[label]][n.toString()] = label;
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
I18N.getSizeJson = function (json) {
|
||
var size = 0,
|
||
i;
|
||
|
||
if (typeof json == 'object') {
|
||
for (i in json) {
|
||
size += 1;
|
||
}
|
||
return size;
|
||
} else {
|
||
throw new Error('the parameter is not a JSON');
|
||
}
|
||
return this;
|
||
};
|
||
|
||
I18N.setCurrentLanguage = function (lang) {
|
||
this.currentLanguage = lang;
|
||
if (this.repository[lang]) {
|
||
this.loadLanguage(this.repository[lang], lang, true);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
I18N.translate = function (variablesLabels) {
|
||
var translation = String(this),
|
||
index,
|
||
i;
|
||
|
||
index = I18N.indexes[this];
|
||
if (index && I18N.repository[I18N.currentLanguage][index]) {
|
||
translation = I18N.repository[I18N.currentLanguage][index];
|
||
}
|
||
if (variablesLabels) {
|
||
for (i = 0; i < variablesLabels.length; i += 1) {
|
||
translation = translation.replace("{" + i + "}", String(variablesLabels[i]));
|
||
}
|
||
}
|
||
return translation;
|
||
};
|
||
|
||
I18N.translateContext = function (value) {
|
||
var translation,
|
||
index,
|
||
label;
|
||
|
||
if (typeof value != 'number') {
|
||
for (label in I18N.contextIndex[this]) {
|
||
if (I18N.contextIndex[this][label] == value) {
|
||
index = I18N.contextIndex[this][label];
|
||
}
|
||
}
|
||
} else {
|
||
index = I18N.contextIndex[this][value.toString()];
|
||
}
|
||
|
||
if (index) {
|
||
translation = I18N.repository[I18N.currentLanguage][index];
|
||
return translation;
|
||
}
|
||
|
||
return String(this);
|
||
};
|
||
// Declarations created to instantiate in NodeJS environment
|
||
if (typeof exports !== 'undefined') {
|
||
module.exports = I18N;
|
||
}
|
||
|
||
PMUI.extendNamespace('PMUI.lang.I18N', I18N);
|
||
|
||
}());
|
||
PMUI.init();
|
||
|