"use strict";
/* Minify Order(1) */
window.TK = {};
window.TK.AutoTypeSelection = true;
window.TK.Initialize = function (obj, parentObj, nameChildObj, selfObj, taggedObjects) {
var reserved = ['Parent', 'Sibling', 'Add', 'AddMultiple', 'Clear', 'Near', 'Remove', 'SetHTML', '_'];
var allObjs = [obj];
var inits = [];
var copyObj = {};
var defaultInnerHTML = null;
var type = obj._;
if (!taggedObjects)
taggedObjects = {};
var childTagged = {};
// Allow types to point to different objects (overriding their properties)
while (type && (typeof type != "string" || type.indexOf(".") > 0)) {
if (typeof type == "string") {
type = eval(type);
}
allObjs.push(type);
type = type._;
}
// Allow classname to be specified (example: div.orange)
var className = null;
/*if (type && type.indexOf && type.indexOf(".") >= 0) {
className = type.substr(type.indexOf(".") + 1);
type = type.substr(0, type.indexOf("."));
if (type == "")
type = null;
}*/
// Default type (div, unless name ends with Input, Button, Select or Label)
if (!type) {
type = "div";
if (nameChildObj && window.TK.AutoTypeSelection) {
var autoTypes = ["Input", "TextButton", "Button", "Select", "Label", "Span", "Textarea", "H1", "H2", "H3", "H4"];
var endsWith = function (s, has) {
if (!s || !has || s.length < has)
return false;
return s.substr(s.length - has.length) == has;
};
for (var i = 0; i < autoTypes.length; i++) {
if (endsWith(nameChildObj, autoTypes[i])) {
if (autoTypes[i] == "TextButton") {
defaultInnerHTML = nameChildObj.substr(0, nameChildObj.length - 10);
type = "button";
} else {
type = autoTypes[i].toLowerCase();
}
break;
}
}
}
}
// Actually create the element (or empty object, in case its a component with no DOM representation)
var copyObj = type != "component" ? document.createElement(type) : {};
copyObj._ = type;
if (type == "button") {
copyObj.type = "button"; // Prevent Buttons to automatically become submit buttons in case they are located in a form
}
// Go through all levels of elements, set (and override) properties. Keep all child elements and Init functions in a seperate list
var elements = {};
var resolveProperties = [];
for (var i = allObjs.length - 1; i >= 0; i--) {
for (var propName in allObjs[i]) {
if (propName == "style" && copyObj.appendChild) {
for (var styleName in allObjs[i].style) {
copyObj.style[styleName] = allObjs[i].style[styleName];
}
continue;
}
if (reserved.indexOf(propName) >= 0)
continue;
if (propName == "Elements") {
for (var elementName in allObjs[i][propName]) {
if (typeof allObjs[i][propName][elementName] === 'string') {
elements[elementName] = {
HTML: allObjs[i][propName][elementName]
};
} else if (typeof allObjs[i][propName][elementName] === 'function') {
elements[elementName] = {
onclick: allObjs[i][propName][elementName]
};
} else {
elements[elementName] = allObjs[i][propName][elementName];
}
}
} else {
if (allObjs[i][propName] && allObjs[i][propName].ToolkitPropertyReference)
resolveProperties.push(propName);
if (copyObj["__RecursiveProperties" + propName]) {
// We're going to copy all settings recursively
window.TK.RecursiveCopy(allObjs[i], copyObj, propName);
} else {
if (allObjs[i][propName] !== undefined)
copyObj[propName] = allObjs[i][propName];
}
}
if (propName == "Init")
inits.push(copyObj[propName]);
}
}
// Set the classname (Automatically adds a Element-Name class, and any custom classes)
if (type != "component" && (nameChildObj || className)) {
if (!copyObj.className)
copyObj.className = "";
copyObj.className += " " + (nameChildObj ? "Element-" + nameChildObj : "") + (className ? " " + className : "");
}
if (nameChildObj) {
copyObj._Name = nameChildObj;
}
if (copyObj._Self) // When set to true, this forces this element to be marked as 'Self'
selfObj = copyObj;
if (defaultInnerHTML && (!copyObj.innerHTML || copyObj.innerHTML == "")) {
copyObj.innerHTML = defaultInnerHTML;
}
if (copyObj._Position && copyObj.style) {
var isSet = function (a) {
return !(a === null || a === undefined);
};
var p = TK.ParsePosition(copyObj._Position); // top,right,bottom,left,width,height[,relative]
copyObj.style.top = isSet(p[0]) ? p[0] : "";
copyObj.style.right = isSet(p[1]) ? p[1] : "";
copyObj.style.bottom = isSet(p[2]) ? p[2] : "";
copyObj.style.left = isSet(p[3]) ? p[3] : "";
if (isSet(p[4]))
copyObj.style.width = p[4];
if (isSet(p[5]))
copyObj.style.height = p[5];
copyObj.style.position = isSet(p[6]) ? p[6] : "absolute";
}
for (var name in taggedObjects) {
copyObj["$"+name] = taggedObjects[name]; // Tagged parent objects always start with a $ to make them easy to recognize
}
if (copyObj._Tag) {
if (copyObj._Tag === true && nameChildObj)
copyObj._Tag = nameChildObj;
var tag = copyObj._Tag.substr(0, 1) == "$" ? copyObj._Tag.substr(1) : copyObj._Tag;
taggedObjects[tag] = copyObj;
}
//if (nameChildObj)
// taggedObjects["Element_"+nameChildObj] = copyObj; // Speed up the 'Near' method. TODO: Need to test .Add performance impact first
// Add extra helper functions
copyObj.Add = function (obj, nameChildObj) {
// Add single child element
var copyTagged = {};
for (var tagName in taggedObjects) {
if (childTagged[tagName]) // Make sure we don't pass other siblings childs
continue;
copyTagged[tagName] = taggedObjects[tagName];
}
return window.TK.Initialize(obj, this, nameChildObj, null, copyTagged);
};
copyObj.AddMultiple = function (obj, propertyArray, syncPropertyName, useVariable) {
// Add multiple child elements
var newObjs = [];
var allNewObjIds = [];
var existingObjIds = [];
if (syncPropertyName) {
existingObjIds = this.Elements.ToArray().Select(function (a) { return useVariable ? a[useVariable][syncPropertyName] : a[syncPropertyName]; });
}
for (var i = 0; i < propertyArray.length; i++) {
if (syncPropertyName) {
var objId = propertyArray[i][syncPropertyName];
allNewObjIds.push(objId);
var existingIndex = existingObjIds.indexOf(objId);
if (existingIndex >= 0) { // Already exists
existingObjIds.splice(existingIndex, 1);
continue;
}
}
var toInitialize = propertyArray[i];
if (useVariable) {
toInitialize = { _: obj };
toInitialize[useVariable] = propertyArray[i];
} else {
toInitialize._ = obj;
}
var copyTagged = {};
for (var tagName in taggedObjects) {
if (childTagged[tagName]) // Make sure we don't pass other siblings childs
continue;
copyTagged[tagName] = taggedObjects[tagName];
}
newObjs.push(window.TK.Initialize(toInitialize, this, null, null, copyTagged));
}
if (syncPropertyName) {
// Remove all old child elements which aren't in the new propertyArray
for (var childName in this.Elements) {
if (typeof this.Elements[childName] != "function" && allNewObjIds.indexOf(useVariable ? this.Elements[childName][useVariable][syncPropertyName] : this.Elements[childName][syncPropertyName]) < 0) {
this.Elements[childName].Remove();
}
}
}
return newObjs;
};
copyObj.Remove = function (onlyExecuteCallback) {
if (this.Destroy) {
this.Destroy();
}
for (var childName in this.Elements) {
if (this.Elements[childName].Remove)
this.Elements[childName].Remove(true);
}
if (onlyExecuteCallback)
return;
if (this.Parent) {
if (this.parentNode)
this.parentNode.removeChild(this);
for (var childName in this.Parent.Elements) {
if (this.Parent.Elements[childName] == this) {
delete this.Parent.Elements[childName];
break;
}
}
delete this.Parent;
} else {
if (this.parentNode && this.parentNode.removeChild)
this.parentNode.removeChild(this);
}
};
copyObj.Clear = function () {
this.Elements.ToArray().Select(function (a) { a.Remove(); });
};
copyObj.Near = function (name) {
// Find the nearest element with this name, or classname, or id
if (name.substr(0, 1) == "$") { // Search by tag
var tmp = this;
while (tmp) {
if (tmp[name])
return tmp[name];
tmp = tmp.Parent;
}
}
var curEle = this;
var findName = name;
if (name.substr(0, 1) != "." && name.substr(0, 1) != "#") {
if (curEle.Elements && curEle.Elements[name])
return curEle.Elements[name]; // Direct child
if (curEle["$$" + name])
return curEle["$$" + name]; // Child somewhere in the tree
if (curEle["$" + name])
return curEle["$" + name]; // One of the parents
findName = ".Element-" + findName;
}
var found = curEle.querySelector(findName);
if (found)
return found;
while (curEle.Parent || curEle.parentNode) {
curEle = curEle.Parent ? curEle.Parent : curEle.parentNode;
if (curEle._Name == name)
return curEle;
if (curEle["$$" + name])
return curEle["$$" + name];
if (curEle["$" + name])
return curEle["$" + name];
/*if (curEle["$$Element_" + name]) // Speed up the 'Near' method. TODO: Need to test .Add performance impact first
return curEle["$$Element_" + name];
if (curEle["$Element_" + name])
return curEle["$Element_" + name]; */
if (curEle.className && "." + curEle.className == name)
return curEle;
if (curEle.Elements && curEle.Elements[name])
return curEle.Elements[name];
var found = curEle.querySelector(findName);
if (found)
return found;
}
return null;
};
copyObj.DetachElementFromParent = function () {
// This appends the div to the document.body element with a fixed position on the same position using getBoundingClientRect
if (!this.getBoundingClientRect)
return;
var rect = this.getBoundingClientRect();
if (!rect || isNaN(rect.top) || isNaN(rect.left))
return;
this.style.position = "fixed";
this.style.top = rect.top + "px";
this.style.left = rect.left + "px";
document.body.appendChild(this);
};
var getReference = function (capture, observingObject) {
var curObj = copyObj;
if (typeof capture == "function") {
return capture(copyObj);
}
if (capture.indexOf(":") >= 0) {
curObj = copyObj.Near(capture.substr(0, capture.indexOf(":")));
if (!curObj)
return "";
capture = capture.substr(capture.indexOf(":") + 1);
}
if (capture != "") {
while (capture.indexOf(".") > 0) {
var part = capture.substr(0, capture.indexOf("."));
if (part == "Parent")
curObj = parentObj;
else
curObj = curObj[part];
capture = capture.substr(capture.indexOf(".") + 1);
}
if (observingObject) {
// Add a getter/setter structure to the property we want to observe, when changed, call the object's FieldUpdate function
curObj["__Orig" + capture] = curObj[capture];
Object.defineProperty(curObj, capture, {
get: function () {
return this["__Orig" + capture];
},
set: function (value) {
this["__Orig" + capture] = value;
if (observingObject.Obj.FieldUpdate) {
observingObject.Obj.FieldUpdate(observingObject.Name, value);
}
}
});
}
curObj = curObj[capture];
}
return curObj;
};
copyObj.SetHTML = function (html) {
var injectChildsObj = {};
var injectChilds = false;
this.innerHTML = html.replace(/\$([\ \-\#\:\w\.]*?)\$/g, function (match, capture) {
var curObj = getReference(capture);
if (curObj && curObj.tagName) { // Reference added to a HTML element
var rnd = "placeholder-" + Math.floor(Math.random() * 1000000) + "-" + Math.floor(Math.random() * 1000000) + "-" + Math.floor(Math.random() * 1000000);
injectChildsObj[rnd] = curObj;
injectChilds = true;
return "";
}
return curObj;
});
if (injectChilds) {
var items = this.querySelectorAll(".tkInternalPlaceHolder");
for (var i = 0; i < items.length; i++) {
var elementToAdd = injectChildsObj[items[i].id];
items[i].parentNode.insertBefore(elementToAdd, items[i]);
items[i].parentNode.removeChild(items[i]);
}
}
};
copyObj.Elements = {};
copyObj.Elements.ToArray = function () {
var arr = [];
for (var propName in this) {
if (typeof this[propName] != "function")
arr.push(this[propName]);
}
return arr;
};
// Set the 'Self' property, which will always point to the main object added with .Add or TK.Initialize
if (!selfObj)
selfObj = copyObj;
if (copyObj.Self === undefined)
copyObj.Self = selfObj;
// Create all sub elements
for (var name in elements) {
var copyTagged = {};
for (var tagName in taggedObjects)
copyTagged[tagName] = taggedObjects[tagName];
window.TK.Initialize(elements[name], copyObj, name, selfObj, copyTagged);
// The copyTagged object is now expanded with child objects, we will just keep the new childs
for (var name in copyTagged) {
if (taggedObjects[name] == copyTagged[name])
continue; // Old one we've already added as parent, or it is ourself
childTagged[name] = copyTagged[name];
}
}
for (var name in childTagged) {
copyObj["$$" + name] = childTagged[name];
taggedObjects[name] = childTagged[name]; // Will also add it to our tagged object (but only at this step), so any of the didn't get the child elements of their siblings.
}
// Add this element to the child elements of a parent element (and get a reference to it)
if (parentObj) {
copyObj.Parent = parentObj;
copyObj.Sibling = parentObj.Elements;
parentObj.Elements[nameChildObj ? nameChildObj : ("ele"+Math.random().toString())] = copyObj;
if (copyObj.appendChild && parentObj.appendChild) {
// This and parent element are html nodes
parentObj.appendChild(copyObj);
}
}
// Special HTML template support. Variables in the same object can be including using their $PropertyName$ , $Parent.Sub.PropertyName$ etc. also works
// You can also reference to other elements, which will be appended at the correct locations.
if (copyObj.HTML) {
copyObj.SetHTML(copyObj.HTML);
}
// Use TK.P("Parent.PropertyName") in a template to reference to a object on runtime
for (var i = 0; i < resolveProperties.length; i++) {
var p = copyObj[resolveProperties[i]];
if (!p.ToolkitPropertyReference)
continue;
if (p.Observe) {
// Attach getter/setter to the property we are looking at, so it can call our 'FieldChange' function
getReference(p.ToolkitPropertyReference, { Name: resolveProperties[i], Obj: copyObj });
// Attach an getter to the current object, to always retrieve the latest value
var attachGetter = function (referencePath) {
Object.defineProperty(copyObj, resolveProperties[i], {
get: function () {
return getReference(referencePath);
}
});
};
attachGetter(p.ToolkitPropertyReference);
} else {
copyObj[resolveProperties[i]] = getReference(p.ToolkitPropertyReference);
}
}
// Call all init functions of inheritance objects, lowest level goes first, all the 'overrides' go after
for (var i = 0; i < inits.length; i++) {
inits[i].call(copyObj);
}
return copyObj;
};
window.TK.P = function (name, observe) {
return { ToolkitPropertyReference: name, Observe: observe };
};
window.TK.RecursiveCopy = function (objSource, objTarget, singleProperty) {
for (var n in objSource) {
if (objSource[n] === undefined || (singleProperty && n != singleProperty))
continue;
if (!(objSource[n] instanceof Object) || typeof objSource[n] == "function") {
objTarget[n] = objSource[n];
} else if (Array.isArray(objSource[n])) {
if (!objTarget[n])
objTarget[n] = [];
for (var i = 0; i < objSource[n].length; i++) {
objTarget[n].push(objSource[n][i]);
}
} else {
if (!objTarget[n])
objTarget[n] = {};
window.TK.RecursiveCopy(objSource[n], objTarget[n]);
}
}
};
window.TK.ParsePosition = function (p) {
if (!p)
return [];
// Parse a _Position property and returns an array with all values
// Supported:
// - [top,right,bottom,left,width,height,tags]
// - L10 T20 W200 H400
// - L10 T20 R10 B10
// - X10 Y20 W200 H400 relative
// - [100, 200, "50px","10%", null, null, "relative"]
if (p.substr) {
if (p.indexOf(",") >= 0) { // 'old' style
p = p.split(/,/g);
} else {
var newP = [];
var matches = p.match(/[XYLTRBWH][\d\-\.]+(%|px|pt|vw|vh)?/g);
for (var i = 0; i < matches.length; i++) {
p = p.replace(matches[i], "");
var c = matches[i].substr(0, 1);
var v = matches[i].substr(1);
if (c == "X" || c == "L")
newP[3] = v;
else if (c == "Y" || c == "T")
newP[0] = v;
else if (c == "R")
newP[1] = v;
else if (c == "B")
newP[2] = v;
else if (c == "W")
newP[4] = v;
else if (c == "H")
newP[5] = v;
}
// Rest are tags, we'll put them all in the [6] position
if (p.trim)
p = p.trim();
if (p)
newP[6] = p;
p = newP;
}
} else {
p = p.slice(); // Don't edit the existing array object as it might be observed
}
for (var i = 0; i < p.length; i++) {
if (p[i] !== null && p[i] !== undefined && !p[i].substr) {
p[i] = p[i].toString() + "px"; // Convert numbers to px
}
}
return p;
};
/// Helper functions
window.SvgPath = function (d, width, height, color, strokeWidth) {
if (!color) color = "#333";
if (!strokeWidth) strokeWidth = 3;
return '';
};
window.ConvertFromASPTime = function (a) {
if (a && a.length && a.length > 6 && a.substr(0, 6) == "/Date(") {
var dateObj = new Date(parseInt(a.substr(6, a.length - 2)));
return dateObj.toISOString();
}
return "";
};
window.ConvertToASPTime = function (a) {
if (a == "")
return "";
var time = new Date(a).getTime();
return "\\/Date(" + time + ")\\/";
};
"use strict";
/* Minify Order(5) */
window.ajax = function () {
var obj = this;
this.timeout = 30000;
this.timeoutChecker = null;
this.ajaxObject = null;
this.busy = false;
this.queue = [];
this.currentRequestInfo = null; // url, callback etc.
this.retryCount = 0;
this.maxRetries = 3;
this.cached = {};
this.allowEmptyResponse = false;
this.showServerErrors = true;
this.saveResults = false;
this.cacheResults = false;
this.executeScriptTags = true;
this.parseJSONResponse = false;
this.errorHandler = null; // function(statusCode,responseText) {}
this.extraHeaders = []; // [ ["Content-Type", "application/json"] ]
this.beforeRequest = null; // function(requestInfo, callBackExecuteRequest(requestInfo) ) {}
this.getSetting = function (name, requestInfo) {
if (!requestInfo)
requestInfo = this.currentRequestInfo;
if (requestInfo && requestInfo.extraSettings && requestInfo.extraSettings[name] !== undefined) {
return requestInfo.extraSettings[name];
}
return this[name];
};
this.initComponent = function () {
this.ajaxObject = this.getAvailableAjaxObject();
if (!this.ajaxObject) // could not init any ajax object
return;
// set event handlers
this.ajaxObject.onreadystatechange = function () {
if (obj.ajaxObject.readyState !== 4 || obj.ajaxObject.status == 0)
return;
if (obj.timeoutChecker) {
clearTimeout(obj.timeoutChecker);
obj.timeoutChecker = null;
}
if (obj.ajaxObject.status !== 200) {
if (obj.ajaxObject.status >= 400) {
var errorHandler = obj.getSetting("errorHandler");
if (errorHandler)
errorHandler(obj.ajaxObject.status, obj.ajaxObject.responseText);
else if (obj.getSetting("showServerErrors"))
alert('Server error, returned code: ' + obj.ajaxObject.status); // mostly unrecoverable server error
obj.nextRequest();
} else
obj.retryLast(); // retry, sometimes IE returns some unusual number for failed requests
return;
}
var responseIsText = (!obj.ajaxObject.responseType || obj.ajaxObject.responseType === "" || obj.ajaxObject.responseType == "text");
try {
// Response is required since bad requests can sometimes give an empty response
if (responseIsText && obj.ajaxObject.responseText == "" && !obj.getSetting("allowEmptyResponse")) {
obj.retryLast();
return;
}
} catch (r) {
obj.retryLast(); // Sometimes the responseText is unreadable, also retry
return;
}
// Everything seems to be ok!
var curReq = obj.currentRequestInfo;
obj.retryCount = 0;
var callBacks = [];
if (curReq.callBack)
callBacks.push(curReq.callBack);
var pageCacheHash = responseIsText && (obj.getSetting("saveResults") || obj.getSetting("cacheResults")) ? "page" + obj.hashString(curReq.get) : "";
if (responseIsText && obj.getSetting("saveResults")) {
window.localStorage[pageCacheHash] = obj.ajaxObject.responseText;
}
if (responseIsText && obj.getSetting("cacheResults")) {
if (obj.cached[pageCacheHash] !== undefined && Array.isArray(obj.cached[pageCacheHash]))
callBacks = callBacks.concat(obj.cached[pageCacheHash]); // There were possibly multiple calls waiting for this response
obj.cached[pageCacheHash] = obj.ajaxObject.responseText;
}
// check for callback
for (var i = 0; i < callBacks.length; i++) {
let cb = callBacks[i];
var responseData = null;
if (responseIsText) {
responseData = obj.ajaxObject.responseText;
if (obj.getSetting("parseJSONResponse") && responseData && (responseData.substr(0, 1) == "{" || responseData.substr(0, 1) == "\"" || responseData.substr(0, 1) == "[")) {
responseData = JSON.parse(responseData);
}
} else {
responseData = obj.ajaxObject.response;
}
obj.executeCallBack(cb, responseData, curReq);
}
obj.nextRequest();
};
this.ajaxObject.onerror = function (error) {
var errorHandler = obj.getSetting("errorHandler");
if (errorHandler)
errorHandler(0, null);
obj.nextRequest();
};
};
this.executeCallBack = function (callBack, responseData, request) {
// Do this as a timeout, so it doesn't mess with our ajax code
setTimeout(function () { callBack(responseData, request.get, request.post, request.callBackData); }, 1);
}
this.getAvailableAjaxObject = function () {
// Modern browsers
if (window.XMLHttpRequest)
return new XMLHttpRequest();
// IE Specific
if (window.ActiveXObject) {
try {
return new ActiveXObject("Msxml2.XMLHTTP");
} catch (r) { }
try {
return new ActiveXObject("Microsoft.XMLHTTP");
} catch (r) { }
}
};
this.hashString = function (string) {
var hash = 0;
if (string.length == 0)
return hash;
for (var i = 0; i < string.length; i++) {
var char = string.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
};
this.clearSaved = function () {
for (var item in window.localStorage) {
if (item.substr(0, 4) == "page") {
delete window.localStorage[item];
}
}
};
this.clearCached = function () {
this.cached = {};
};
//redo current request
this.retryLast = function () {
if (this.getSetting("saveResults") && window.localStorage["page" + this.hashString(this.currentRequestInfo.get)]) {
console.log("Using saved results");
// Use saved result instead
if (this.currentRequestInfo.callBack) {
// make a copy since the callback is called in timeout (currentRequestInfo can be changed)
var curReq = this.currentRequestInfo;
var content = window.localStorage["page" + this.hashString(this.currentRequestInfo.get)];
if (this.getSetting("parseJSONResponse") && content && (content.substr(0, 1) == "{" || content.substr(0, 1) == "\"" || content.substr(0, 1) == "[")) {
content = JSON.parse(content);
}
obj.executeCallBack(curReq.callBack, content, curReq);
}
this.nextRequest();
return;
}
this.busy = false;
this.retryCount++;
if (this.retryCount > this.getSetting("maxRetries")) {
this.retryCount = 0;
this.nextRequest();
return;
}
if (this.currentRequestInfo)
this.do(this.currentRequestInfo.get, this.currentRequestInfo.post, this.currentRequestInfo.callBack, this.currentRequestInfo.callBackData, this.currentRequestInfo.extraSettings);
};
// Prepare everything for a next request (and even do them if there is something in the queue)
this.nextRequest = function () {
this.busy = false;
if (this.queue.length == 0) {
return;
}
var nextRequestInfo = this.queue.shift();
this.do(nextRequestInfo.get, nextRequestInfo.post, nextRequestInfo.callBack, nextRequestInfo.callBackData, nextRequestInfo.extraSettings);
};
this.do = function (get, post, callBack, callBackData, extraSettings) {
if (!this.ajaxObject) {
this.initComponent();
}
if (extraSettings) {
var orig = extraSettings;
extraSettings = JSON.parse(JSON.stringify(extraSettings)); // Clone to make sure we don't override any settings for the next request
if (orig.errorHandler)
extraSettings.errorHandler = orig.errorHandler;
}
var requestInfo = { get: get, post: post, callBack: callBack, callBackData: callBackData, extraSettings: extraSettings };
var beforeRequest = this.getSetting("beforeRequest", requestInfo);
if (beforeRequest) {
beforeRequest(requestInfo, function (requestInfo) {
if (!requestInfo.extraSettings)
requestInfo.extraSettings = {};
requestInfo.extraSettings.beforeRequest = null;
obj.do(requestInfo.get, requestInfo.post, requestInfo.callBack, requestInfo.callBackData, requestInfo.extraSettings);
});
return;
}
if (extraSettings && extraSettings.cacheResults) {
var pageHash = ["page" + this.hashString(get)];
var content = this.cached[pageHash];
var done = 0;
if (content !== undefined && Array.isArray(content)) {
// This request is already on its way, add us to the callbacks
content.push(callBack);
done = 1;
} else if (content) {
if (callBack) {
if (!(typeof post === "string" || post instanceof String) && this.parseJSONResponse !== false && content && (content.substr(0, 1) == "{" || content.substr(0, 1) == "\"" || content.substr(0, 1) == "[")) {
content = JSON.parse(content);
}
obj.executeCallBack(callBack, content, requestInfo);
}
done = 1;
} else {
// We will execute this request, so add a temp array all next callback can be added to
if (!this.busy)
this.cached[pageHash] = [];
}
if (done) {
if (!this.busy)
this.nextRequest();
return;
}
}
if (this.busy) {
this.queue.push(requestInfo);
return;
}
this.busy = true;
this.currentRequestInfo = requestInfo;
if (post == null) {
this.ajaxObject.open('GET', get, true);
} else {
this.ajaxObject.open('POST', get, true);
}
var extraHeaders = this.getSetting("extraHeaders");
for (var i = 0; i < extraHeaders.length; i++) {
this.ajaxObject.setRequestHeader(extraHeaders[i][0], extraHeaders[i][1]);
}
if (this.ajaxObject.responseType !== this.undefined && this.getSetting("responseType"))
this.ajaxObject.responseType = this.getSetting("responseType");
this.timeoutChecker = setTimeout(function () {
obj.timeoutChecker = null;
try { // try to cancel
obj.ajaxObject.abort();
} catch (errie) { }
obj.retryLast();
}, this.getSetting("timeout"));
if (post == null) {
this.ajaxObject.send(); // get
} else {
if (post instanceof FormData) { // Post form data (including file uploads)
this.ajaxObject.send(post);
return;
} else if (!(typeof post === "string" || post instanceof String)) {
// We can only put text in our post data
post = JSON.stringify(post);
if (!this.currentRequestInfo.extraSettings)
this.currentRequestInfo.extraSettings = {};
if (this.currentRequestInfo.extraSettings.parseJSONResponse == undefined)
this.currentRequestInfo.extraSettings.parseJSONResponse = true;
}
this.ajaxObject.setRequestHeader("Content-Type", post.length > 0 && post.substr(0, 1) == "{" ? "application/json" : "application/x-www-form-urlencoded");
this.ajaxObject.setRequestHeader("Content-Size", post.length);
if (post.length > 0 && post.substr(0, 1) == "{") {
post = post.replace(/"\/Date\((\d*)\)\/"/g, "\"\\/Date($1)\\/\"");
}
this.ajaxObject.send(post);
}
};
/* Extra handy functions */
this.doAjaxToDiv = function (get, post, divName, extraSettings) {
var obj = this;
this.do(get, post, function (txt) {
document.getElementById(divName).innerHTML = txt;
if (obj.getSetting("executeScriptTags")) {
obj.executeScripts(txt);
}
}, null, extraSettings);
};
this.doAjaxToDivElement = function (get, post, divElement, extraSettings) {
var obj = this;
this.do(get, post, function (txt) {
divElement.innerHTML = txt;
if (obj.getSetting("executeScriptTags")) {
obj.executeScripts(txt);
}
}, null, extraSettings);
};
this.doAjaxFormSubmit = function (formElement, callBack, submitButton, extraSettings) {
/*if (window.FormData) { // We can use the FormData api
var fd = new FormData(formElement);
if (submitButton && submitButton.name) {
fd.append(fd.name, fd.value);
}
this.do(formElement.action, fd, callBack, null, extraSettings);
return fd;
}*/
var inputs = "";
for (var i = 0; i < formElement.length; i++) {
if (formElement[i].type == "submit" && submitButton != formElement[i])
continue;
if ((formElement[i].type == "checkbox" || formElement[i].type == "radio") && !formElement[i].checked)
continue;
if (formElement[i].multiple && formElement[i].options && formElement[i].name) {
for (var j = 0; j < formElement[i].options.length; j++) {
if (formElement[i].options[j].selected && formElement[i].options[j].value) {
inputs += "&" + formElement[i].name + "=" + this.URLEncode(formElement[i].options[j].value);
}
}
continue;
}
if (formElement[i].value && formElement[i].name) {
inputs += "&" + formElement[i].name + "=" + this.URLEncode(formElement[i].value);
}
}
this.do(formElement.action, inputs, callBack, null, extraSettings);
};
this.doAjaxFormSubmitToDiv = function (formElement, divName, submitButton, extraSettings) {
var obj = this;
this.doAjaxFormSubmit(formElement, function (pTxt) {
document.getElementById(divName).innerHTML = pTxt;
if (obj.getSetting("executeScriptTags")) {
obj.executeScripts(pTxt);
}
}, submitButton, extraSettings);
};
this.doFileUpload = function (url, nameFormField, blobOrFileElement, blobFileName, callBack, callBackData, extraSettings) {
var fd = new FormData();
fd.append(nameFormField, blobOrFileElement, blobFileName);
this.do(url, fd, callBack, callBackData, extraSettings);
};
this.executeScripts = function (data) {
while (data.indexOf("") >= 0) {
var script = data.substr(data.indexOf(""));
try {
eval(script);
} catch (errie) {
console.log("Error executing script:");
console.log(errie);
}
data = data.substr(data.indexOf("") + 9);
}
};
// URL Encoding script
this.gethex = function (decimal) {
var hexchars = "0123456789ABCDEFabcdef";
return "%" + hexchars.charAt(decimal >> 4) + hexchars.charAt(decimal & 0xF);
};
this.URLEncode = function (decoded) {
var unreserved = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.~";
var encoded = "";
for (var i = 0; i < decoded.length; i++) {
var ch = decoded.charAt(i);
if (unreserved.indexOf(ch) != -1) {
encoded = encoded + ch;
} else {
var charcode = decoded.charCodeAt(i);
if (charcode < 128) {
encoded = encoded + this.gethex(charcode);
} else if (charcode > 127 && charcode < 2048) {
encoded = encoded + this.gethex((charcode >> 6) | 0xC0);
encoded = encoded + this.gethex((charcode & 0x3F) | 0x80);
} else if (charcode > 2047 && charcode < 65536) {
encoded = encoded + this.gethex((charcode >> 12) | 0xE0);
encoded = encoded + this.gethex(((charcode >> 6) & 0x3F) | 0x80);
encoded = encoded + this.gethex((charcode & 0x3F) | 0x80);
} else if (charcode > 65535) {
encoded = encoded + this.gethex((charcode >> 18) | 0xF0);
encoded = encoded + this.gethex(((charcode >> 12) & 0x3F) | 0x80);
encoded = encoded + this.gethex(((charcode >> 6) & 0x3F) | 0x80);
encoded = encoded + this.gethex((charcode & 0x3F) | 0x80);
}
}
}
return encoded;
};
};
window.Ajax = new ajax();"use strict";
/* Minify Order(5) */
// Extra array functions, inspired by LinqToSql
Array.prototype.Where = function (func) {
var items = [];
for (var i = 0; i < this.length; i++) {
if (func(this[i], i))
items.push(this[i]);
}
return items;
};
Array.prototype.First = function (func) {
if (!func)
return this[0];
for (var i = 0; i < this.length; i++) {
if (func(this[i], i))
return this[i];
}
};
Array.prototype.Take = function (count) {
var items = [];
for (var i = 0; i < this.length && i < count; i++) {
items.push(this[i]);
}
return items;
};
Array.prototype.Skip = function (count) {
var items = [];
for (var i = count; i < this.length; i++) {
items.push(this[i]);
}
return items;
};
Array.prototype.OrderBy = function (func) {
if (!func)
func = function (a) { return a; };
return this.sort(function (a, b) {
var a2 = func(a), b2 = func(b);
if (a2 === null || a2 === undefined)
a2 = 0;
if (b2 === null || b2 === undefined)
b2 = 0;
if (a2.localeCompare && b2.localeCompare) { // Both are string
return a2.localeCompare(b2);
} else if (a2.localeCompare) { // Only a2 is a string
return a2.localeCompare(b2.toString());
} else if (b2.localeCompare) {
return a2.toString().localeCompare(b2); // Only b2 is a string
}
return a2 - b2;
});
};
Array.prototype.OrderByDesc = function (func) {
return this.OrderBy(func).reverse();
};
Array.prototype.Select = function (func) {
var items = [];
for (var i = 0; i < this.length; i++)
items.push(func(this[i], i));
return items;
};
Array.prototype.Max = function (func) {
if (!func)
func = function (a) { return a; };
var highest = null;
for (var i = 0; i < this.length; i++) {
var value = func(this[i], i);
if (highest == null || value > highest)
highest = value;
}
return highest;
};
Array.prototype.Min = function (func) {
if (!func)
func = function (a) { return a; };
var lowest = null;
for (var i = 0; i < this.length; i++) {
var value = func(this[i], i);
if (lowest == null || value < lowest)
lowest = value;
}
return lowest;
};
Array.prototype.Average = function (func) {
if (!func)
func = function (a) { return a; };
var average = null;
var averageCount = 0;
for (var i = 0; i < this.length; i++) {
var value = func(this[i], i);
average = (average * averageCount + value) / (averageCount + 1);
averageCount++;
}
return average;
};
Array.prototype.Unique = function (func) {
if (!func)
func = function (a) { return a; };
var items = [];
var uniqueKeys = [];
for (var i = 0; i < this.length; i++) {
var key = func ? func(this[i], i) : this[i];
if (uniqueKeys.indexOf(key) < 0) {
items.push(this[i]);
uniqueKeys.push(key);
}
}
return items;
};
Array.prototype.Randomize = function () {
var items = this.slice();
var currentIndex = items.length, temporaryValue, randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = items[currentIndex];
items[currentIndex] = items[randomIndex];
items[randomIndex] = temporaryValue;
}
return items;
};/* Minify Order(50) */
if (!window.Svg) { window.Svg = {}; }
var s="",
"Home":s+"",
"Hamburger":s+"",
"Close":s+"",
"Resize":s+"",
"Move":s+"",
"Copy":s+"",
"User":s+"",
"Meter":s+"",
"Barcode":s+"",
"Route":s+"",
"Find":s+"",
"Popout":s+"",
"Download":s+"",
"Upload":s+"",
"Warning":s+"",
"Help":s+"",
"Message":s+"",
"Favorite":s+"",
"Dashboard":s+"",
"Sync":s+"",
"SyncError":s+"",
"ErrorAlarrt":s+"",
"Report":s+"",
"Back":s+"",
"Next":s+"",
"OK":s+"",
"Cancel":s+"",
"Text":s+"",
"Table":s+"",
"Gauge":s+"",
"Donut":s+"",
"Left":s+"",
"Right":s+"",
"Up":s+"",
"TextIncrease":s+"",
"TextDecrease":s+"",
"Down":s+"",
"TextItalic":s+"",
"TextBold":s+"",
"TextUnderline":s+"",
"TextAlignLeft":s+"",
"TextAlignRight":s+"",
"TextAlignCenter":s+"",
"TextList":s+"",
"TextIndent":s+"",
"TextOutdent":s+"",
"TextQuoteBlock":s+"",
"TextCodeBlock":s+"",
"Card":s+"",
"Link":s+"",
"Image":s+"",
"TextParagraph":s+"",
"TextHeader1":s+"",
"TextHeader2":s+"",
"TextHeader3":s+"",
};"use strict";
window.TK.AjaxList = {
_: "div",
Url: "",
Post: null,
IdField: "Id",
Template: {},
AjaxSettings: {},
UseVariable: null,
Init: function () {
var obj = this;
if (this.Url) {
Ajax.do(this.Url, this.Post, function (response) {
obj.AddMultiple(obj.Template, JSON.parse(response), obj.IdField, obj.UseVariable);
}, undefined, this.AjaxSettings);
}
},
Refresh: function () {
this.Init();
}
};/* Minify Order(100) */
// Component to store client side data with several fallbacks: IndexedDB, LocalStorage
// This component has the same methods as TK.ServerStorage
TK.ClientStorage = {
_: "component",
Prefix: "TKStorage_",
Store: function (path, blobOrByteArrayOrStringContents, isStoredCallBack) {
var obj = this;
// We will convert all byte arrays to blobs, which will later be converted to data urls
if ((window.Uint8Array && blobOrByteArrayOrStringContents instanceof Uint8Array) || (window.Uint16Array && blobOrByteArrayOrStringContents instanceof Uint16Array)) {
blobOrByteArrayOrStringContents = new Blob([blobOrByteArrayOrStringContents], { 'type': 'application/octet-stream' });
}
// We will convert all blobs to data urls
if ((window.Blob && blobOrByteArrayOrStringContents instanceof Blob) || (window.File && blobOrByteArrayOrStringContents instanceof File)) {
var reader = new FileReader();
reader.onload = function () {
if (reader.result) {
obj.Store(path, reader.result, isStoredCallBack);
}
};
reader.readAsDataURL(blobOrByteArrayOrStringContents);
return;
}
this.GetIndexedDBInstance(function (db) {
if (!db) {
// use local storage as fallback
var saved = false;
try {
window.localStorage[obj.Prefix + path] = blobOrByteArrayOrStringContents;
saved = true;
} catch (ex) { } // not allowed, supported or quota reached
if (isStoredCallBack)
isStoredCallBack(saved);
return;
}
var transaction = db.transaction(["data"], "readwrite");
transaction.oncomplete = function (event) {
if (isStoredCallBack)
isStoredCallBack(true);
};
transaction.onerror = function (event) {
console.log("IndexedDB transaction onerror: " + event);
};
var store = transaction.objectStore("data");
var request = store.get(path);
request.onerror = function (event) {
console.log('IndexedDB objectStore get onerror: ' + event);
};
request.onsuccess = function (event) {
if (request.result === undefined) { // Add
store.add({ key: path, data: blobOrByteArrayOrStringContents });
} else { // Update
request.result.data = blobOrByteArrayOrStringContents;
store.put(request.result);
}
};
});
},
Retrieve: function (path, asBlob, callBack) {
if (!callBack)
return;
var dataUrlToBlob = function (dataUrl) {
var parts = dataUrl.split(','), mime = parts[0].match(/:(.*?);/)[1]
if (parts[0].indexOf('base64') != -1) {
var data = atob(parts[1]);
var i = data.length;
var byteArray = new Uint8Array(data.length);
while (i--)
byteArray[i] = data.charCodeAt(i);
return new Blob([byteArray], { type: mime });
} else {
return new Blob([decodeURIComponent(parts[1])], { type: mime });
}
};
var obj = this;
this.GetIndexedDBInstance(function (db) {
if (!db) {
// use local storage as fallback
if (!window.localStorage[obj.Prefix + path]) {
callBack();
} else if (!asBlob) {
callBack(window.localStorage[obj.Prefix + path]);
} else if (request.result.data.length < 5 && request.result.data.substr(0, 5) != "data:") {
callBack(new Blob([window.localStorage[obj.Prefix + path]], { type: 'text/plain' }));
} else {
callBack(dataUrlToBlob(window.localStorage[obj.Prefix + path]));
}
return;
}
var transaction = db.transaction(["data"]);
var store = transaction.objectStore("data");
var request = store.get(path);
request.onerror = function (event) {
console('IndexedDB getAllKeys onerror: ' + event);
};
request.onsuccess = function () {
if (!request.result) {
callBack();
} else if (!asBlob) {
callBack(request.result.data);
} else if (request.result.data.length < 5 && request.result.data.substr(0, 5) != "data:") {
callBack(new Blob([request.result.data], { type: 'text/plain' }));
} else {
callBack(dataUrlToBlob(request.result.data)); // Data url, turn into blob
}
};
});
},
GetUrl: function (path, callBack) {
if (window.URL && window.URL.createObjectURL) {
// Return a blob url if supported
this.Retrieve(path, true, function (resp) {
if (!resp) {
callBack();
} else {
callBack(window.URL.createObjectURL(resp));
}
});
} else {
// Return a data url as fallback
this.Retrieve(path, false, function (resp) {
if (!resp) {
callBack();
} else if (resp.length < 5 || resp.substr(0, 5) != "data:") {
callBack("data:text/plain;base64," + btoa(resp));
} else {
callBack(resp);
}
});
}
},
Delete: function (path, isDeletedCallBack) {
var obj = this;
this.GetIndexedDBInstance(function (db) {
if (!db) {
if (window.localStorage[obj.Prefix + path])
delete window.localStorage[obj.Prefix + path];
if (isDeletedCallBack)
isDeletedCallBack(true);
return;
}
var transaction = db.transaction(["data"], "readwrite");
transaction.oncomplete = function (event) {
if (isDeletedCallBack)
isDeletedCallBack(true);
};
transaction.onerror = function (event) {
console.log("IndexedDB transaction onerror: " + event);
if (isDeletedCallBack)
isDeletedCallBack(false);
};
var store = transaction.objectStore("data");
var request = store.get(path);
request.onerror = function (event) {
console.log('IndexedDB objectStore get onerror: ' + event);
if (isDeletedCallBack)
isDeletedCallBack(false);
};
request.onsuccess = function (event) {
if (request.result !== undefined) {
// Found: Delete
store.delete(path);
}
};
});
},
List: function (pathsCallBack) {
if (!pathsCallBack)
return;
var obj = this;
this.GetIndexedDBInstance(function (db) {
if (!db) {
// use local storage as fallback
var keys = [];
for (var name in window.localStorage) {
if (name.length > obj.Prefix && name.substr(0, obj.Prefix.length) == obj.Prefix) {
keys.push(name.substr(obj.Prefix.length));
}
}
pathsCallBack(keys);
return;
}
var transaction = db.transaction(["data"]);
var store = transaction.objectStore("data");
var request = store.getAllKeys();
request.onerror = function (event) {
console('IndexedDB getAllKeys onerror: ' + event);
};
request.onsuccess = function () {
pathsCallBack(request.result);
};
});
},
// Internal
GetIndexedDBInstance: function (callBack) {
if (this.IndexedDB) {
callBack(this.IndexedDB);
return;
}
var obj = this;
var db = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
if (!db) {
callBack();
return;
}
var request = window.indexedDB.open(this.Prefix, 1);
request.onerror = function (event) {
console.log("IndexedDB onerror: " + request.errorCode);
callBack();
};
request.onupgradeneeded = function (event) {
obj.IndexedDB = event.target.result;
event.target.transaction.oncomplete = function () {
callBack(obj.IndexedDB);
};
obj.IndexedDB.createObjectStore("data", { keyPath: "key" });
};
request.onsuccess = function (event) {
obj.IndexedDB = event.target.result;
callBack(obj.IndexedDB);
};
}
};"use strict";
window.TK.DragDrop = {
_: "div",
className: "toolkitDragDrop",
Init: function () {
this.style.position = "relative";
},
Type: "",
Threshold: 10,
ElementTemplate: null, // When set, the current element will not be moved, but a new element will be created by this. This will also be used as hover template if the HoverTemplate property is not set.
HoverTemplate: null, // When set, this element will be used for a hover-preview. If both are set, the ElementTemplate will be passed as Template to the .Drop method
Dropped: function (droppedInContainer, addedElement) { }, // Extra callback
ontouchstart: function (e) {
this.onmousedown(e.touches[0]);
e.stopPropagation();
},
onmousedown: function (e) {
var startX, startY;
try { startX = e.clientX; startY = e.clientY; } catch (errie) { var e2 = window.event; startX = e2.clientX; startY = e2.clientY; }
var obj = this;
var origObj = this;
var origParent = this.parentNode;
var myPosition = this.getBoundingClientRect();
var cursorOffsetX = startX - myPosition.left;
var cursorOffsetY = startY - myPosition.top;
var positions = [];
var newTop, newLeft;
var first = true;
var elementOrTemplateToAdd = null;
var passedThreshold = false;
var aboveContainer = null;
var aboveContainerPosition = null;
window.onmousemove = function (e) {
var x, y;
try { x = e.clientX; y = e.clientY; } catch (errie) { var e2 = window.event; x = e2.clientX; y = e2.clientY; }
if (!passedThreshold && (Math.abs(startX - x) < obj.Threshold && Math.abs(startY - y) < obj.Threshold))
return;
passedThreshold = true;
if (first) {
if (obj.HoverTemplate) {
obj = obj.Add(obj.HoverTemplate);
origParent = null;
} else if (obj.ElementTemplate) {
obj = obj.Add(obj.ElementTemplate);
origParent = null;
}
obj.style.position = "fixed";
document.body.appendChild(obj);
elementOrTemplateToAdd = (origObj.ElementTemplate && origObj.HoverTemplate ? origObj.ElementTemplate : obj);
var containers = document.querySelectorAll(".toolkitDragDropContainer");
for (var i = 0; i < containers.length; i++) {
if (containers[i].DropFilter && (!obj.Type || containers[i].DropFilter.indexOf(obj.Type) < 0))
continue;
if (containers[i].CanDrop && !containers[i].CanDrop(elementOrTemplateToAdd))
continue;
containers[i].className += " toolkitDragDropContainerArea";
positions.push({ Element: containers[i], Position: containers[i].getBoundingClientRect() });
}
first = false;
} else {
for (var i = 0; i < positions.length; i++) {
positions[i].Position = positions[i].Element.getBoundingClientRect();
}
}
newTop = (y - startY) + myPosition.top;
newLeft = (x - startX) + myPosition.left;
var cursorX = newLeft + cursorOffsetX;
var cursorY = newTop + cursorOffsetY;
var found = [];
for (var i = 0; i < positions.length; i++) {
if (positions[i].Position.left <= cursorX && positions[i].Position.right >= cursorX &&
positions[i].Position.top <= cursorY && positions[i].Position.bottom >= cursorY) {
if (aboveContainer != positions[i].Element) {
if (aboveContainer != null) {
aboveContainer.className = aboveContainer.className.replace(/toolkitDragDropContainerHover/g, "");
}
aboveContainer = positions[i].Element;
aboveContainerPosition = positions[i].Position;
aboveContainer.className += " toolkitDragDropContainerHover";
}
positions[i].TotalSize = positions[i].Position.width + positions[i].Position.height;
found.push(positions[i]);
}
}
if (found.length == 0 && aboveContainer != null) {
aboveContainer.className = aboveContainer.className.replace(/toolkitDragDropContainerHover/g, "");
aboveContainer = null;
} else if (found.length > 0) {
// We will pick the smallest element hovered over, as that will often work fine for nested elements
var newAboveContainer = found.OrderBy(function (a) { return a.TotalSize }).First().Element;
if (aboveContainer != newAboveContainer) {
if (aboveContainer != null) {
aboveContainer.className = aboveContainer.className.replace(/toolkitDragDropContainerHover/g, "");
}
aboveContainer = newAboveContainer;
aboveContainerPosition = positions[i].Position;
aboveContainer.className += " toolkitDragDropContainerHover";
}
}
obj.style.top = newTop + "px";
obj.style.left = newLeft + "px";
};
window.onmouseup = function () {
// If above container element, append to container element, or else move back
obj.style.left = "";
obj.style.top = "";
obj.style.position = "relative";
for (var i = 0; i < positions.length; i++) {
if (positions[i].Element.className)
positions[i].Element.className = positions[i].Element.className.replace(/toolkitDragDropContainerArea/g, "");
}
if (aboveContainer) {
aboveContainer.className = aboveContainer.className.replace(/toolkitDragDropContainerHover/g, "");
var createdElement = null;
if (aboveContainer.Drop) {
createdElement = aboveContainer.Drop(elementOrTemplateToAdd, newLeft - aboveContainerPosition.left, newTop - aboveContainerPosition.top);
}
if (!createdElement && elementOrTemplateToAdd == obj) {
if (origObj.ElementTemplate && origObj.HoverTemplate) { // Both are set, but not handled. Create a new element to add
// Remove hover element
if (obj.Remove)
obj.Remove();
else
obj.parentNode.removeChild(obj);
if (aboveContainer.Add) { // Container is a toolkit element, use the Add method
aboveContainer.Add(origObj.ElementTemplate);
obj = null; // Mark as finished
} else {
obj = TK.Initialize(origObj.ElementTemplate); // Initialize and append to this container
}
} else if (!origObj.ElementTemplate && origObj.HoverTemplate) { // Just the hover is set, add the original object to the new parent
// Remove hover element
if (obj.Remove)
obj.Remove();
else
obj.parentNode.removeChild(obj);
obj = origObj;
}
if (obj != null) {
aboveContainer.appendChild(obj);
obj.Parent = aboveContainer;
var newElementId = Math.random();
if (origParent && origParent != aboveContainer && origParent.Elements) {
for (var id in origParent.Elements) {
if (origParent.Elements[id] == obj) {
delete origParent.Elements[id];
newElementId = id;
break;
}
}
}
if (aboveContainer.Elements) {
aboveContainer.Elements[newElementId] = obj;
}
}
}
if (origObj.Dropped) {
origObj.Dropped(aboveContainer, createdElement);
}
} else if (passedThreshold && origParent) {
origParent.appendChild(obj);
} else if (passedThreshold) {
// Remove hover element
if (obj.Remove)
obj.Remove();
else
obj.parentNode.removeChild(obj);
}
window.onmousemove = null;
window.onmouseup = null;
window.onselectstart = null;
window.ontouchmove = null;
window.ontouchend = null;
};
window.ontouchmove = function (e) {
if (window.onmousemove)
window.onmousemove(e.touches[0]);
e.stopPropagation();
};
window.ontouchend = function (e) {
if (window.onmouseup)
window.onmouseup();
e.stopPropagation();
};
window.onselectstart = function () { return false; };
if (e && e.preventDefault)
e.preventDefault();
else
window.event.returnValue = false;
}
};"use strict";
window.TK.Event = {
_: "component",
Subscribe: [],
Init: function () {
if (!window.TK.EventHandlers) {
window.TK.EventHandlers = [];
}
window.TK.EventHandlers.push(this);
},
Destroy: function () {
var i = window.TK.EventHandlers.indexOf(this);
if (i >= 0) {
window.TK.EventHandlers.splice(i, 1);
}
},
Send: function (eventType, eventData) {
if (!window.TK.EventHandlers)
return;
for (var i = 0; i < window.TK.EventHandlers.length; i++) {
if (window.TK.EventHandlers[i].Subscribe.indexOf(eventType) >= 0) {
window.TK.EventHandlers[i].Receive(eventType, eventData);
}
}
},
Receive: function (eventType, eventData) { /* Callback */ }
};"use strict";
window.TK.Form = {
_: "form",
className: "toolkitForm",
Model: null,
DefaultModel: null,
ModelProperty: "Model",
Fields: null, // fieldName: { Required: false, DisplayName: "Field1", Type: "number", Template: {..} }
SortByFields: false,
IgnoreRest: false,
CurrentFields: null,
LabelWidth: 0, // when non-zero number: width of labels in px, when string: width of label with unit (ex. 50%), when 0/null: the labels will be displayed as 'block' and fill the complete line.
SaveButtonText: "Save",
AutoSave: false,
RequiredText: "The following fields are required: ",
ApplyToModelDirectly: false,
RemoveValueOfNotVisibleFields: true, // If false, a field hidden by IsVisible will still keep its value when saving
CustomValidation: function (model, callBackResult) { callBackResult([]); }, // Callback with an array of errors. If the array is empty or undefined, the validation is seen as passed.
SubmitResult: function (isSaved, errors) { }, // Callback after .onsubmit and .Save or .RenderErrors is called
DefaultTemplates: {
text: {
_: "input",
type: "text",
Init: function () { this.value = this.Data; },
GetValue: function () { return this.value; }
},
textarea: {
_: "textarea",
Init: function () { this.value = this.Data; },
GetValue: function () { return this.value; }
},
textarray: {
_: "div",
className: "textArray",
TemplateEditableDiv: {
className: "textArrayItem",
Data: null,
PlaceHolder: null,
Init: function () {
this.Elements.Content.disabled = this.Parent ? this.Parent.disabled : false;
if (this.PlaceHolder) {
this.Elements.Content.value = this.PlaceHolder;
this.className += " newItem";
this.Elements.RemoveButton.style.display = "none";
} else {
this.Elements.Content.value = this.Data;
}
},
Elements: {
ContentSize: {
_: "div",
style: {
position: "absolute",
height: "0px",
overflow: "hidden",
maxWidth: "70%"
}
},
Content: {
_: "input",
onfocus: function () {
if (this.Parent.PlaceHolder) {
this.value = "";
delete this.Parent.PlaceHolder;
this.Parent.className = "textArrayItem";
this.Parent.Elements.RemoveButton.style.display = "";
this.Parent.OnUse();
}
},
oninput: function () {
this.Parent.Elements.ContentSize.textContent = this.value;
this.style.width = (this.Parent.Elements.ContentSize.offsetWidth + 5) + "px";
},
onblur: function () {
if (this.value == "")
this.Parent.Remove();
}
},
RemoveButton: {
innerHTML: "X",
tabIndex: -1,
onclick: function () {
this.Parent.Remove();
}
}
},
OnUse: function () {
}
},
Init: function () {
for (var i = 0; i < this.Data.length; i++) {
this.Add({
_: this.TemplateEditableDiv,
Data: this.Data[i]
});
}
this.AddNewItem();
},
AddNewItem: function () {
var obj = this;
this.Add({
_: this.TemplateEditableDiv,
Data: null,
PlaceHolder: "New item",
OnUse: function () {
obj.AddNewItem();
}
});
this.ResizeAllElements();
},
ResizeAllElements: function () {
var obj = this;
setTimeout(function () {
for (var name in obj.Elements) {
if (!obj.Elements[name].Elements)
continue;
obj.Elements[name].Elements.Content.oninput();
}
}, 1);
},
GetValue: function () {
var items = this.Elements.ToArray();
var value = [];
for (var i = 0; i < items.length; i++) {
if (items[i].Elements.Content.value != "" && !items[i].PlaceHolder)
value.push(items[i].Elements.Content.value);
}
return value;
}
},
number: {
_: "input",
type: "number",
step: "any",
className: "digits",
Init: function () { this.value = this.Data; },
GetValue: function () {
if (this.value == "")
return null;
return parseFloat(this.value);
}
},
password: {
_: "input",
type: "password",
Init: function () { this.value = this.Data; },
GetValue: function () {
return this.value;
}
},
boolean: {
_: "input",
type: "checkbox",
Init: function () {
this.checked = this.Data;
this.Parent.Elements.DataLabel.insertBefore(this, this.Parent.Elements.DataLabel.childNodes[0]); // Put the text behind the checkbox and make the text clickable
if (this.Parent.Elements.DataLabel.style.width) {
// Insert dummy container in the place where the label used to be
var dummy = this.Add({ style: { display: "inline-block", width: this.Parent.Elements.DataLabel.style.width } });
this.Parent.insertBefore(dummy, this.Parent.Elements.DataLabel);
this.Parent.Elements.DataLabel.style.width = "auto";
}
},
GetValue: function () { return this.checked; }
},
select: {
_: "select",
Init: function () {
if (!this.DataSettings.Options)
return;
for (var i = 0; i < this.DataSettings.Options.length; i++) {
this.appendChild(new Option(this.DataSettings.Options[i].Text, this.DataSettings.Options[i].Value.toString()));
}
if (this.Data)
this.value = this.Data.toString();
else
this.value = this.DataSettings.ValueIsText ? "" : 0;
},
GetValue: function () {
return this.DataSettings.ValueIsText ? this.value :
this.value !== null && this.value !== undefined ? parseInt(this.value) :
0;
}
},
ajaxselect: {
_: "select",
Init: function () {
this.Refresh();
},
Refresh: function () {
var obj = this;
Ajax.do(this.DataSettings.Url, null, function (response) {
obj.Values = JSON.parse(response);
if (obj.DataSettings.Options && obj.DataSettings.Options.length > 0) {
obj.Values = obj.DataSettings.Options.concat(obj.Values);
}
obj.GenerateOptions();
}, null, { cacheResults: true });
},
GenerateOptions: function () {
for (var i = 0; i < this.Values.length; i++) {
var name = this.DataSettings.GetName ? this.DataSettings.GetName(this.Values[i]) : this.Values[i].Name;
var value = this.DataSettings.GetValue ? this.DataSettings.GetValue(this.Values[i]) : this.Values[i].Id;
var optionEle = new Option(name.toString(), value.toString());
optionEle.ValueObj = this.Values[i];
this.appendChild(optionEle);
}
if (this.Data !== undefined && this.Data !== null) {
this.value = this.Data.toString(); // Always set a string for compatibility reasons
// Set Data to null so GetValue will return value from here on
this.Data = null;
}
else
this.value = this.DataSettings.ValueIsText ? "" : "0";
},
GetValue: function () {
// When Data is set and options are being retrieved we can return the Data.
// The user was not able to change the value up to this point so the Data is accurate.
if (this.Data !== null && this.Data !== undefined) {
return this.Data;
} else if (this.value !== null && this.value !== undefined) {
return this.DataSettings.ValueIsText ? this.value.toString() : parseInt(this.value);
}
return this.DataSettings.ValueIsText ? "" : 0;
}
},
date: {
_: "input",
type: "date",
Init: function () { this.value = this.Data; },
GetValue: function () { return this.value; }
},
color: {
_: "input",
type: "color",
Init: function () { this.value = this.Data; },
GetValue: function () { return this.value; }
},
datetime: {
_: "input",
type: "text",
Init: function () { this.value = this.Data; },
GetValue: function () { return this.value; }
},
form: {
_: "div",
className: "subForm",
Init: function () {
var dataSettings = this.DataSettings;
if (this.LinkedData !== undefined && dataSettings.LinkSettings && dataSettings.LinkSettings[this.LinkedData]) {
dataSettings = dataSettings.LinkSettings[this.LinkedData];
}
this.Add({
_: TK.Form,
SaveButtonText: null,
Model: this.Data,
DefaultModel: dataSettings.DefaultModel,
Fields: dataSettings.Fields,
IgnoreRest: dataSettings.IgnoreRest,
SortByFields: dataSettings.SortByFields,
// Init: dataSettings.Init
}, "Form");
},
GetValue: function (errors) {
return this.Elements.Form.GetModel(errors);
}
},
forms: {
_: "div",
className: "subForms",
Forms: null,
Init: function () {
this.Forms = [];
var obj = this;
if (this.DataSettings.NewItem) {
this.Add({
_: "button",
innerHTML: this.DataSettings.AddButtonText ? this.DataSettings.AddButtonText : "Add",
className: "addButton",
type: "button",
onclick: function () {
obj.Forms.push(obj.Add({
_: TK.Form,
Model: JSON.parse(JSON.stringify(obj.DataSettings.NewItem)), // deepcopy
SaveButtonText: null,
Fields: obj.DataSettings.Fields,
IgnoreRest: obj.DataSettings.IgnoreRest,
SortByFields: obj.DataSettings.SortByFields,
// Init: obj.DataSettings.Init,
Elements: {
RemoveButton: {
innerHTML: obj.DataSettings.RemoveButtonText ? obj.DataSettings.RemoveButtonText : "Remove",
className: "removeButton",
onclick: function () {
this.Parent.Remove();
}
}
}
}));
if (obj.onchange)
obj.onchange();
}
});
}
if (!this.Data)
return;
for (var i = 0; i < this.Data.length; i++) {
this.Forms.push(this.Add({
_: TK.Form,
Model: this.Data[i],
SaveButtonText: null,
Fields: this.DataSettings.Fields,
IgnoreRest: this.DataSettings.IgnoreRest,
SortByFields: this.DataSettings.SortByFields,
//Init: this.DataSettings.Init,
Elements: {
RemoveButton: {
innerHTML: this.DataSettings.RemoveButtonText ? this.DataSettings.RemoveButtonText : "Remove",
className: "removeButton",
onclick: function () {
this.Parent.Remove();
}
}
}
}));
}
},
GetValue: function (errors) {
var newObjs = [];
for (var i = 0; i < this.Forms.length; i++) {
if (!this.Forms[i].Parent)
continue; // This form is removed
newObjs.push(this.Forms[i].GetModel(errors));
}
return newObjs;
}
}
},
Init: function () {
var obj = this;
this.CurrentFields = {};
var tmpFields = {};
var model = this[this.ModelProperty];
if (!model && this.DefaultModel)
model = this.DefaultModel;
else if (!model)
return;
if (this.Templates) {
for (var name in this.Templates) {
this.DefaultTemplates[name] = this.Templates[name];
}
}
var callIsVisible = false;
for (var name in model) {
var type = this.Fields && this.Fields[name] && this.Fields[name].Type ? this.Fields[name].Type : typeof model[name];
if (this.IgnoreRest && (!this.Fields || !this.Fields[name]))
type = "ignore";
var getField = function (fieldName, fallBack) {
if (fallBack == undefined)
fallBack = null;
return obj.Fields && obj.Fields[name] && obj.Fields[name][fieldName] ? obj.Fields[name][fieldName] : fallBack;
};
if (type != "ignore") {
var defaultTemplate = this.DefaultTemplates[type] ? this.DefaultTemplates[type] : this.DefaultTemplates.text;
var isRequired = getField("Required", false);
var row = {
style: { },
className: "fieldRow field-" + name + (isRequired ? " fieldRequired" : "") + " " + (getField("Inline") ? "inlineBlock" : ""),
Elements: {
DataLabel: { innerHTML: getField("DisplayName",name), style: {} },
DataField: {
_: getField("Template", defaultTemplate),
_Self: true,
/* required: isRequired, */
placeholder: getField("PlaceHolder",""),
Data: model[name],
DataName: name,
LinkedData: getField("LinkField") ? model[getField("LinkField")] : null,
DataSettings: (this.Fields && this.Fields[name] ? this.Fields[name] : null),
onfocus: getField("onfocus"),
onblur: getField("onblur"),
onchange: getField("onchange"),
disabled: getField("disabled", false),
readOnly: getField("readOnly"),
IsVisible: getField("IsVisible"),
//Init: (this.Fields && this.Fields[name] && this.Fields[name].Init ? this.Fields[name].Init : undefined),
Form: this
}
}
};
if (this.LabelWidth) {
row.Elements.DataLabel.style.display = "inline-block";
row.Elements.DataLabel.style.width = this.LabelWidth + (this.LabelWidth.substr ? "" : "px");
}
if (this.Fields && this.Fields[name]) {
if (this.Fields[name].Width) {
row.className += " withWidth";
row.style.width = this.Fields[name].Width;
}
if (this.Fields[name].IsVisible) {
row.style.display = this.Fields[name].IsVisible(model) ? "" : "none";
callIsVisible = true;
}
if (this.Fields[name].LabelWidth) {
row.Elements.DataLabel.style.display = "inline-block";
row.Elements.DataLabel.style.width = this.LabelWidth + (this.LabelWidth.substr ? "" : "px");
}
}
row.Elements.DataField.origOnBlur = row.Elements.DataField.onblur;
row.Elements.DataField.onblur = function () {
if (this.origOnBlur)
this.origOnBlur();
if (obj.AutoSave) {
obj.onsubmit();
}
};
row.Elements.DataField.origOnchange = row.Elements.DataField.onchange;
row.Elements.DataField.onchange = function () {
if (this.origOnchange)
this.origOnchange();
var curModel = null;
for (var name in obj.CurrentFields) {
if (obj.CurrentFields[name] && obj.CurrentFields[name].DataSettings && obj.CurrentFields[name].DataSettings.LinkField && obj.CurrentFields[name].DataSettings.LinkField == this.DataName) {
obj.CurrentFields[name].LinkedData = this.GetValue();
obj.CurrentFields[name].Clear();
obj.CurrentFields[name].Init();
}
if (obj.CurrentFields[name] && obj.CurrentFields[name].IsVisible && obj.CurrentFields[name].Parent && obj.CurrentFields[name].Parent.style) {
// Get model and call obj.CurrentFields[name].DataSettings.IsVisible(model);
if (!curModel)
curModel = obj.GetModel([]);
obj.CurrentFields[name].Parent.style.display = obj.CurrentFields[name].IsVisible(curModel) ? "" : "none";
}
}
if (obj.AutoSave) {
obj.onsubmit();
}
};
if (this.SortByFields) {
tmpFields[name] = row;
} else {
var rowObj = this.Add(row);
this.CurrentFields[name] = rowObj.Elements.DataField;
}
} else {
this.CurrentFields[name] = "ignore";
}
}
var parent = this;
if (this.SortByFields && this.Fields) {
for (var fieldName in this.Fields) {
if (this.Fields[fieldName].Type == "section") {
parent = this.Add({
_: "fieldset",
Elements: {
Legend: {
_: "legend",
innerHTML: this.Fields[fieldName].DisplayName
}
}
});
}
if (!tmpFields[fieldName]) {
if (this.Fields[fieldName]._) // This is just a template
parent.Add(this.Fields[fieldName], fieldName);
continue;
}
var rObj = parent.Add(tmpFields[fieldName]);
this.CurrentFields[fieldName] = rObj.Elements.DataField;
}
}
if (callIsVisible) {
// There is at least 1 IsVisible function, so we'll get the model and call all methods now the elements are actually created
var curModel = this.GetModel([]);
for (var name in this.CurrentFields) {
if (this.CurrentFields[name] && this.CurrentFields[name].IsVisible && this.CurrentFields[name].Parent && this.CurrentFields[name].Parent.style) {
this.CurrentFields[name].Parent.style.display = this.CurrentFields[name].IsVisible(curModel) ? "" : "none";
}
}
}
if (this.SaveButtonText) {
this.Add({
_: "button",
type: "submit",
innerHTML: this.SaveButtonText
}, "SaveButton");
}
},
Save: function (obj) {
},
GetModel: function (errors, applyToModelDirectly) {
if (applyToModelDirectly === undefined)
applyToModelDirectly = this.ApplyToModelDirectly;
var model = this[this.ModelProperty];
var newObj = applyToModelDirectly ? model : {};
if (applyToModelDirectly) { // Check for errors first
var tmpErrorList = [];
var tmpModel = this.GetModel(tmpErrorList, false);
if (tmpErrorList.length > 0) {
for (var i = 0; i < tmpErrorList.length; i++) {
errors.push(tmpErrorList[i]);
}
return tmpModel;
}
}
for (var name in this.CurrentFields) {
if (this.CurrentFields[name] == "ignore") {
if (!applyToModelDirectly && model != null)
newObj[name] = model[name];
} else {
if (this.CurrentFields[name].IsVisible && this.RemoveValueOfNotVisibleFields && this.CurrentFields[name].Parent && this.CurrentFields[name].Parent.style && this.CurrentFields[name].Parent.style.display == "none") {
if (applyToModelDirectly && newObj != null) // Set to null, otherwise don't include it in the new model
newObj[name] = null;
continue;
}
newObj[name] = this.CurrentFields[name].GetValue(errors);
var hasError = false;
if (errors) {
if (this.Fields && this.Fields[name] && this.Fields[name].Required && (newObj[name] === null || newObj[name] === "")) {
errors.push(this.Fields && this.Fields[name] && this.Fields[name].DisplayName ? this.Fields[name].DisplayName : name);
hasError = true;
this.CurrentFields[name].Parent.className += " fieldError";
}
}
if (!hasError) {
this.CurrentFields[name].Parent.className = this.CurrentFields[name].Parent.className.replace("fieldError", "");
}
}
}
return newObj;
},
RenderErrors: function (errors, textBefore) {
if (this.Elements.ErrorText) {
this.Elements.ErrorText.innerHTML = textBefore + errors.join(", ");
} else {
this.Add({ innerHTML: textBefore + errors.join(", "), className: "validationError" }, "ErrorText");
}
},
onsubmit: function () {
if (this.IsCurrentlySubmitting)
return false;
this.IsCurrentlySubmitting = true;
var obj = this;
var errors = [];
var newObj = this.GetModel(errors);
if (errors.length == 0) {
if (this.CustomValidation) {
this.CustomValidation(newObj, function (customErrors) {
obj.IsCurrentlySubmitting = false;
if (!customErrors || customErrors.length == 0) {
obj.Save(newObj);
} else {
obj.RenderErrors(customErrors, "");
}
if (obj.SubmitResult)
obj.SubmitResult(!customErrors || customErrors.length == 0, customErrors);
});
} else {
this.IsCurrentlySubmitting = false;
this.Save(newObj);
if (this.SubmitResult)
this.SubmitResult(true, errors);
}
} else {
this.RenderErrors(errors, this.RequiredText);
this.IsCurrentlySubmitting = false;
if (this.SubmitResult)
this.SubmitResult(false, errors);
}
this.LastErrors = errors;
return false;
}
};
"use strict";
window.TK.Navigator = {
_: "div",
DefaultHash: "index",
Seperator: "/",
Current: null,
CurrentElement: null,
UseTemplates: false,
Init: function () {
var obj = this;
if (this.Templates) {
this.UseTemplates = true;
}
this.onHashChangeHandler = function () {
obj.Handle();
};
window.addEventListener("hashchange", this.onHashChangeHandler);
if (this.NavigatorLevel === undefined) {
this.NavigatorLevel = 0;
var parent = this.Parent;
while (parent) {
if (parent.DefaultHash) {
// This is a navigator
this.NavigatorLevel++;
}
parent = parent.Parent;
}
}
this.Handle();
},
Destroy: function () {
window.removeEventListener("hashchange", this.onHashChangeHandler);
},
Handle: function () {
var navigateTo = window.location.hash;
if (navigateTo == "")
navigateTo = this.DefaultHash;
else
navigateTo = navigateTo.substr(1);
var pagePart = decodeURIComponent(navigateTo).split(this.Seperator);
if (pagePart.length <= this.NavigatorLevel) {
pagePart.push(this.DefaultHash);
}
if (this.UseTemplates) { // Add new element, and destroy old elements (Slower, less memory usage)
if (pagePart[this.NavigatorLevel] != this.Current) {
if (this.CurrentElement) {
this.CurrentElement.Remove();
}
this.Current = pagePart[this.NavigatorLevel];
if (this.Templates[this.Current]) {
this.CurrentElement = this.Add(this.Templates[this.Current], "current");
}
}
} else { // Just hide/show elements (Faster, but more memory usage)
this.CurrentElement = null;
for (var elementName in this.Elements) {
if (elementName != pagePart[this.NavigatorLevel] && this.Elements[elementName].style && this.Elements[elementName].style.display != "none")
this.Elements[elementName].style.display = "none";
else if (elementName == pagePart[this.NavigatorLevel]) {
this.CurrentElement = this.Elements[elementName];
if (this.Elements[elementName].style && this.Elements[elementName].style.display != "")
this.Elements[elementName].style.display = "";
}
}
}
this.Current = pagePart[this.NavigatorLevel];
pagePart.splice(0, this.NavigatorLevel + 1);
if (this.CurrentElement && this.CurrentElement.Navigate) {
this.CurrentElement.Navigate(pagePart);
}
if (this.Navigate)
this.Navigate(this.Current);
},
Navigate: function (newPage) { }
};"use strict";
window.TK.Page = {
_: "div",
Url: "",
Post: null,
IsTemplate: false,
Template: null,
ExecuteScripts: true,
ChangeForms: true,
AjaxSettings: {},
State: null,
Init: function () {
var obj = this;
this.ajaxCallBack = function (response) {
if (response && response.substr(0, 1) == "{") {
// Response is a template
var template = eval('(' + response + ')');
if (obj.Template) {
obj.Template._ = template;
obj.Add(obj.Template, "page");
} else {
obj.Add(template, "page");
}
} else {
obj.innerHTML = response;
if (obj.ExecuteScripts) {
Ajax.executeScripts(response);
}
if (obj.ChangeForms) {
var allForms = obj.querySelectorAll("form");
for (var i = 0; i < allForms.length; i++) {
allForms[i].onsubmit = function () {
Ajax.doAjaxFormSubmit(this, obj.ajaxCallBack);
return false;
};
}
}
}
if (obj.Update) {
obj.Update();
}
};
if (this.Url) {
Ajax.do(this.Url, this.Post, this.ajaxCallBack, undefined, this.AjaxSettings);
}
},
Refresh: function () {
if (this.Elements.page) {
this.Elements.page.Remove();
}
this.innerHTML = "";
this.Init();
},
Update: function () { }
};"use strict";
window.TK.Popup = {
_: "div",
_Tag: "ToolkitPopup",
Width: 400,
Height: 500,
MinWidth: 150,
MinHeight: 150,
Title: "Popup",
EnableCloseButton: true,
EnableBackDrop: false,
CloseWithEscapeButton: false,
CloseByClickingOutsideOfPopup: false,
EnableResize: true,
EnableSnapping: true,
Maximized: false,
className: "toolkitPopup",
Template: {},
OnResize: function () { },
Buttons: null, // { Ok: function() { alert('ok pressed!'); } }
Init: function () {
var obj = this;
this.style.position = "fixed";
this.CenterWindow();
this.RestoreBodyOverflow = function () {
if (obj.OrigBodyOverflow) {
document.body.style.overflow = obj.OrigBodyOverflow;
obj.OrigBodyOverflow = null;
}
};
this.Add({
_: "h2",
Elements: {
TitleSpan: {
innerText: this.Title
}
},
onselectstart: function () { return false; },
ondblclick: function () {
if (!obj.EnableResize)
return;
if (obj.Maximized) {
obj.Maximized = false;
obj.RestoreBodyOverflow();
obj.style.left = obj.OldCords[0] + "px";
obj.style.top = obj.OldCords[1] + "px";
obj.style.width = obj.OldCords[2] + "px";
obj.style.height = obj.OldCords[3] + "px";
} else {
obj.Maximized = true;
obj.OrigBodyOverflow = document.body.style.overflow;
if (!obj.OrigBodyOverflow)
obj.OrigBodyOverflow = "initial";
document.body.style.overflow = "hidden";
obj.OldCords = [obj.offsetLeft, obj.offsetTop, obj.offsetWidth, obj.offsetHeight];
obj.style.left = "0px";
obj.style.top = "0px";
obj.style.width = window.innerWidth + "px";
obj.style.height = window.innerHeight + "px";
}
if (obj.OnResize) {
obj.OnResize();
}
},
ontouchstart: function (e) {
this.onmousedown(e.touches[0]);
e.stopPropagation();
},
onmousedown: function (e) {
var x, y;
try { x = e.pageX; y = e.pageY; } catch (errie) { var e2 = window.event; x = e2.clientX; y = e2.clientY; }
var startX = x - obj.offsetLeft;
var startY = y - obj.offsetTop;
var startWidth = obj.offsetWidth;
var startHeight = obj.offsetHeight;
var snapXSides = [0, window.innerWidth];
var snapYSides = [0, window.innerHeight];
if (obj.EnableSnapping) {
var allPopups = document.querySelectorAll(".toolkitPopup");
for (var i = 0; i < allPopups.length; i++) {
if (allPopups[i] == obj || !allPopups[i].parentNode)
continue;
snapXSides.push(allPopups[i].offsetLeft - 2);
snapXSides.push(allPopups[i].offsetLeft + allPopups[i].offsetWidth);
snapYSides.push(allPopups[i].offsetTop);
snapYSides.push(allPopups[i].offsetTop + allPopups[i].offsetHeight);
}
}
window.onmousemove = function (e) {
if (obj.Maximized) {
obj.Maximized = false;
obj.style.left = obj.OldCords[0] + "px";
obj.style.top = obj.OldCords[1] + "px";
obj.style.width = obj.OldCords[2] + "px";
obj.style.height = obj.OldCords[3] + "px";
obj.RestoreBodyOverflow();
}
var x, y;
try { x = e.pageX; y = e.pageY; } catch (errie) { var e2 = window.event; x = e2.clientX; y = e2.clientY; }
var newLeft = (x - startX);
var newTop = (y - startY);
if (obj.EnableSnapping) {
for (var i = 0; i < snapXSides.length; i++) {
if (Math.abs(snapXSides[i] - newLeft) < 10) {
newLeft = snapXSides[i];
} else if (Math.abs(snapXSides[i] - (newLeft + startWidth)) < 10) {
newLeft = snapXSides[i] - startWidth;
}
}
for (var i = 0; i < snapYSides.length; i++) {
if (Math.abs(snapYSides[i] - newTop) < 10) {
newTop = snapYSides[i];
} else if (Math.abs(snapYSides[i] - (newTop + startHeight)) < 10) {
newTop = snapYSides[i] - startHeight;
}
}
}
obj.style.left = newLeft + "px";
obj.style.top = newTop + "px";
};
window.onmouseup = function () {
window.onmousemove = null;
window.onmouseup = null;
window.onselectstart = null;
window.ontouchmove = null;
window.ontouchend = null;
};
window.ontouchmove = function (e) {
if (window.onmousemove)
window.onmousemove(e.touches[0]);
e.stopPropagation();
};
window.ontouchend = function (e) {
if (window.onmouseup)
window.onmouseup();
e.stopPropagation();
};
window.onselectstart = function () { return false; };
if (e && e.preventDefault)
e.preventDefault();
else
window.event.returnValue = false;
}
}, "PopupTitle");
if (this.EnableResize) {
this.Add({
_: "button",
innerHTML: "",
onselectstart: function () { return false; },
ontouchstart: function (e) {
this.onmousedown(e.touches[0]);
e.stopPropagation();
},
onmousedown: function (e) {
var x, y;
try { x = e.pageX; y = e.pageY; } catch (errie) { var e2 = window.event; x = e2.clientX; y = e2.clientY; }
var startX = x;
var startY = y;
var startWidth = obj.offsetWidth;
var startHeight = obj.offsetHeight;
window.onselectstart = function () { return false; };
window.onmousemove = function (e) {
obj.Maximized = false;
obj.RestoreBodyOverflow();
var x, y;
try { x = e.pageX; y = e.pageY; } catch (errie) { var e2 = window.event; x = e2.clientX; y = e2.clientY; }
var newWidth = startWidth + (x - startX);
if (newWidth < obj.MinWidth)
newWidth = obj.MinWidth;
var newHeight = startHeight + (y - startY);
if (newHeight < obj.MinWidth)
newHeight = obj.MinWidth;
obj.style.width = newWidth + "px";
obj.style.height = newHeight + "px";
window.onmouseup = function () {
window.onmousemove = null;
window.onselectstart = null;
window.ontouchmove = null;
window.ontouchend = null;
if (obj.OnResize) {
obj.OnResize();
}
};
if (e && e.preventDefault)
e.preventDefault();
else
window.event.returnValue = false;
};
window.ontouchmove = function (e) {
if (window.onmousemove)
window.onmousemove(e.touches[0]);
e.stopPropagation();
};
window.ontouchend = function (e) {
if (window.onmouseup)
window.onmouseup();
e.stopPropagation();
};
}
}, "ResizeButton");
}
if (this.EnableCloseButton) {
this.Add({
_: "button",
innerHTML: "x",
onclick: function () {
this.Parent.Remove();
}
}, "CloseButton");
}
if (this.Buttons) {
var buttonBar = {
className: "toolkitButtonBar",
Elements: {}
};
this.className += " toolkitPopupWithButtonBar";
for (var name in this.Buttons) {
if (typeof this.Buttons[name] === 'function') {
this.Buttons[name] = {
Click: this.Buttons[name]
};
}
buttonBar.Elements[name + "Button"] = {
_: this.Buttons[name],
ButtonName: name,
Init: function () {
this.appendChild(document.createTextNode(this.Text ? this.Text : this.ButtonName));
},
onclick: function () {
var cancelClosePopup = false;
if (this.Click)
cancelClosePopup = this.Click();
if (!cancelClosePopup)
this.Parent.Parent.Remove();
}
};
}
this.Add(buttonBar, "ButtonBar");
}
this.Add(this.Template, "Content");
if (this.EnableBackDrop) {
this.BackDrop = document.createElement("DIV");
this.BackDrop.className = "toolkitPopupBackDrop";
this.BackDrop.style.position = "fixed";
this.BackDrop.style.top = "0px";
this.BackDrop.style.right = "0px";
this.BackDrop.style.bottom = "0px";
this.BackDrop.style.left = "0px";
this.BackDrop.style.zIndex = (window.TK.Popup.StartZIndex++);
if (this.CloseByClickingOutsideOfPopup) {
this.BackDrop.onclick = function () {
obj.Remove();
}
};
if (this.CloseWithEscapeButton) {
obj.Keydown = function (evt) {
if (evt && evt.key === 'Escape' && obj != null) {
obj.Remove();
}
};
document.addEventListener('keydown', obj.Keydown)
};
document.body.appendChild(this.BackDrop);
}
this.style.zIndex = (window.TK.Popup.StartZIndex++);
document.body.appendChild(this); // Move myself to the body element
if (this.Maximized || window.innerWidth < this.Width || window.innerHeight < this.Height) {
this.Maximized = false;
this.Elements.PopupTitle.ondblclick();
}
},
Destroy: function () {
if (this.BackDrop) {
this.BackDrop.parentNode.removeChild(this.BackDrop);
}
if (this.Keydown) {
document.removeEventListener('keydown', this.Keydown);
}
this.RestoreBodyOverflow();
},
onmousedown: function () {
this.style.zIndex = (window.TK.Popup.StartZIndex++);
},
CenterWindow: function () {
this.style.width = this.Width + "px";
this.style.height = this.Height + "px";
this.style.top = Math.round((window.innerHeight / 2) - (this.Height / 2)) + "px";
this.style.left = Math.round((window.innerWidth / 2) - (this.Width / 2)) + "px";
}
};
window.TK.Popup.StartZIndex = 10000;
window.TK.PopupOpen = function (template, title, width, height) {
TK.Initialize({
_: TK.Popup,
Width: width ? width : 600,
Height: height ? height : 500,
Title: title,
Template: template
});
};
"use strict";
/* Minify Skip */
/* Minify Order(100) */
// Component to send and receive messages in a public channel, this will try to use WebSockets or fall back to https requests to the toolkit api
TK.ServerChannel = {
_: "component",
Channels: [],
ClientId: "Client" + (Math.random() * 100000) + "-" + (Math.random() * 100000) + "-" + (Math.random() * 100000) + "-" + (Math.random() * 100000), // Not visible for other connected client
Receive: function (channel, identity, data) { },
Connection: null,
Init: function () {
if (!TK.ServerChannel.Connections)
TK.ServerChannel.Connections = {};
if (!TK.ServerChannel.Connections[this.ClientId]) {
// Create connection
TK.ServerChannel.Connections[this.ClientId] = TK.Initialize({
_: TK.ServerChannelConnection,
ClientId: this.ClientId,
Channels: this.Channels.slice(0),
UsedBy: [this],
Receive: function (channel, identity, data) {
for (var i = 0; i < this.UsedBy.length; i++) {
if (this.UsedBy[i].Channels.indexOf(channel) >= 0)
this.UsedBy[i].Receive(channel, identity, data);
}
}
});
} else {
// Use existing connection
TK.ServerChannel.Connections[this.ClientId].UsedBy.push(this);
for (var i = 0; i < this.Channels.length; i++) {
TK.ServerChannel.Connections[this.ClientId].AddChannel(this.Channels[i]);
}
}
this.Connection = TK.ServerChannel.Connections[this.ClientId];
},
Destroy: function () {
while (this.Channels.length > 0)
this.RemoveChannel(this.Channels[0]);
this.Connection.UsedBy.splice(this.Connection.UsedBy.indexOf(this), 1);
if (this.Connection.UsedBy.length == 0)
this.Connection.Remove();
},
Send: function (channel, data) {
this.Connection.Send(channel, data);
},
AddChannel: function (channel) {
if (this.Channels.indexOf(channel) >= 0)
return;
this.Channels.push(channel);
this.Connection.AddChannel(channel);
},
RemoveChannel: function (channel) {
if (this.Channels.indexOf(channel) < 0)
return;
this.Channels.splice(this.Channels.indexOf(channel), 1);
// Check if used by other ServerChannel objects
for (var i = 0; i < this.Connection.UsedBy.length; i++) {
if (this.Connection.UsedBy[i].Channels.indexOf(channel) >= 0)
return;
}
// Not used anymore, leave channel
this.Connection.RemoveChannel(channel);
}
};
// Shared component, this will be used by (multiple) TK.ServerChannel objects
TK.ServerChannelConnection = {
_: "component",
Channels: [],
ClientId: null, // Not visible for other connected client
UrlFallback: "https://toolkitapi.comgenie.com/Channel/Communicate",
UrlWebsocket: "wss://toolkitapi.comgenie.com/ws",
FallbackInterval: 5000,
Receive: function (channel, identity, data) { },
ChannelIndexes: [], // used internally for fallback method
Init: function () {
if (this.ClientId == null)
return;
if (this.UrlWebsocket)
this.CreateWebsocket();
else
this.CreateFallback();
},
Destroy: function () {
// Disconnect communication
if (this.WebSocket)
this.WebSocket.close();
if (this.FallBackTimeout) {
clearTimeout(this.FallBackTimeout);
this.FallBackTimeout = null;
}
},
CreateWebsocket: function () {
var obj = this;
var webSocket = new WebSocket(this.UrlWebsocket);
webSocket.SendData = function (command, data) {
//console.log("Send data: " + command, data);
this.send(command + "|" + data.length + "|" + data);
};
webSocket.onopen = function (eventData) {
//console.log("WS Open", eventData);
obj.WebSocket = this;
this.SendData("ID", obj.ClientId);
for (var i = 0; i < obj.Channels.length; i++)
this.SendData("JOIN", obj.Channels[i]);
};
webSocket.onmessage = function (eventData) {
if (!eventData.data.substr)
return;
//console.log("WS Receive", eventData.data);
var firstSeperator = eventData.data.indexOf("|");
if (firstSeperator < 0)
return;
var secondSeperator = eventData.data.indexOf("|", firstSeperator + 1);
if (secondSeperator < 0)
return;
var command = eventData.data.substr(0, firstSeperator);
var dataLength = eventData.data.substring(secondSeperator + 1, secondSeperator);
var payload = eventData.data.substr(secondSeperator + 1);
if (command == "MSG") {
var msg = JSON.parse(payload);
console.log(msg);
obj.Receive(msg.Channel, msg.Identity, msg.Data);
}
};
webSocket.onerror = function (eventData) {
// Couldn't connect
//console.log("WS Error", eventData);
obj.CreateFallback();
};
webSocket.onclose = function (eventData) {
// Disconnected
//console.log("WS Close", eventData)
obj.CreateFallback();
};
},
CreateFallback: function () {
console.log("Using fallback");
this.WebSocket = null; // TODO: See if we can reconnect
this.SendFallBack(null, null); // Send first check message, this activates the interval as well
},
AddChannel: function (channel) {
if (this.Channels.indexOf(channel) >= 0)
return;
this.Channels.push(channel);
this.ChannelIndexes.push(-1);
if (this.WebSocket)
this.WebSocket.SendData("JOIN", channel);
},
RemoveChannel: function (channel) {
var channelIndex = this.Channels.indexOf(channel);
if (channelIndex < 0)
return;
this.Channels.splice(channelIndex, 1);
this.ChannelIndexes.splice(channelIndex, 1);
if (this.WebSocket)
this.WebSocket.SendData("LEAVE", channel);
},
SendFallBack: function (channel, data) {
if (this.FallBackTimeout) {
clearTimeout(this.FallBackTimeout);
this.FallBackTimeout = null;
}
var obj = this;
var channelsArr = [];
var indexesArr = [];
for (var i = 0; i < this.Channels.length; i++) {
channelsArr.push(this.Channels[i]);
indexesArr.push(this.ChannelIndexes[i] !== undefined ? this.ChannelIndexes[i] : -1);
}
Ajax.do(this.UrlFallback, { clientId: this.ClientId, channels: channelsArr, indexes: indexesArr, sendChannel: channel, sendData: data }, function (responseObj) {
//console.log("Fallback response", responseObj);
for (var i = 0; i < responseObj.length; i++) {
if (!responseObj[i].channel)
continue;
var arrChannelIndex = obj.Channels.indexOf(responseObj[i].channel);
if (arrChannelIndex < 0) // Unsubscribed before callback was received
continue;
for (var j = 0; j < responseObj[i].messages.length; j++) {
obj.Receive(responseObj[i].channel, responseObj[i].messages[j].identity, responseObj[i].messages[j].data);
}
// Update our index so we can prevent double-messages
if (responseObj[i].index != 0)
obj.ChannelIndexes[arrChannelIndex] = responseObj[i].index;
}
});
this.FallBackTimeout = setTimeout(function () {
obj.SendFallBack(null, null);
}, this.FallbackInterval);
},
Send: function (channel, data) {
if (this.WebSocket)
this.WebSocket.SendData("MSG", JSON.stringify({ Channel: channel, Data: data }));
else if (this.UrlFallback)
this.SendFallBack(channel, data);
}
};"use strict";
/* Minify Skip */
/* Minify Order(100) */
// Component to save and retrieve files, using the Toolkit API
// This component has the same methods as TK.ClientStorage
TK.ServerStorage = {
_: "component",
Container: null, // null is only for public file storage/retrieval, use a https:// link for a private storage container with rights check based on the clientId
ClientId: "Client" + (Math.random() * 100000) + "-" + (Math.random() * 100000) + "-" + (Math.random() * 100000) + "-" + (Math.random() * 100000), // Used for private containers
Url: "https://toolkitapi.comgenie.com/Storage",
Store: function (path, blobOrByteArrayOrStringContents, callBack) {
var formData = new FormData();
var url = "?clientId=" + encodeURIComponent(this.ClientId) + (this.Container ? "&container=" + encodeURIComponent(this.Container) : "");
if (path)
url += "&fileName=" + encodeURIComponent(path);
if ((window.Blob && blobOrByteArrayOrStringContents instanceof Blob) || (window.File && blobOrByteArrayOrStringContents instanceof File)) {
formData.append("files", blobOrByteArrayOrStringContents);
} else if ((window.Uint8Array && blobOrByteArrayOrStringContents instanceof Uint8Array) || (window.Uint16Array && blobOrByteArrayOrStringContents instanceof Uint16Array)) {
formData.append("files", new Blob(blobOrByteArrayOrStringContents));
} else if (blobOrByteArrayOrStringContents.substr && blobOrByteArrayOrStringContents.length && blobOrByteArrayOrStringContents.length > 10 && blobOrByteArrayOrStringContents.substr(0, 5) == "data:") {
var blob = new Blob(atob(blobOrByteArrayOrStringContents.split(',')[1])); // Convert base64 data url to blob
formData.append("files", blob);
} else { // string
if (!blobOrByteArrayOrStringContents.substr)
blobOrByteArrayOrStringContents = blobOrByteArrayOrStringContents.toString();
var buf = new ArrayBuffer(blobOrByteArrayOrStringContents.length * 2); // 2 bytes for each char
var bufView = new Uint16Array(buf);
for (var i = 0; i < blobOrByteArrayOrStringContents.length; i++)
bufView[i] = blobOrByteArrayOrStringContents.charCodeAt(i);
formData.append("files", new Blob(bufView));
}
Ajax.do(this.Url + "/Store" + url, formData, function (response) {
if (!callBack)
return;
if (response.length && response.length > 0 && response[0].url)
callBack(response[0]);
else
callBack();
}, null, { parseJSONResponse: true });
},
Retrieve: function (path, asBlob, callBack) {
Ajax.do(this.Url + "/Retrieve", { clientId: this.ClientId, container: this.Container, fileName: path, directly: true }, function (contents) {
if (callBack)
callBack(contents);
}, null, { parseJSONResponse: false, responseType: (asBlob ? "blob" : undefined) });
},
GetUrl: function (path, callBack) {
Ajax.do(this.Url + "/Retrieve", { clientId: this.ClientId, container: this.Container, fileName: path }, function (fileData) {
if (!callBack)
return;
if (fileData.Url)
callBack(fileData.Url);
else {
console.log(fileData);
callBack();
}
});
},
Delete: function (path, callBack) {
Ajax.do(this.Url + "/Delete", { clientId: this.ClientId, container: this.Container, fileName: path }, function (result) {
if (callBack)
callBack(result == "OK");
});
},
List: function (callBack) {
Ajax.do(this.Url + "/List", { clientId: this.ClientId, container: this.Container }, function (files) {
if (!callBack)
return;
if (files && files.length > 0 && files[0].url)
callBack(files);
else {
console.log(files);
callBack();
}
});
},
};
"use strict";
// Sortable table
window.TK.Table = {
_: "table",
className: "toolkitTable",
EnableSort: true,
EnableFilter: false,
EnableTotals: false,
DisableFilterForColumns: [],
ThresholdFilterMultiselect: 15,
EnableCheckBoxes: false,
EnableFullRowCheckBoxToggle: false,
EnableFullRowClickDeselectOthers: false,
EnableSelectAllCheckBox: true,
EnableRemoveButton: false,
EnablePartialInit: false, // TODO: Only add rows as TR elements which are currently visible
PageSize: null,
PageOffset: 0,
SpecificColumns: null,
ColumnTitles: {},
Templates: {},
HeaderTemplates: {},
SortedBy: null,
SortedDesc: false,
SortCallBack: null,
FilterCallBack: null,
MaxRows: null,
CurrentFilter: null,
DefaultTemplate: {
_: "td",
Data: null,
Init: function () { this.appendChild(document.createTextNode(this.Data)); }
},
CheckBoxTemplate: {
_: "td",
Data: null,
onclick: function (event) {
if (event)
event.stopPropagation();
if (window.event)
window.event.cancelBubble = true;
return true;
},
Elements: {
CheckBox: {
_: "input",
type: "checkbox",
className: "tableRowCheckBox",
onclick: function (event) {
this.Parent.Table.LastCheckBoxRange = null;
if (event.shiftKey && this.Parent.Table.PreviousCheckBox) {
// Select everything in between
this.Parent.Table.LastCheckBoxRange = [];
var curIndex = this.Parent.Parent.RowIndex;
var otherIndex = this.Parent.Table.PreviousCheckBox.Parent.Parent.RowIndex;
for (var i = curIndex; i != otherIndex; i = (curIndex < otherIndex ? i + 1 : i - 1)) {
var checkBoxElement = this.Parent.Table.querySelectorAll(".Element-row" + i + " input[type=checkbox].tableRowCheckBox")[0];
if (checkBoxElement.Parent.Parent.style.display == "none")
continue; // Skip filtered rows
if (checkBoxElement.checked != this.Parent.Table.PreviousCheckBox.checked) {
this.Parent.Table.LastCheckBoxRange.push(checkBoxElement.Parent.Row);
checkBoxElement.checked = this.Parent.Table.PreviousCheckBox.checked;
}
checkBoxElement.UpdateData();
}
}
},
onblur: function () {
this.Parent.Table.PreviousCheckBox = this;
},
onchange: function (event) {
this.UpdateData();
if (this.Parent.Table.EnableSelectAllCheckBox) {
var selectAll = this.Parent.Table.querySelectorAll(".tableSelectAllCheckBox")[0];
if (selectAll) {
var checkBoxElements = this.Parent.Table.Elements.tbody.Elements.ToArray()
.Where(function (a) { return a.Elements.CheckBoxes && a.Elements.CheckBoxes.Elements.CheckBox && a.style.display != "none"; })
.Select(function (a) { return a.Elements.CheckBoxes.Elements.CheckBox });
selectAll.checked = checkBoxElements.length == this.Parent.Table.SelectedRows().length;
}
}
if (this.Parent.Table.CheckboxCheck) {
if (!this.Parent.Table.LastCheckBoxRange) {
this.Parent.Table.CheckboxCheck([this.Parent.Row], this.checked);
} else {
if (this.Parent.Table.LastCheckBoxRange.indexOf(this.Parent.Row) < 0)
this.Parent.Table.LastCheckBoxRange.push(this.Parent.Row);
this.Parent.Table.CheckboxCheck(this.Parent.Table.LastCheckBoxRange, this.checked);
}
}
this.Parent.Table.LastCheckBoxRange = null;
},
UpdateData: function () {
this.Parent.Row["CheckBoxes"] = this.checked;
},
Init: function () {
this.checked = this.Parent.Data === true;
}
}
}
},
RemoveButtonTemplate: {
_: "td",
Data: null,
onclick: function (event) {
if (event)
event.stopPropagation();
if (window.event)
window.event.cancelBubble = true;
return true;
},
Elements: {
RemoveButton: {
_: "button",
innerHTML: "Remove",
onclick: function (event) {
// Find with button clicked and delete it from Rows variable in the table
var table = this.Parent.Table;
var thisRow = this.Parent.Parent.Row;
// When the row was succesfully deleted in the save function remove current row
if (table.Save(thisRow, true) !== false) {
for (var i = 0; i < table.Rows.length; i++) {
if (table.Rows[i] == thisRow) {
table.Rows.splice(i, 1);
break;
}
}
var thisRowNode = this.Parent.Parent;
// When the user was editing the row a form is showing on the next row. When this is the case remove that form as well.
if (thisRowNode.subTr)
thisRowNode.subTr.Remove();
thisRowNode.Remove();
}
}
}
}
},
PreviousCheckBox: null,
Rows: [],
Form: null,
FormAlwaysLoaded: false, // If true, the subViews are initialized directly, but shown/hidden using style.display
Init: function () {
if (this.SortedBy && this.Rows && this.Rows.OrderBy) {
var sortedBy = this.SortedBy;
this.Rows = this.SortedDesc ? this.Rows.OrderByDesc(function (a) { return a[sortedBy]; }) : this.Rows.OrderBy(function (a) { return a[sortedBy]; });
}
this.Refresh();
},
RowClick: function (rowObj, trElement) {
var obj = this;
if (this.Form) {
if (!trElement) { // Optional parameter, Find the TR element based on the given row Obj
if (!this.Elements.tbody)
return;
for (var rowId in this.Elements.tbody.Elements) {
var row = this.Elements.tbody.Elements[rowId];
if (row.Row == rowObj) {
trElement = row;
break;
}
}
if (!trElement)
return;
}
if (obj.FormAlwaysLoaded) {
if (trElement.subTr) {
trElement.subTr.style.display = trElement.subTr.style.display == "" ? "none" : "";
return;
}
} else {
if (trElement.subTr) {
trElement.subTr.parentNode.removeChild(trElement.subTr);
trElement.subTr = null;
return;
}
}
var template = {
_: obj.Form,
Model: rowObj,
ApplyToModelDirectly: true,
};
if (obj.Form.Save == undefined) {
template.Save = function (model) {
obj.Save(model, false);
obj.UpdateRow(trElement);
};
}
if (obj.Form.ApplyToModelDirectly == undefined) {
template.ApplyToModelDirectly = true;
}
this.OpenViewForRow(trElement, template);
}
},
RowDoubleClick: function (rowObj, trElement) { },
Save: function (rowObj, isRemoved) {
// Only used when the Form property is given
},
OpenViewForRow: function (trElement, template) {
if (!template || trElement.subTr)
return;
var childElements = trElement.Elements.ToArray();
var tds = 0;
for (var i = 0; i < childElements.length; i++) {
tds += childElements[i].colSpan ? parseInt(childElements[i].colSpan) : 1;
}
trElement.subTr = trElement.Parent.Add(
{
_: "tr",
ThisIsASubTR: true,
Destroy: function () {
trElement.subTr = null;
},
Elements: {
Editor: {
_: "td",
className: "subView",
colSpan: tds,
Elements: {
View: template
}
}
}
});
trElement.parentNode.insertBefore(trElement.subTr, trElement.nextSibling);
},
CheckboxCheck: function (rowsChanged, isChecked) { },
SelectedRows: function () {
if (!this.EnableCheckBoxes)
return [];
return this.Elements.tbody.Elements.ToArray()
.Where(function (a) { return a.Elements.CheckBoxes && a.Elements.CheckBoxes.Elements.CheckBox && a.Elements.CheckBoxes.Elements.CheckBox.checked; })
.Select(function (a) { return a.Row });
},
ApplyFilter: function (filter, skipCallback) {
this.CurrentFilter = filter == null ? "" : filter.toLowerCase ? filter.toLowerCase() : filter;
if (this.FilterCallBack && !skipCallback) {
this.FilterCallBack();
return;
}
if (!this.Elements.tbody) {
return;
}
if (this.Elements.thead && this.ColumnFilter) {
for (var name in this.ColumnFilter) {
if (this.Elements.thead.Elements.tr.Elements[name]) {
this.Elements.thead.Elements.tr.Elements[name].className = this.ColumnFilter[name] ? "toolkitHasFilter" : "";
}
}
}
this.Elements.tbody.style.display = "none"; // This prevents row style changes to cause render updates, making it a lot faster
var rows = 0;
for (var rowId in this.Elements.tbody.Elements) {
var row = this.Elements.tbody.Elements[rowId];
if (!row.innerText || row.ThisIsASubTR)
continue;
if (this.MaxRows != null && rows >= this.MaxRows) {
row.style.display = "none";
if (row.subTr)
row.subTr.style.display = "none";
continue;
}
if (row.subTr && row.subTr.Elements && row.subTr.Elements.Editor && row.subTr.Elements.Editor.Elements && row.subTr.Elements.Editor.Elements.View && row.subTr.Elements.Editor.Elements.View.IsVisible && row.subTr.Elements.Editor.Elements.View.IsVisible(this.CurrentFilter)) {
// The subTr wants to be visible, so we'll also make the parent row visible
row.style.display = "";
row.subTr.style.display = "";
rows++;
continue;
}
if (this.CurrentFilter == "" || this.CurrentFilter == null || !row.innerText || (this.CurrentFilter && this.CurrentFilter.toLowerCase && row.innerText.toLowerCase().indexOf(this.CurrentFilter) >= 0) || (this.CurrentFilter && !this.CurrentFilter.toLowerCase && this.CurrentFilter(row.Row, row))) {
row.style.display = "";
if (row.subTr)
row.subTr.style.display = "";
rows++;
} else {
row.style.display = "none";
if (row.subTr)
row.subTr.style.display = "none";
}
if (this.PageSize != null && ((rows - 1) < this.PageOffset || (rows-1) >= this.PageOffset + this.PageSize)) {
row.style.display = "none";
if (row.subTr)
row.subTr.style.display = "none";
continue;
}
}
this.Elements.tbody.style.display = "";
this.VisibleRowCount = rows;
var ttnc = this.Near(".toolkitTableNavigationContainer");
if (ttnc)
ttnc.Init();
return rows;
},
Refresh: function () {
var obj = this;
this.Clear();
this.PreviousCheckBox = null;
if (this.Rows.length == 0) {
return;
}
// Build header
var thead = {
_: "thead",
Elements: {
tr: {
_: "tr",
Elements: {}
}
}
};
var columns = [];
if (this.EnableCheckBoxes) {
columns.push("CheckBoxes");
if (!this.DisableFilterForColumns)
this.DisableFilterForColumns = [];
if (this.DisableFilterForColumns.indexOf("CheckBoxes") < 0)
this.DisableFilterForColumns.push("CheckBoxes");
this.ColumnTitles["CheckBoxes"] = " ";
this.Templates["CheckBoxes"] = this.CheckBoxTemplate;
if (this.EnableSelectAllCheckBox) {
this.HeaderTemplates["CheckBoxes"] = {
_: "th",
Init: function () {
var selectAllCheckBox = this.Add({
_: "input",
type: "checkbox",
className: "tableSelectAllCheckBox",
onclick: function (event) {
if (event)
event.stopPropagation();
if (window.event)
window.event.cancelBubble = true;
},
onchange: function (event) {
var checkBoxElements = obj.Elements.tbody.Elements.ToArray()
.Where(function (a) { return a.Elements.CheckBoxes && a.Elements.CheckBoxes.Elements.CheckBox && a.style.display != "none"; })
.Select(function (a) { return a.Elements.CheckBoxes.Elements.CheckBox });
var changedRange = [];
for (var i = 0; i < checkBoxElements.length; i++) {
if (checkBoxElements[i].checked != this.checked) {
changedRange.push(checkBoxElements[i].Parent.Row);
checkBoxElements[i].checked = this.checked;
}
checkBoxElements[i].UpdateData();
}
if (obj.CheckboxCheck)
obj.CheckboxCheck(changedRange, this.checked);
}
});
// See if all rows are already selected
var totalRowsChecked = 0;
for (; totalRowsChecked < obj.Rows.length; totalRowsChecked++) {
if (!obj.Rows[totalRowsChecked]["CheckBoxes"])
break;
}
if (totalRowsChecked > 0 && totalRowsChecked == obj.Rows.length)
selectAllCheckBox.checked = true;
}
};
} else {
this.HeaderTemplates["CheckBoxes"] = null;
}
}
if (this.SpecificColumns && this.SpecificColumns.length > 0) {
columns = columns.concat(this.SpecificColumns);
} else {
for (var name in this.Rows[0]) {
columns.push(name);
}
}
if (this.EnableRemoveButton) {
columns.push("RemoveButtons");
this.ColumnTitles["RemoveButtons"] = " ";
this.Templates["RemoveButtons"] = this.RemoveButtonTemplate;
}
for (var i = 0; i < columns.length; i++) {
var name = columns[i];
thead.Elements.tr.Elements[name] = {
_: this.HeaderTemplates && this.HeaderTemplates[name] ? this.HeaderTemplates[name] : "th",
innerHTML: (this.ColumnTitles && this.ColumnTitles[name] ? this.ColumnTitles[name] : name),
className: (name == obj.SortedBy ? "sorted" + (this.SortedDesc ? " desc" : "") : ""),
DataColumnName: name,
onclick: function () {
if (!obj.EnableSort)
return;
var thisTh = this;
if (obj.SortedBy == this.DataColumnName) {
obj.Rows = obj.Rows.reverse();
obj.SortedDesc = !obj.SortedDesc;
} else {
obj.Rows = obj.Rows.OrderBy(function (a) {
if (a[thisTh.DataColumnName + "-SortValue"] !== undefined)
return a[thisTh.DataColumnName + "-SortValue"];
return a[thisTh.DataColumnName];
});
obj.SortedDesc = false;
}
obj.SortedBy = this.DataColumnName;
if (obj.SortCallBack) {
obj.SortCallBack();
} else {
obj.Refresh();
}
},
Elements: {}
};
// Enable filter button on column
if (this.EnableFilter && (!this.DisableFilterForColumns || this.DisableFilterForColumns.indexOf(name) < 0 )) {
thead.Elements.tr.Elements[name].Elements.FilterButton = {
className: "toolkitFilterButton",
innerHTML: "v",
onclick: function (event) {
// Open filter window for this column and data type (Slider for numbers, Multiselect for few options, search for many options)
var currentHeader = this.Parent;
var position = this.Parent.getBoundingClientRect();
var filterWindow = {
className: "toolkitFilterBox",
style: {
backgroundColor: "#eee",
left: position.left + "px",
top: position.bottom + "px",
position: "fixed"
},
Elements: {
CloseButton: {
innerHTML: "x",
onclick: function () {
this.Parent.Remove();
obj.ActiveFilterWindow = null;
}
},
Container: {
Init: function () {
var values = [];
for (var i = 0; i < obj.Rows.length; i++) {
var value = obj.Rows[i][currentHeader.DataColumnName];
if (values.indexOf(value) < 0)
values.push(value);
if (values.length >= obj.ThresholdFilterMultiselect) {
break;
}
}
if (!obj.ColumnFilter)
obj.ColumnFilter = {};
var filterFunc = function (rowObj, trObj) {
for (var name in obj.ColumnFilter) {
if (!obj.ColumnFilter[name])
continue;
if (obj.ColumnFilter[name].toLowerCase) { // text match, match if any of the text is in there
var lowerColumnSearch = obj.ColumnFilter[name].toLowerCase();
var foundInFieldValue = rowObj[name] && rowObj[name].toString().toLowerCase().indexOf(lowerColumnSearch) >= 0;
var foundInTdText = trObj.Elements && trObj.Elements[name] && trObj.Elements[name].innerText && trObj.Elements[name].innerText.toLowerCase().indexOf(lowerColumnSearch) >= 0;
if (!foundInFieldValue && !foundInTdText)
return false;
continue;
}
if (Array.isArray(obj.ColumnFilter[name]) && rowObj[name] !== undefined) {
if (obj.ColumnFilter[name].indexOf(rowObj[name]) < 0)
return false;
} else if (obj.ColumnFilter[name] != rowObj[name]) { // match exact, for numbers etc.
return false;
}
}
return true;
};
if (values.length < obj.ThresholdFilterMultiselect) {
// Show multi select
values = values.OrderBy(function (a) { return a; });
var filterTable = {
_: TK.Table,
EnableFilter: false,
Rows: [],
Templates: obj.Templates,
EnableCheckBoxes: true,
ColumnTitles: {},
CheckboxCheck: function () {
var rows = this.SelectedRows();
if (rows.length != this.Rows.length) {
var allowed = [];
for (var i = 0; i < rows.length; i++)
allowed.push(rows[i][currentHeader.DataColumnName]);
obj.ColumnFilter[currentHeader.DataColumnName] = allowed;
} else {
obj.ColumnFilter[currentHeader.DataColumnName] = null;
}
obj.ApplyFilter(filterFunc);
}
};
filterTable.ColumnTitles[currentHeader.DataColumnName] = "Filter";
for (var i = 0; i < values.length; i++) {
var rowObj = {};
rowObj.CheckBoxes = !obj.ColumnFilter || !obj.ColumnFilter[currentHeader.DataColumnName] || (obj.ColumnFilter[currentHeader.DataColumnName].indexOf(values[i]) >= 0);
rowObj[currentHeader.DataColumnName] = values[i];
filterTable.Rows.push(rowObj)
}
this.Add(filterTable);
} else {
// Show search field
var inputElement = this.Add({
_: "input",
value: !obj.ColumnFilter || !obj.ColumnFilter[currentHeader.DataColumnName] ? "" : obj.ColumnFilter[currentHeader.DataColumnName],
onkeyup: function (event) {
obj.ColumnFilter[currentHeader.DataColumnName] = (this.value == "") ? null : this.value;
obj.ApplyFilter(filterFunc);
var x = event.which || event.keyCode;
if (x == 13) {
this.Near("CloseButton").onclick();
}
}
});
setTimeout(function () {
inputElement.focus();
}, 1);
}
}
}
}
};
if (obj.ActiveFilterWindow)
obj.ActiveFilterWindow.Remove();
obj.ActiveFilterWindow = TK.Initialize(filterWindow);
document.body.appendChild(obj.ActiveFilterWindow);
if (event)
event.stopPropagation();
if (window.event)
window.event.cancelBubble = true;
return true;
}
};
}
}
this.TableUseColumns = columns;
// Build contents
var tbody = {
_: "tbody",
Elements: {}
}
this.CurrentAddedRowCount = 0;
this.AddNewRowsToTableBody(tbody);
this.Add(thead, "thead");
var tbodyElement = this.Add(tbody, "tbody");
if (this.FormAlwaysLoaded) {
var trRows = tbodyElement.Elements.ToArray();
for (var i = 0; i < trRows.length; i++) {
this.RowClick(trRows[i].Row, trRows[i]);
if (trRows[i].subTr) {
trRows[i].subTr.style.display = "none";
}
}
}
var tfoot = {
_: "tfoot",
Elements: {}
};
var includeTFoot = false;
if (this.EnableTotals) {
includeTFoot = true;
tfoot.Elements.SubTotals = {
_: "tr",
Elements: {}
};
for (var i = 0; i < columns.length; i++) {
var name = columns[i];
if (name == "CheckBoxes" || name == "RemoveButtons") {
tfoot.Elements.SubTotals.Elements[name] = {
_: "td"
};
continue;
}
var allRowValues = this.Rows.Select(function (a) {
return a[name]
});
var total = null;
for (var j = 0; j < allRowValues.length; j++) {
if (allRowValues[j] !== undefined && allRowValues[j] !== null && allRowValues[j] === +allRowValues[j])
total = (total === null ? 0 : total) + allRowValues[j];
}
if (total === null)
total = "";
tfoot.Elements.SubTotals.Elements[name] = {
_: this.Templates[name] ? this.Templates[name] : this.DefaultTemplate,
className: "totalColumn-" + name,
Data: total,
Values: allRowValues,
Table: this
};
}
}
if (this.MaxRows != null || this.CurrentFilter != null || this.PageSize != null) {
this.ApplyFilter(this.CurrentFilter, true);
includeTFoot = true;
if (this.PageSize) {
tfoot.Elements.NavigationRow = {
_: "tr",
Elements: {
NavigationCell: {
_: "td",
className: "toolkitTableNavigationContainer",
colSpan: columns.length,
Init: function () {
this.Clear();
var pageCount = Math.ceil(obj.VisibleRowCount / obj.PageSize);
var currentPage = Math.floor(obj.PageOffset / obj.PageSize) + 1;
var maxBeforeAfter = 3;
var template = {
_: "button",
className: "toolkitTableNavigation",
disabled: i == currentPage,
innerHTML: i,
onclick: function () {
obj.PageOffset = this.Offset;
obj.Refresh();
}
};
if (currentPage > maxBeforeAfter + 1) {
template.Offset = 0;
template.innerHTML = 1;
this.Add(template);
this.Add({
_: "span", innerHTML: "..."
});
}
for (var i = (currentPage > maxBeforeAfter ? currentPage - maxBeforeAfter : 1); i <= pageCount && i < currentPage + maxBeforeAfter; i++) {
template.Offset = (i - 1) * obj.PageSize;
template.disabled = i == currentPage;
template.innerHTML = i;
this.Add(template);
}
if (currentPage + maxBeforeAfter < pageCount) {
this.Add({
_: "span", innerHTML: "..."
});
template.Offset = (pageCount - 1) * obj.PageSize;
template.innerHTML = pageCount;
this.Add(template);
}
}
}
}
};
}
}
if (includeTFoot)
this.Add(tfoot, "tfoot");
},
AddRow: function (row, rowClick) {
this.Rows.push(row);
if (this.Elements.tbody) {
var tr = this.AddNewRowsToTableBody()[0];
if (!tr) {
this.Refresh();
} else if (rowClick && tr) {
this.RowClick(tr.Row, tr);
return;
}
} else {
this.Refresh();
}
if (rowClick) {
this.RowClick(row);
}
},
UpdateRow: function (trRow) {
var template = this.GenerateRowTemplate(trRow.Row, trRow.RowIndex);
var tr = this.Elements.tbody.Add(template, "row" + trRow.RowIndex);
trRow.parentNode.insertBefore(tr, trRow);
if (trRow.subTr) {
trRow.subTr.Remove();
}
trRow.Remove();
},
AddNewRowsToTableBody: function (tbody) {
if (!tbody)
tbody = this.Elements.tbody;
var newElements = [];
var obj = this;
for (var i = this.CurrentAddedRowCount; i < this.Rows.length; i++) {
var tr = this.GenerateRowTemplate(this.Rows[i], i);
if (tbody.Add) {
newElements.push(tbody.Add(tr, "row" + i));
} else {
tbody.Elements["row" + i] = tr;
}
}
this.CurrentAddedRowCount = this.Rows.length;
return newElements;
},
GenerateRowTemplate: function (rowObj, rowIndex) {
var obj = this;
var tr = {
_: "tr",
Elements: {},
Row: rowObj,
RowIndex: rowIndex,
onclick: function (event) {
if (obj.EnableFullRowCheckBoxToggle) {
var checkBoxElement = this.querySelector("input[type=checkbox]");
if (checkBoxElement != null) {
if (obj.EnableFullRowClickDeselectOthers && !event.shiftKey && !event.ctrlKey) {
var allCheckBoxes = obj.querySelectorAll("input[type=checkbox]");
for (var i = 0; i < allCheckBoxes.length; i++) {
allCheckBoxes[i].checked = false;
}
}
checkBoxElement.checked = !checkBoxElement.checked;
checkBoxElement.onclick(event);
checkBoxElement.onchange();
obj.PreviousCheckBox = checkBoxElement;
}
}
obj.RowClick(this.Row, this);
},
ondblclick: function () {
if (obj.RowDoubleClick) {
obj.RowDoubleClick(this.Row, this);
}
}
};
for (var j = 0; j < this.TableUseColumns.length; j++) {
var name = this.TableUseColumns[j];
var templateToUse = this.DefaultTemplate;
if (this.Templates[name]) {
templateToUse = this.Templates[name];
}
tr.Elements[name] = {
_: templateToUse,
DataColumnName: name,
Data: rowObj[name],
Row: rowObj,
Table: this
};
if (rowObj[name] && rowObj[name].substr && rowObj[name].substr(0, 6) == "/Date(") {
var tmp = rowObj[name].substr(6);
tmp = tmp.substr(0, tmp.length - 2);
rowObj[name + "-SortValue"] = new Date(parseInt(tmp)).getTime();
}
}
return tr;
}
};
window.TK.AjaxTable = {
_: window.TK.Table,
Url: null,
Post: null,
AjaxSettings: {},
Init: function () {
this.RefreshData();
},
RefreshData: function () {
this.Clear();
var obj = this;
if (this.Url) {
var url = this.Url;
if (url.indexOf("SORTBY") >= 0) {
// Sort using ajax requests
var tmp = this.SortedBy ? this.SortedBy : "";
url = url.replace("SORTBY", encodeURIComponent(tmp));
url = url.replace("SORTDESC", this.SortedDesc);
this.SortCallBack = function () {
obj.RefreshData();
};
}
if (url.indexOf("FILTER") >= 0) {
// Limit rows using ajax requests
var filter = this.CurrentFilter ? this.CurrentFilter : "";
url = url.replace("FILTER", encodeURIComponent(filter));
this.FilterCallBack = function () {
obj.RefreshData();
};
}
if (url.indexOf("COUNT") >= 0) {
// Limit rows using ajax requests
// TODO
}
Ajax.do(url, this.Post, function (response) {
if (!obj.Post || typeof obj.Post === "string" || obj.Post instanceof String) {
obj.Rows = JSON.parse(response);
} else {
obj.Rows = response;
}
obj.Refresh();
obj.Update();
}, undefined, this.AjaxSettings);
}
},
Update: function () { }
};
"use strict";
window.TK.Toast = {
_: "component",
Template: {
_: "div",
className: "toolkitToast",
Title: "",
Message: "",
Action: null,
Init: function () {
if (this.Title) {
this.Elements.TitleH3.appendChild(document.createTextNode(this.Title));
} else {
this.Elements.TitleH3.style.display = "none";
}
this.Elements.Message.appendChild(document.createTextNode(this.Message));
},
onclick: function () {
if (this.Action)
this.Action(this);
},
Elements: {
TitleH3: {},
Message: {}
},
Destroy: function () {
var obj = this;
TK.Toast.CurrentToasts = TK.Toast.CurrentToasts.Where(function (a) { return a != obj });
}
},
Position: 0, // 0 Top, 0.5 Top right, 1 Right, 1.5 Bottom right, 2 Bottom, 2.5 Bottom left, 3 Left, 3.5 Top left
VisibleMS: 3000,
Width: 250,
Height: 100,
CurrentToasts: [],
Create: function (title, message, action, customTemplate) {
if (customTemplate && !customTemplate._) {
customTemplate._ = this.Template;
}
var toast = TK.Initialize({ _: customTemplate ? customTemplate : this.Template, Title: title, Message: message, Action: action });
toast.style.position = "fixed";
toast.style.width = this.Width + "px";
var offset = 5;
var offsetStep = this.Position == 1 || this.Position == 3 ? this.Width : this.Height;
for (var i = 0; i < TK.Toast.CurrentToasts.length; i++) {
if (TK.Toast.CurrentToasts[i].ToastOffset + offsetStep > offset && TK.Toast.CurrentToasts[i].ToastPosition == this.Position) {
offset = TK.Toast.CurrentToasts[i].ToastOffset + offsetStep + 5;
}
}
toast.ToastOffset = offset;
toast.ToastPosition = this.Position;
TK.Toast.CurrentToasts.push(toast);
//toast.style.height = this.Height + "px";
if (this.Position == 0) {
toast.style.top = offset + "px";
toast.style.left = ((window.innerWidth / 2) - (this.Width / 2)) + "px";
} else if (this.Position == 0.5) {
toast.style.top = offset + "px";
toast.style.right = "5px";
} else if (this.Position == 1) {
toast.style.top = ((window.innerHeight / 2) - (this.Height / 2)) + "px";
toast.style.right = offset + "px";
} else if (this.Position == 1.5) {
toast.style.bottom = offset + "px";
toast.style.right = "5px";
} else if (this.Position == 2) {
toast.style.bottom = offset +"px";
toast.style.left = ((window.innerWidth / 2) - (this.Width / 2)) + "px";
} else if (this.Position == 2.5) {
toast.style.bottom = offset +"px";
toast.style.left = "5px";
} else if (this.Position == 3) {
toast.style.top = ((window.innerHeight / 2) - (this.Height / 2)) + "px";
toast.style.left = offset +"px";
} else if (this.Position == 3.5) {
toast.style.top = offset + "px";
toast.style.left = "5px";
}
document.body.appendChild(toast);
setTimeout(function () {
toast.className += " toolkitVisible";
}, 10);
setTimeout(function () {
toast.Remove();
}, this.VisibleMS);
return toast;
}
};"use strict";
window.TK.Tree = {
_: "ul",
IdField: "Id",
ParentIdField: "ParentId",
CurrentFilter: null,
Rows: [],
CurRows: null,
className: "tree toolkitTree",
EnableFullRowExpand: false,
AutoExpandChildNodesDuringFilter: true, // When applying filter with showAllChildNodes=true and this setting is set to false, the child rows will be visible but not expanded
inAddRowsFunction: false, // used by functions inside object do not override
Template: {
_: "li",
Data: null,
Init: function () {
this.Elements.Text.innerText = (this.Data && this.Data.Text) ? this.Data.Text : "";
},
Elements: {
Text: { _: "span" }
}
},
Expanded: function (row, byUserClick, rowElement) { },
Collapsed: function (row, byUserClick, rowElement) { },
Init: function () {
if (this.Rows.length == 0)
return;
this.Refresh();
},
AddExpandButtonToRowElement: function (rowElement) {
var obj = this;
if (rowElement.SubList)
return; // Already has an expand button
rowElement.SubList = document.createElement("UL");
rowElement.SubList.style.display = "none";
rowElement.className += " collapsed";
rowElement.appendChild(rowElement.SubList);
var expandButton = document.createElement("SPAN");
expandButton.className = "expandCollapseButton";
var collapsed = window.SvgPath("M3,2L7,6L3,10", 12, 12, "#999");
expandButton.innerHTML = collapsed;
expandButton.Update = function () {
if (this.parentNode.className.indexOf("expanded") >= 0) {
this.innerHTML = window.SvgPath("M2,3L6,7L10,3", 12, 12, "#999");
} else {
this.innerHTML = collapsed;
}
};
expandButton.onclick = function (e) {
if (this.parentNode.className.indexOf("expanded") >= 0) {
obj.Collapsed(this.parentNode.Data, true, this.parentNode);
this.parentNode.SubList.style.display = "none";
this.parentNode.className = this.parentNode.className.replace(/expanded/g, "") + " collapsed";
} else {
obj.Expanded(this.parentNode.Data, true, this.parentNode);
this.parentNode.SubList.style.display = "";
this.parentNode.className = this.parentNode.className.replace(/collapsed/g, "") + " expanded";
}
this.Update();
if (e)
e.stopPropagation();
return false;
};
rowElement.ExpandCollapseButton = expandButton;
rowElement.insertBefore(expandButton, rowElement.firstChild);
},
AddRows: function (rows) {
var obj = this;
obj.inAddRowsFunction = true;
if (!this.CurRows)
this.CurRows = {};
// First add all the rows
var addedRows = [];
for (var i = 0; i < rows.length; i++) {
// Order at the end for performance
var rowElement = obj.AddRow(rows[i], false);
addedRows.push(rows[i]);
}
obj.OrderRows(addedRows);
obj.inAddRowsFunction = false;
return addedRows;
},
AddRow: function (data) {
let obj = this;
if (!this.CurRows)
this.CurRows = {};
let rowId = data[this.IdField];
if (this.CurRows["id" + rowId]) {
console.warn(rowId + ' row id is already added and must be unique. Row not added.');
return;
}
let row = obj.Add({
_: obj.Template,
TreeRoot: obj,
Data: data,
Row: {},
onclick: function (e) {
let rowObj = this;
if (e && e.target && (e.target.tagName == "INPUT" || e.target.tagName == "SELECT" || e.target.tagName == "TEXTAREA" || e.target.PreventRowClick))
return;
obj.RowClick(rowObj.Data, e, rowObj);
if (rowObj.EnableFullRowExpand && rowObj.ExpandCollapseButton) {
rowObj.ExpandCollapseButton.click();
}
e.stopPropagation();
return false;
}
});
row.Row = row;
if (data.AlwaysShowExpandButton) {
obj.AddExpandButtonToRowElement(row);
}
if (obj.CurrentFilter && row.innerText.toLowerCase().indexOf(this.CurrentFilter) < 0) {
row.style.display = "none";
}
obj.CurRows["id" + rowId] = row;
obj.Rows.push(data);
if (!obj.inAddRowsFunction) {
obj.OrderRows(obj.Rows);
}
return row;
},
OrderRows: function (rows) {
var obj = this;
// Move rows to right place
for (var i = 0; i < rows.length; i++) {
// if (this.IgnoredRows.indexOf(rows[i]) >= 0)
// continue;
var rowId = rows[i][this.IdField];
var parentId = rows[i][this.ParentIdField];
if (!parentId || !this.CurRows["id" + parentId])
continue;
// Add expand button to the parent item
var parent = this.CurRows["id" + parentId];
this.AddExpandButtonToRowElement(parent);
// Move this item to the right parent element
parent.SubList.appendChild(this.CurRows["id" + rowId]);
this.CurRows["id" + rowId].Parent = parent;
}
// After ordering set tree depth for each row
for (var rowKey in obj.children) {
var row = obj.children[rowKey];
if (!row || !row.Row)
continue;
row.TreeDepth = 0;
obj.RecursiveSublist(row, function (childRow) {
if (!childRow.Parent.TreeDepth)
childRow.TreeDepth = 1;
else
childRow.TreeDepth = childRow.Parent.TreeDepth + 1;
});
}
},
RemoveRows: function (rows) {
for (var i = 0; i < rows.length; i++) {
var rowId = rows[i][this.IdField];
var rowElement = this.CurRows["id" + rowId];
if (rowElement)
rowElement.parentNode.removeChild(rowElement);
var posIndex = this.Rows.indexOf(rows[i]);
if (posIndex >= 0) {
this.Rows.splice(posIndex, 1);
}
}
},
Refresh: function () {
this.Clear();
var rows = this.Rows;
this.Rows = []; // Will be filled again
this.CurRows = {};
this.AddRows(rows);
},
RecursiveSublist: function (row, subItemFunction) {
var obj = this;
if (!row.SubList)
return;
for (var rowDescendantKey in row.SubList.childNodes) {
var rowDescendant = row.SubList.childNodes[rowDescendantKey];
// if descendant does not have the Row property it is not a generated row.
if (!rowDescendant.Row)
continue;
let breakLoop = subItemFunction.apply(obj, [rowDescendant]);
if (breakLoop)
break;
obj.RecursiveSublist(rowDescendant, subItemFunction);
}
},
RecursiveParent: function (row, parentFunction) {
var obj = this;
// Check if parent is a generated row
if (!row.Parent || !row.Parent.Row)
return;
let breakRecursion = parentFunction.apply(obj, [row.Parent]);
if (breakRecursion)
return;
obj.RecursiveParent(row.Parent, parentFunction);
},
ApplyFilter: function (filter, showAllChildNodes, callBackFoundRows) {
let obj = this;
const isFunction = typeof filter === "function";
if (!filter) {
this.Refresh(); // Collapse everything
return;
}
// Show item and all parent nodes, display:none the rest
this.style.display = "none"; // Faster when updating
// First hide everything
for (var item in this.CurRows) {
var row = this.CurRows[item];
row.style.display = "none";
}
var foundRows = [];
// Then make everything matching visible, including all parents and optionally all child nodes
function processRow(filterString) {
for (var item in obj.CurRows) {
var row = obj.CurRows[item];
let matchesFilter = false;
if (isFunction) {
matchesFilter = filter(row.Data, row);
} else {
var txt = "";
if (row.SubList) { // Only look at the text of this element
for (var j = 0; j < row.childNodes.length; j++) {
if (row.childNodes[j] != row.SubList)
txt += row.childNodes[j].innerText;
}
} else {
txt = row.innerText;
}
matchesFilter = txt.toLowerCase().indexOf(filterString) >= 0;
}
if (matchesFilter) {
row.style.display = "";
foundRows.push(row);
if (!obj.AutoExpandChildNodesDuringFilter && row.className.indexOf("collapsed") < 0) {
row.className = row.className.replace(/expanded/g, "") + " collapsed";
if (row.ExpandCollapseButton)
row.ExpandCollapseButton.Update();
}
if (showAllChildNodes && row.SubList) {
var subLists = [row.SubList];
for (var j = 0; j < subLists.length; j++) {
var curList = subLists[j];
var addClass = "expanded";
var removeClass = "collapsed";
var setStyle = "";
if (!obj.AutoExpandChildNodesDuringFilter) {
addClass = "collapsed";
removeClass = "expanded";
setStyle = "none";
}
curList.style.display = setStyle;
for (var n = 0; n < curList.childNodes.length; n++) {
var li = curList.childNodes[n];
if (li.className.indexOf(addClass) < 0) {
li.className = li.className.replace(removeClass, "") + " " + addClass;
if (addClass == "expanded")
obj.Expanded(li.Data, false, curList);
else
obj.Collapsed(li.Data, false, curList);
if (li.ExpandCollapseButton)
li.ExpandCollapseButton.Update();
}
if (li.style)
li.style.display = "";
if (li.SubList)
subLists.push(li.SubList);
}
}
}
// Expand all items above
while (row.parentNode.Rows == undefined) {
row = row.parentNode;
if (row.SubList && row.className.indexOf("expanded") < 0) {
row.className = row.className.replace(/collapsed/g, "") + " expanded";
obj.Expanded(row.Data, false, row);
if (row.ExpandCollapseButton)
row.ExpandCollapseButton.Update();
}
row.style.display = "";
}
}
}
}
if (isFunction) {
processRow()
}
else {
var filterString = (filter || "").toLowerCase();
var filterParts = filterString.split(/;/g);
for (var i = 0; i < filterParts.length; i++) {
processRow(filterParts[i]);
}
}
this.style.display = "";
if (callBackFoundRows) {
callBackFoundRows(foundRows);
}
},
SelectRow: function (id) {
// Select a single item and expand+scroll the tree to that item
var curSelectedItem = this.querySelector(".selectedItem");
if (curSelectedItem)
curSelectedItem.className = curSelectedItem.className.replace(/selectedItem/g, "");
var currentRow = this.CurRows["id" + id];
if (!currentRow)
return;
currentRow.className += " selectedItem";
var row = currentRow;
row.style.display = "";
if (row.SubList) {
this.Expanded(row.Data, false, row);
row.className = row.className.replace(/collapsed/g, "") + " expanded";
row.SubList.style.display = "";
}
while (row.parentNode.Rows == undefined) {
row = row.parentNode;
if (row.SubList) {
this.Expanded(row.Data, false, row);
row.className = row.className.replace(/collapsed/g, "") + " expanded";
}
row.style.display = "";
}
currentRow.scrollIntoView();
return currentRow;
},
ConvertJsonToRows: function (json, arrayChildNames) {
let obj = this;
let rowId = 0;
let resultRows = [];
if (!arrayChildNames)
arrayChildNames = [];
let recursiveJsonProperties = function (top, skip) {
let parentId = rowId;
for (const propIndex in top) {
let prop = top[propIndex];
if (!prop || (skip && skip === propIndex)) {
continue;
}
let proptype = typeof prop;
rowId++;
let rowObj = { Id: rowId, ParentId: parentId, Text: propIndex + ": " + prop };
if (proptype === 'boolean' || proptype === 'number' || proptype === 'string' || proptype === 'date') {
if (obj.ValueProperty && propIndex == obj.ValueProperty)
rowObj[obj.ValueProperty] = prop;
// Don't show indexes for array's that don't contain objects
if (Array.isArray(top))
rowObj.Text = prop + "";
resultRows.push(rowObj);
}
// Set right object name when dealing with arrays
else if (proptype === 'object') {
let childArrayProp = null;
rowObj.Text = propIndex + "";
if (!Array.isArray(prop)) {
childArrayProp = Object.keys(prop).find(k => arrayChildNames.includes(k));
if (childArrayProp)
rowObj.Text = prop[childArrayProp] + "";
}
resultRows.push(rowObj);
recursiveJsonProperties(prop, childArrayProp);
}
}
}
recursiveJsonProperties(json);
return resultRows;
},
RowClick: function (rowObj, jsEvent) { }
};
window.TK.AjaxTree = {
_: window.TK.Tree,
Url: null,
Post: null,
AjaxSettings: {},
ShowJsonAsTree: false, // When you want to show the ajax response in json directly
ArrayChildNames: [], // Set child name of array if that value must be the name of that array item
Init: function (callback) {
var obj = this;
obj.Clear();
if (this.Url) {
Ajax.do(this.Url, this.Post, function (response) {
if (response && response.substr)
response = JSON.parse(response);
if (obj.ShowJsonAsTree)
response = obj.ConvertJsonToRows(response, obj.ArrayChildNames);
obj.Rows = response;
obj.Refresh();
obj.Update();
if (callback) {
callback.apply(obj);
}
}, undefined, this.AjaxSettings);
}
},
Update: function () { }
};
// Control and shift keys are supported.
// For switching a parent and keep the rest of the selection use the control key.
// For selecting multiple checkboxes next to each other use the shift key.
window.TK.FormTree = {
_: window.TK.Tree,
ValueProperty: null, // By default it retrieved the Id field. When set to something else it will be returned with GetValue()
inAddCheckboxesFunction: false, // used by functions inside object do not override
Data: [],
Init: function () {
if (this.Rows.length == 0)
return;
let obj = this;
var originalAddRows = obj.AddRows;
obj.AddRows = function (rows) {
if (!rows) return;
originalAddRows.apply(obj, [rows]);
obj.AddCheckBoxes();
};
var originalAddRow = obj.AddRow;
obj.AddRow = function (row, orderRows) {
var rowNode = originalAddRow.apply(obj, [row, orderRows]);
// At the end of the add rows function the rest of the functionality will be executed
if (obj.inAddRowsFunction)
return;
var checked = obj.Data && rowNode.Data &&
(rowNode.Data[obj.IdField] !== undefined && rowNode.Data[obj.IdField] !== null && obj.Data.some(function (d) { return d === rowNode.Data[obj.IdField] }))
|| (obj.ValueProperty && rowNode.Data[obj.ValueProperty] !== undefined && rowNode.Data[obj.ValueProperty] !== null && obj.Data.some(function (d) { return d === rowNode.Data[obj.ValueProperty] }));
obj.AddCheckBox(rowNode, checked);
}
obj.style.display = 'none'; // invisible when adding checkboxes and building tree makes it faster
obj.Refresh();
if (obj.Data) {
let checkedCheckboxes = obj.Checkboxes.filter(function (c) { return c ? c.checked : false });
for (let i = 0; i < checkedCheckboxes.length; i++) {
let boxChecked = checkedCheckboxes[i];
obj.RecursiveParent(boxChecked.Parent.Row, function (parentRow) {
if (parentRow.CheckBox.checked)
return;
obj.SetParentCheckbox(parentRow);
});
}
}
obj.style.display = '';
},
CheckBoxChange: function (changedRow, checkedRows) { },
CheckBoxClick: function (event, row) {
// Set all decendants to the same value
let sublistCheck = function (row) {
obj.RecursiveSublist(row, function (rowDescendant) {
let box = rowDescendant.CheckBox;
if (box) {
box.checked = checkboxObj.checked;
box.indeterminate = false;
}
});
};
// Check parent nodes and their childeren to set checkbox value
let parentCheck = function (row) {
obj.RecursiveParent(row, obj.SetParentCheckbox);
};
let obj = this;
let checkboxObj = row.CheckBox;
// Control only selects that single specific row
if (event.ctrlKey) {
obj.lastBoxClick = checkboxObj;
// Call change function
obj.CheckBoxChange(row, obj.Checkboxes.filter(function (b) { return b.checked; }).map(function (b) { return b.Parent; }));
return;
}
// Shift key functionality
if (event.shiftKey && obj.lastBoxClick) {
// Dont remember last click when shift is pressed
// When shift clicked on same box deselect all children and check parent
if (obj.lastBoxClick === checkboxObj) {
obj.RecursiveSublist(checkboxObj.Parent, function (row) { row.CheckBox.checked = false; });
checkboxObj.indeterminate = false;
checkboxObj.checked = true;
// Call change function
obj.CheckBoxChange(row, obj.Checkboxes.filter(function (b) { return b.checked; }).map(function (b) { return b.Parent; }));
return;
}
// Filter and set right checkboxes based on checkbox Id
let goUp = checkboxObj.TreeId < obj.lastBoxClick.TreeId;
let cboxes = obj.Checkboxes.filter(function (box) {
if (goUp)
return box.TreeId < obj.lastBoxClick.TreeId && box.TreeId >= checkboxObj.TreeId;
return box.TreeId > obj.lastBoxClick.TreeId && box.TreeId <= checkboxObj.TreeId;
});
cboxes.forEach(function (b) {
b.checked = obj.lastBoxClick.checked
});
sublistCheck(row.TreeDepth <= obj.lastBoxClick.Parent.Row.TreeDepth ? row : obj.lastBoxClick.Parent.Row);
parentCheck(row.TreeDepth >= obj.lastBoxClick.Parent.Row.TreeDepth ? row : obj.lastBoxClick.Parent.Row);
// Call change function
obj.CheckBoxChange(row, obj.Checkboxes.filter(function (b) { return b.checked; }).map(function (b) { return b.Parent; }));
return;
}
obj.lastBoxClick = row.CheckBox;
sublistCheck(row);
parentCheck(row);
// Call change function
obj.CheckBoxChange(row, obj.Checkboxes.filter(function (b) { return b.checked; }).map(function (b) { return b.Parent; }));
},
AddCheckBoxes: function () {
var obj = this;
obj.inAddCheckboxesFunction = true;
for (var rowId in obj.CurRows) {
var row = obj.CurRows[rowId];
let rowNode = row.Row;
if (obj.ValueProperty && !row.Row.Data[obj.ValueProperty]) {
continue;
}
let checked = obj.Data && rowNode.Data &&
(rowNode.Data[obj.IdField] !== undefined && rowNode.Data[obj.IdField] !== null && obj.Data.some(function (d) { return d === rowNode.Data[obj.IdField] }))
|| (obj.ValueProperty && rowNode.Data[obj.ValueProperty] !== undefined && rowNode.Data[obj.ValueProperty] !== null && obj.Data.some(function (d) { return d === rowNode.Data[obj.ValueProperty] }));
obj.AddCheckBox(row, checked);
if (obj.ValueProperty) {
obj.RecursiveParent(row, function (parentRow) { if (!parentRow.CheckBox) obj.AddCheckBox(parentRow) });
}
}
// Give each checkbox a tree Id
obj.IndexCheckboxes();
obj.inAddCheckboxesFunction = false;
},
AddCheckBox: function (row, checked) {
var obj = this;
if (!row || row.CheckBox || !row.firstChild)
return;
let checkbox = TK.Initialize({
_: "input",
type: "checkbox",
checked: checked ? true : false,
className: "toolkitTreeCheckbox"
});
checkbox.onclick = function (e) { obj.CheckBoxClick(e, row); };
row.CheckBox = checkbox;
checkbox.Parent = row;
if (row.firstChild.classList.contains('expandCollapseButton') && row.childNodes.length > 1)
row.insertBefore(checkbox, row.childNodes[1]);
else
row.insertBefore(checkbox, row.firstChild);
if (!obj.inAddCheckboxesFunction)
obj.IndexCheckboxes();
},
IndexCheckboxes: function () {
var obj = this;
// Give each checkbox a tree Id
if (obj.parentNode) {
obj.Checkboxes = [];
let treeIndex = 1;
for (var i = 0; i < obj.children.length; i++) {
let row = obj.children[i];
if (!row.Row || !row.CheckBox)
continue;
row.CheckBox.TreeId = treeIndex;
obj.Checkboxes.push(row.CheckBox);
treeIndex++;
obj.RecursiveSublist(row, function (childNode) {
if (!childNode.CheckBox)
return;
childNode.CheckBox.TreeId = treeIndex;
obj.Checkboxes.push(childNode.CheckBox);
treeIndex++;
});
}
}
},
GetValue: function () {
let obj = this;
let result = [];
for (var rowId in obj.CurRows) {
var row = obj.CurRows[rowId];
if (row.CheckBox && row.CheckBox.checked) {
if (obj.ValueProperty && !row.Data[obj.ValueProperty]) {
continue;
}
result.push(row.Data[obj.ValueProperty ? obj.ValueProperty : obj.IdField]);
}
}
return result;
},
SetParentCheckbox: function (parentRow) {
let obj = this;
if (!parentRow.CheckBox)
return;
let checked = true;
let indeterminate = false;
obj.RecursiveSublist(parentRow, function (childRow) {
// When at least one is checked and one is unchecked we don't need to check the rest
if (!checked && indeterminate)
return true; // will break out of recursion
let box = childRow.CheckBox;
if (box) {
checked = checked && box.checked;
indeterminate = indeterminate || box.checked;
}
});
// If checked is true here, all items are checked so indeterminate is false
indeterminate = !checked && indeterminate;
parentRow.CheckBox.checked = checked;
parentRow.CheckBox.indeterminate = indeterminate;
},
Checkboxes: []
}
window.TK.AjaxFormTree = {
_: window.TK.FormTree,
Url: null,
Post: null,
AjaxSettings: {},
Init: function () {
let obj = this;
window.TK.AjaxTree.Init.apply(obj, [window.TK.FormTree.Init]);
},
Update: function () { }
};"use strict";
/* Minify Order(110) */
// Dragable items on a board
window.TK.Dashboard = {
_: "div",
EnableMove: true,
EnableCopy: true,
EnableResize: true,
EnableRemove: true,
EnableEdit: true,
EnableLimitX: true,
EnableLimitY: true,
EnableDrop: false,
Spacing: 5,
SnapSize: 100,
EditMode: 1, // 0: None, 1: Show edit buttons when hovering, 2: Always show edit buttons
className: "toolkitDashboard",
DashboardItems: [],
DefaultWidth: 600,
AutoGrow: true, // Automatic increase size of this element (Adds [SnapSize] spacing to this div when moving/resizing elements)
AutoShrink: false,
AutoWidthCount: null, // When this is a positive value, the snap size will be adjusted automatically to make sure there are always X 'blocks' in the width
Init: function () {
this.SetEditMode(this.EditMode);
if (this.DashboardItems) {
var obj = this;
setTimeout(function () {
obj.Load(obj.DashboardItems);
}, 1);
}
},
SetEditMode: function (newEditMode) {
this.EditMode = newEditMode;
var newClassName = this.className.replace(/toolkitDashboardEditable/g, "").replace(/toolkitDashboardAlwaysEditable/g, "");
if (this.EditMode == 1)
newClassName += " toolkitDashboardEditable toolkitDragDropContainer";
else if (this.EditMode == 2)
newClassName += " toolkitDashboardAlwaysEditable toolkitDragDropContainer";
this.className = newClassName;
},
Save: function () {
var state = [];
var items = this.Elements.ToArray();
for (var i = 0; i < items.length; i++) {
if (!items[i].Elements || !items[i].Elements.Content || !items[i].Elements.Content.StateProperties)
continue;
var c = items[i].Elements.Content;
var stateProperties = {};
for (var j = 0; j < c.StateProperties.length; j++) {
stateProperties[c.StateProperties[j]] = c[c.StateProperties[j]];
}
state.push({ _: c.StateObjectName, State: stateProperties, Top: items[i].Top, Left: items[i].Left, Width: items[i].Width, Height: items[i].Height });
}
this.DashboardItems = state;
return JSON.stringify(state);
},
Load: function (state) {
if (state.substr)
state = JSON.parse(state);
this.Clear();
var regex = /[^A-Za-z0-9\.]/g;
if (this.AutoWidthCount) {
this.SnapSize = Math.floor(this.offsetWidth / this.AutoWidthCount);
while (this.offsetWidth / (this.SnapSize + this.Spacing) < this.AutoWidthCount && this.SnapSize > 30) {
this.SnapSize -= 5;
}
}
for (var i = 0; i < state.length; i++) {
if (regex.exec(state[i]._))
continue;
var tmp = eval(state[i]._ + ".StateObjectName");
if (!tmp)
continue;
var stateProperties = state[i].State;
stateProperties._ = state[i]._;
this.AddDashboardItem(stateProperties, null, state[i].Left, state[i].Top, state[i].Width, state[i].Height);
}
},
CanDrop: function (elementOrTemplate) {
if (!this.EnableDrop)
return false;
for (var i = 0; i < 30 && elementOrTemplate._ && !elementOrTemplate.StateObjectName; i++)
elementOrTemplate = elementOrTemplate._;
return (elementOrTemplate && elementOrTemplate.StateObjectName);
},
Drop: function (elementOrTemplate, x, y) {
if (!this.EnableDrop)
return;
var size = this.SnapSize + this.Spacing;
y = Math.round(y / size);
x = Math.round(x / size);
if (y < 0) y = 0;
if (x < 0) x = 0;
var width = (elementOrTemplate.Width ? elementOrTemplate.Width : 1);
var height = (elementOrTemplate.Height ? elementOrTemplate.Height : 1);
if (!elementOrTemplate.appendChild) { // A template has been dropped
return this.AddDashboardItem(elementOrTemplate, "block" + new Date().getTime(), x, y, width, height);
} else { // An element has been dropped, add a block and then replace the content element
var addedBlock = this.AddDashboardItem({}, "block" + new Date().getTime(), x, y, width, height);
addedBlock.Elements.Content.Remove();
addedBlock.Elements.Content = elementOrTemplate;
elementOrTemplate.Parent = addedBlock;
addedBlock.appendChild(elementOrTemplate);
return addedBlock;
}
},
AutoGrowHandler: function (restore) {
if (restore) {
this.className = this.className.replace(/toolkitDashboardEditing/g, "");
} else if (this.className.indexOf("Editing") < 0) {
this.className += " toolkitDashboardEditing";
}
if (!this.AutoGrow || this.offsetHeight == 0)
return;
var items = this.Elements.ToArray();
var maxBottomY = 0;
for (var i = 0; i < items.length; i++) {
if (!items[i].Elements || !items[i].Elements.Content || !items[i].Height)
continue;
var bottomY = this.TopOrLeftSquaresToPX(items[i].Top) + this.HeightOrWidthSquaresToPX(items[i].Height);
if (maxBottomY < bottomY)
maxBottomY = bottomY;
}
var newHeight = maxBottomY + (this.SnapSize + this.Spacing);
if (!this.style.height || parseInt(this.style.height) < newHeight || this.AutoShrink)
this.style.height = newHeight + "px";
},
TemplateDashboardItem: {
style: {
position: "absolute"
},
DashboardElement: null,
// Position/Sizes are in snap-index
Left: 0,
Top: 0,
Width: 1,
Height: 1,
ontouchstart: function () {
if (this.DashboardElement.EditMode == 0)
return;
if (this.className.indexOf("toolkitSelectedDashboardItem") < 0) {
this.className += " toolkitSelectedDashboardItem";
} else {
this.className = this.className.replace(/toolkitSelectedDashboardItem/g, "");
}
},
Init: function () {
var obj = this;
if (this.DashboardElement.EnableMove) {
this.Add({
_: "div",
className: "tkDashboardButton",
innerHTML: Svg.Icons.Move,
ontouchstart: function (e) {
this.onmousedown(e.touches[0]);
e.stopPropagation();
},
onmousedown: function (e) {
var x, y;
try { x = e.pageX; y = e.pageY; } catch (errie) { var e2 = window.event; x = e2.clientX; y = e2.clientY; }
var startX = x - obj.offsetLeft;
var startY = y - obj.offsetTop;
var startWidth = obj.offsetWidth;
var startHeight = obj.offsetHeight;
var totalWidth = obj.DashboardElement.offsetWidth;
var totalHeight = obj.DashboardElement.offsetHeight;
window.onmousemove = function (e) {
var x, y;
try { x = e.pageX; y = e.pageY; } catch (errie) { var e2 = window.event; x = e2.clientX; y = e2.clientY; }
var newLeft = (x - startX);
var newTop = (y - startY);
var size = obj.DashboardElement.SnapSize + obj.DashboardElement.Spacing;
newTop = Math.round(newTop / size);
newLeft = Math.round(newLeft / size);
if (newTop < 0) newTop = 0;
if (newLeft < 0) newLeft = 0;
totalWidth = obj.DashboardElement.offsetWidth;
totalHeight = obj.DashboardElement.offsetHeight;
if (obj.DashboardElement.EnableLimitX && totalWidth > 0 && (newLeft * size) + startWidth > totalWidth) newLeft = Math.floor((totalWidth - startWidth) / size);
if (obj.DashboardElement.EnableLimitY && totalHeight > 0 && (newTop * size) + startHeight > totalHeight) newTop = Math.floor((totalHeight - startHeight) / size);
if (newLeft < 0) newLeft = 0;
if (newTop < 0) newTop = 0;
obj.Left = newLeft;
obj.Top = newTop;
obj.SetSize();
obj.DashboardElement.AutoGrowHandler();
};
window.onmouseup = function () {
window.onmousemove = null;
window.onmouseup = null;
window.onselectstart = null;
window.ontouchend = null;
window.ontouchmove = null;
obj.DashboardElement.AutoGrowHandler(true);
};
window.ontouchmove = function (e) {
if (window.onmousemove)
window.onmousemove(e.touches[0]);
e.stopPropagation();
};
window.ontouchend = function (e) {
if (window.onmouseup)
window.onmouseup();
e.stopPropagation();
};
window.onselectstart = function () { return false; };
if (e && e.preventDefault)
e.preventDefault();
else
window.event.returnValue = false;
}
}, "MoveButton");
}
if (this.DashboardElement.EnableResize) {
this.Add({
_: "div",
className: "tkDashboardButton",
innerHTML: Svg.Icons.Resize,
ontouchstart: function (e) {
this.onmousedown(e.touches[0]);
e.stopPropagation();
},
onmousedown: function (e) {
var startX, startY;
try { startX = e.pageX; startY = e.pageY; } catch (errie) { var e2 = window.event; startX = e2.clientX; startY = e2.clientY; }
var startWidth = obj.offsetWidth;
var startHeight = obj.offsetHeight;
var totalWidth = obj.DashboardElement.offsetWidth;
var totalHeight = obj.DashboardElement.offsetHeight;
window.onmousemove = function (e) {
var x, y;
try { x = e.pageX; y = e.pageY; } catch (errie) { var e2 = window.event; x = e2.clientX; y = e2.clientY; }
var newWidth = (x - startX) + startWidth;
var newHeight = (y - startY) + startHeight;
var size = obj.DashboardElement.SnapSize;
newHeight = Math.round(newHeight / size);
newWidth = Math.round(newWidth / size);
var newWidthPx = ((newWidth * obj.DashboardElement.SnapSize) + ((newWidth - 1) * obj.DashboardElement.Spacing));
var newHeightPx = ((newHeight * obj.DashboardElement.SnapSize) + ((newHeight - 1) * obj.DashboardElement.Spacing));
totalWidth = obj.DashboardElement.offsetWidth;
totalHeight = obj.DashboardElement.offsetHeight;
if (obj.DashboardElement.EnableLimitX && totalWidth > 0 && obj.DashboardElement.TopOrLeftSquaresToPX(obj.Left) + newWidthPx > totalWidth) newWidth = Math.floor((totalWidth + obj.DashboardElement.Spacing) / (size + obj.DashboardElement.Spacing)) - obj.Left;
if (obj.DashboardElement.EnableLimitY && totalHeight > 0 && obj.DashboardElement.TopOrLeftSquaresToPX(obj.Top) + newHeightPx > totalHeight) newHeight = Math.floor((totalHeight + obj.DashboardElement.Spacing) / (size + obj.DashboardElement.Spacing)) - obj.Top;
obj.Width = newWidth;
obj.Height = newHeight;
obj.SetSize(true);
obj.DashboardElement.AutoGrowHandler();
};
window.onmouseup = function () {
window.onmousemove = null;
window.onmouseup = null;
window.onselectstart = null;
window.ontouchend = null;
window.ontouchmove = null;
obj.DashboardElement.AutoGrowHandler(true);
};
window.ontouchmove = function (e) {
if (window.onmousemove)
window.onmousemove(e.touches[0]);
e.stopPropagation();
};
window.ontouchend = function (e) {
if (window.onmouseup)
window.onmouseup();
e.stopPropagation();
};
window.onselectstart = function () { return false; };
if (e && e.preventDefault)
e.preventDefault();
else
window.event.returnValue = false;
}
}, "ResizeButton");
}
if (this.DashboardElement.EnableRemove) {
this.Add({
_: "div",
className: "tkDashboardButton",
innerHTML: Svg.Icons.Close,
ontouchstart: function (e) {
e.stopPropagation();
},
onclick: function () {
obj.Remove();
}
}, "RemoveButton");
}
if (this.DashboardElement.EnableEdit && this.Elements.Content && this.Elements.Content.Editor) {
this.Add({
_: "div",
className: "tkDashboardButton",
innerHTML: Svg.Icons.Settings,
ontouchstart: function (e) {
e.stopPropagation();
},
onclick: function () {
obj.Elements.Content.Add({ _: obj.Elements.Content.Editor });
}
}, "EditButton");
}
if (this.DashboardElement.EnableCopy) {
this.Add({
_: "div",
className: "tkDashboardButton",
innerHTML: Svg.Icons.Copy,
ontouchstart: function (e) {
this.onmousedown(e.touches[0]);
e.stopPropagation();
},
onmousedown: function (e) {
var x, y;
try { x = e.pageX; y = e.pageY; } catch (errie) { var e2 = window.event; x = e2.clientX; y = e2.clientY; }
var startX = x - obj.offsetLeft;
var startY = y - obj.offsetTop;
var startWidth = obj.offsetWidth;
var startHeight = obj.offsetHeight;
var totalWidth = obj.DashboardElement.offsetWidth;
var totalHeight = obj.DashboardElement.offsetHeight;
var duplicate = null;
window.onmousemove = function (e) {
var x, y;
try { x = e.pageX; y = e.pageY; } catch (errie) { var e2 = window.event; x = e2.clientX; y = e2.clientY; }
var newLeft = (x - startX);
var newTop = (y - startY);
var size = obj.DashboardElement.SnapSize + obj.DashboardElement.Spacing;
newTop = Math.round(newTop / size);
newLeft = Math.round(newLeft / size);
if (newTop < 0) newTop = 0;
if (newLeft < 0) newLeft = 0;
totalWidth = obj.DashboardElement.offsetWidth;
totalHeight = obj.DashboardElement.offsetHeight;
if (obj.DashboardElement.EnableLimitX && totalWidth > 0 && (newLeft * size) + startWidth > totalWidth) newLeft = Math.floor((totalWidth - startWidth) / size);
if (obj.DashboardElement.EnableLimitY && totalHeight > 0 && (newTop * size) + startHeight > totalHeight) newTop = Math.floor((totalHeight - startHeight) / size);
if (newLeft < 0) newLeft = 0;
if (newTop < 0) newTop = 0;
if (newLeft == obj.Left && newTop == obj.Top)
return;
if (!duplicate) {
var c = obj.Elements.Content;
var stateProperties = {}
for (var i = 0; c.StateProperties && i < c.StateProperties.length; i++) {
stateProperties[c.StateProperties[i]] = c[c.StateProperties[i]];
}
stateProperties = JSON.parse(JSON.stringify(stateProperties)); // Make sure all objects are cloned
stateProperties._ = c.StateObjectName;
duplicate = obj.DashboardElement.AddDashboardItem(stateProperties);
duplicate.Width = obj.Width;
duplicate.Height = obj.Height;
}
duplicate.Left = newLeft;
duplicate.Top = newTop;
duplicate.SetSize();
obj.DashboardElement.AutoGrowHandler();
};
window.onmouseup = function () {
window.onmousemove = null;
window.onmouseup = null;
window.onselectstart = null;
window.ontouchend = null;
window.ontouchmove = null;
obj.DashboardElement.AutoGrowHandler(true);
};
window.ontouchmove = function (e) {
if (window.onmousemove)
window.onmousemove(e.touches[0]);
e.stopPropagation();
};
window.ontouchend = function (e) {
if (window.onmouseup)
window.onmouseup();
e.stopPropagation();
};
window.onselectstart = function () { return false; };
if (e && e.preventDefault)
e.preventDefault();
else
window.event.returnValue = false;
}
}, "CopyButton");
}
this.SetSize();
},
SetSize: function (sizeActuallyChanged) {
var newWidth = this.DashboardElement.HeightOrWidthSquaresToPX(this.Width) + "px";
var newHeight = this.DashboardElement.HeightOrWidthSquaresToPX(this.Height) + "px";
this.style.top = this.DashboardElement.TopOrLeftSquaresToPX(this.Top) + "px";
this.style.left = this.DashboardElement.TopOrLeftSquaresToPX(this.Left) + "px";
if (newWidth != this.style.width || newHeight != this.style.height) {
this.style.width = this.DashboardElement.HeightOrWidthSquaresToPX(this.Width) + "px";
this.style.height = this.DashboardElement.HeightOrWidthSquaresToPX(this.Height) + "px";
} else {
sizeActuallyChanged = false;
}
if (sizeActuallyChanged && this.Elements.Content.SizeChanged)
this.Elements.Content.SizeChanged();
}
},
TopOrLeftSquaresToPX: function (topOrLeft) {
return (topOrLeft * (this.SnapSize + this.Spacing));
},
HeightOrWidthSquaresToPX: function (heightOrWidth) {
return ((heightOrWidth * this.SnapSize) + ((heightOrWidth - 1) * this.Spacing));
},
AddDashboardItem: function (element, name, x, y, width, height) {
if (!width) width = 1;
if (!height) height = 1;
if (x === undefined || x === null || y === null || y === undefined) {
// Auto find available place
var totalWidth = this.offsetWidth;
if (totalWidth == 0)
totalWidth = this.DefaultWidth;
var totalWidthInSquares = Math.floor((totalWidth + this.Spacing) / (this.SnapSize + this.Spacing));
y = 0;
var found = false;
while (y < 100) {
x = 0;
while (x <= totalWidthInSquares - width) {
// Check if there is overlap with existing items
var items = this.Elements.ToArray();
found = true;
for (var i = 0; i < items.length; i++) {
if (!items[i].Elements || !items[i].Elements.Content || !items[i].Height)
continue;
if (x >= items[i].Left + items[i].Width || items[i].Left >= x + width)
continue;
if (y >= items[i].Top + items[i].Height || items[i].Top >= y + height)
continue;
found = false;
break;
}
if (found)
break;
x++;
}
if (found)
break;
y++;
}
}
var addedBlock = this.Add({
_: this.TemplateDashboardItem,
DashboardElement: this,
Elements: {
Content: element
},
Top: y,
Left: x,
Width: width,
Height: height
}, name);
this.AutoGrowHandler(true);
return addedBlock;
}
};
// Items with a saveable state
window.TK.DashboardTemplates = {};
window.TK.DashboardTemplates.BaseWithEditor = {
Editor: {
_: TK.Popup,
Title: "Edit block",
Template: {
Init: function () {
var element = this.Parent.Parent;
var properties = {};
for (var i = 0; i < element.StateProperties.length; i++)
properties[element.StateProperties[i]] = element.Properties && element.Properties[element.StateProperties[i]] ? element.Properties[element.StateProperties[i]] : { };
this.Add({
_: TK.Form,
Model: element,
Fields: properties,
IgnoreRest: true,
ApplyToModelDirectly: true,
Save: function () {
element.Init();
}
});
}
}
}
};
window.TK.DashboardTemplates.Text = {
_: window.TK.DashboardTemplates.BaseWithEditor,
StateObjectName: "TK.DashboardTemplates.Text",
StateProperties: ["Text"],
Text: null,
Init: function () {
if (this.Text) {
var obj = this;
this.Clear();
this.Add({
_: "span",
Init: function () {
this.appendChild(document.createTextNode(obj.Text));
}
});
}
}
};"use strict";
/* Minify Order(110) */
// TODO: Support for moment.js, country code: moment.tz.zone(timeZone).abbr(timeZoneOffset);
window.TK.DateTime = {
_: "div",
className: "toolkitDateTime",
MonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
EnableTime: true,
EnableTimeZone: true,
EnableRelative: false,
TimeZone: "Local", // UTC, Local
UseGlobalTimeZone: true, // If true, the time zone will be based on the static TK.DateTime.TimeZone , and not this instance
AlwaysNavigateToStartOfDay: false, // When set to true, selecting a day will always set time to 00:00, even if there was already a value or the day is today
WeekStart: 1, // 0 Sunday, 1 Monday
ValueIsEpoch: false,
Data: null,
onchange: function () { },
readOnly: false,
disabled: false,
DisplayCodes: {
EuropeAmsterdam: "NL",
EuropeParis: "FR",
EuropeLondon: "UK",
EuropeDublin: "IE",
EuropeLuxembourg: "LU",
EuropeBerlin: "DE",
EuropeBrussels: "BR",
EuropeOslo: "NO",
EuropeStockholm: "SE",
AsiaTokyo: "JP",
},
Init: function () {
if (this.DataSettings) {
var fields = ["ValueIsEpoch", "EnableTime", "EnableTimeZone", "EnableRelative", "TimeZone", "WeekStart", "UseGlobalTimeZone"];
for (var i = 0; i < fields.length; i++) {
if (this.DataSettings[fields[i]] !== undefined)
this[fields[i]] = this.DataSettings[fields[i]];
}
}
if (this.EnableRelative && this.Data == "now") {
this.Data = "|";
}
if (!this.EnableTimeZone) {
this.UseGlobalTimeZone = false;
this.TimeZone = "UTC";
}
if (this.ValueIsEpoch && this.Data && (!this.Data.indexOf || this.Data == parseInt(this.Data).toString()))
{
this.Data = new Date(parseInt(this.Data) * 1000).toISOString();
}
this.RenderDateInput(this.Elements.Selection, this.Data);
this.RefreshDateInput(true);
this.Elements.DateInputContainer.Elements.TimeZoneInfo.style.display = (this.EnableTimeZone ? "" : "none");
},
GetTimeZoneText: function () {
},
GetValue: function () {
var isoDate = this.Data;
if (this.EnableRelative && isoDate && isoDate.indexOf && isoDate.indexOf("|") >= 0) {
return isoDate;
}
if (this.ValueIsEpoch) {
return Math.floor(new Date(isoDate).getTime() / 1000);
}
if (this.EnableTime)
return isoDate;
if (!isoDate)
return null;
var dateObj = new Date(isoDate);
if (this.GetTimeZone() == "UTC") {
dateObj.setUTCHours(0);
dateObj.setUTCMinutes(0);
dateObj.setUTCSeconds(0);
} else if (this.GetTimeZone() == "Local") {
dateObj.setHours(0);
dateObj.setMinutes(0);
dateObj.setSeconds(0);
} else {
// TODO
}
return dateObj.toISOString();
},
Elements: {
DateInputContainer: {
className: "dateTimeContainer",
Elements: {
TimeZoneInfo: {
className: "timeZoneInfo",
onclick: function () {
this.Parent.Parent.SetTimeZone(this.Parent.Parent.GetTimeZone() == "UTC" ? "Local" : "UTC");
this.Parent.Elements.DateInput.focus();
}
},
DateInput: {
onkeyup: function () {
if (this.value == "") {
this.className = "";
this.Parent.Parent.Data = null;
return;
}
var v = this.value.replace(/\\/g, "-").replace(/\//g, "-").replace(/T/g, " ").replace(/\.000/g, "").replace(/Z/g, "");
var parts = v.split(" ");
var dParts = parts[0].split("-");
var tParts = [];
if (parts.length > 1)
tParts = parts[1].split(":");
var year=0, month=1, day=1, hour=0, minute=0, second=0;
if (dParts.length >= 3) {
if (dParts[0].length > 2) { // Starts with year
year = parseInt(dParts[0]);
month = parseInt(dParts[1]);
day = parseInt(dParts[2]);
} else if (dParts[0].length == 2 && dParts[1].length == 2 && dParts[2].length == 2) { // dd-MM-yy
day = parseInt(dParts[0]);
month = parseInt(dParts[1]);
year = 2000 + parseInt(dParts[2]);
} else {
day = parseInt(dParts[0]);
month = parseInt(dParts[1]);
year = parseInt(dParts[2]);
}
}
if (tParts.length >= 2) {
hour = parseInt(tParts[0]);
minute = parseInt(tParts[1]);
if (tParts.length >= 3)
second = parseInt(tParts[2]);
}
var validDate = true;
if (year < 1900 || year > 9999 || day > 31 || day < 1 || month < 1 || month > 12 || hour >= 24 || hour < 0 || minute < 0 || minute >= 60 || second < 0 || second >= 60) {
validDate = false;
}
var tmpDateTime = null;
var obj = this.Parent.Parent;
if (obj.GetTimeZone() == "UTC") {
tmpDateTime = new Date(year + "-" + obj.NumberFormat(month) + "-" + obj.NumberFormat(day) + "T" + obj.NumberFormat(hour) + ":" + obj.NumberFormat(minute) + ":" + obj.NumberFormat(second)+"Z");
} else {
tmpDateTime = new Date(year, month - 1, day, hour, minute, second);
}
if (!validDate || isNaN(tmpDateTime.getHours())) {
this.className = "invalidDate";
return;
}
this.className = "";
this.Parent.Parent.RenderDateInput(this.Parent.Parent.Elements.Selection, tmpDateTime.toISOString());
},
onblur: function () {
if (this.Parent.Parent.readOnly || this.Parent.Parent.disabled)
return;
var obj = this;
if (obj.Parent.Parent.Elements.Selection.InRelativeEditor)
return; // Don't auto hide the relative editor
this.TimeOut = setTimeout(function () {
obj.TimeOut = 0;
if (obj.Parent.Parent.Elements.Selection) {
obj.Parent.Parent.Elements.Selection.style.display = "none";
obj.Parent.Parent.Elements.Selection.style.position = "absolute";
obj.Parent.Parent.Elements.Selection.style.top = "";
obj.Parent.Parent.Elements.Selection.style.left = "";
obj.Parent.Parent.appendChild(obj.Parent.Parent.Elements.Selection); // Move element back (so the next time the position will be correct as well)
}
}, 250);
},
onfocus: function () {
if (this.Parent.Parent.readOnly || this.Parent.Parent.disabled)
return;
if (this.TimeOut)
clearTimeout(this.TimeOut);
// TODO: Append the selection div to the body and use a fixed positioning so the selection div will be over anything
this.Parent.Parent.Elements.Selection.style.display = "";
this.Parent.Parent.Elements.Selection.style.zIndex = "20000";
this.Parent.Parent.Elements.Selection.DetachElementFromParent();
}
},
}
},
Selection: {
style: { display: "none"}
}
},
NumberFormat: function (d) {
return d < 10 ? "0" + d : "" + d;
},
FormatOffset: function (offsetInMinutes) {
var direction = offsetInMinutes < 0 ? "-" : "+";
offsetInMinutes = Math.abs(offsetInMinutes);
var hours = Math.floor(offsetInMinutes / 60);
var minutes = offsetInMinutes % 60;
return direction + this.NumberFormat(hours) + ":" + this.NumberFormat(minutes);
},
RefreshDateInput: function (dontFocus) {
var obj = this;
if (this.EnableTimeZone) {
if (this.GetTimeZone() == "UTC") {
this.Elements.DateInputContainer.Elements.TimeZoneInfo.innerHTML = "UTC";
this.Elements.DateInputContainer.Elements.TimeZoneInfo.title = "Universal timezone";
} else if (this.GetTimeZone() == "Local") {
if (this.Data) {
this.Elements.DateInputContainer.Elements.TimeZoneInfo.innerHTML = this.FormatOffset(-(new Date(this.Data).getTimezoneOffset()));
//this.Elements.DateInputContainer.Elements.TimeZoneInfo.style.display = "";
} else {
this.Elements.DateInputContainer.Elements.TimeZoneInfo.innerHTML = this.FormatOffset(-(new Date().getTimezoneOffset()));
//this.Elements.DateInputContainer.Elements.TimeZoneInfo.style.display = "none";
}
try {
var timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
this.Elements.DateInputContainer.Elements.TimeZoneInfo.title = timeZone;
timeZone = timeZone.replace("/", "");
if (this.DisplayCodes[timeZone]) {
this.Elements.DateInputContainer.Elements.TimeZoneInfo.innerHTML = this.DisplayCodes[timeZone];
}
} catch (errie) {
this.Elements.DateInputContainer.Elements.TimeZoneInfo.title = "Local timezone";
}
} else {
// TODO
}
var customTimeZoneText = this.GetTimeZoneText();
if (customTimeZoneText) {
this.Elements.DateInputContainer.Elements.TimeZoneInfo.innerHTML = customTimeZoneText;
}
}
this.Elements.DateInputContainer.Elements.DateInput.readOnly = this.readOnly ? true : false;
this.Elements.DateInputContainer.Elements.DateInput.disabled = this.disabled ? true : false;
var isRelative = (this.EnableRelative && this.Data && this.Data.indexOf && this.Data.indexOf("|") >= 0);
this.className = "toolkitDateTime" + (this.disabled ? " toolkitDateTimeDisabled" : "") + (this.readOnly ? " toolkitDateTimeReadOnly" : "") + (isRelative ? " toolkitDateTimeRelative" : "");
if (!this.Data) {
this.Elements.DateInputContainer.Elements.DateInput.value = "";
return;
}
var d;
if (isRelative) {
// Parse and display
d = window.TK.DateTimeRelativeToDateObj(this.Data, this.GetTimeZone());
} else {
var d = new Date(this.Data);
}
if (this.GetTimeZone() == "UTC") {
this.Elements.DateInputContainer.Elements.DateInput.value = obj.NumberFormat(d.getUTCFullYear()) + "-" + obj.NumberFormat(d.getUTCMonth() + 1) + "-" + obj.NumberFormat(d.getUTCDate());
if (this.EnableTime)
this.Elements.DateInputContainer.Elements.DateInput.value += " " + obj.NumberFormat(d.getUTCHours()) + ":" + obj.NumberFormat(d.getUTCMinutes()) + ":" + obj.NumberFormat(d.getUTCSeconds());
} else if (this.GetTimeZone() == "Local") {
this.Elements.DateInputContainer.Elements.DateInput.value = obj.NumberFormat(d.getFullYear()) + "-" + obj.NumberFormat(d.getMonth() + 1) + "-" + obj.NumberFormat(d.getDate());
if (this.EnableTime)
this.Elements.DateInputContainer.Elements.DateInput.value += " " + obj.NumberFormat(d.getHours()) + ":" + obj.NumberFormat(d.getMinutes()) + ":" + obj.NumberFormat(d.getSeconds());
} else {
// TODO: Implement custom timezones
}
if (!dontFocus)
this.Elements.DateInputContainer.Elements.DateInput.focus();
},
GetTimeZone: function () {
return this.UseGlobalTimeZone ? window.TK.DateTime.TimeZone : this.TimeZone;
},
SetTimeZone: function (newTimeZone) {
if (this.UseGlobalTimeZone) {
window.TK.DateTime.TimeZone = newTimeZone;
var allPickers = document.querySelectorAll(".toolkitDateTimeSelector");
for (var i = 0; i < allPickers.length; i++) {
if (allPickers[i].Parent && allPickers[i].Parent.RenderDateInput && allPickers[i].Parent.UseGlobalTimeZone) {
allPickers[i].Parent.RenderDateInput(allPickers[i], allPickers[i].DateISO);
allPickers[i].Parent.RefreshDateInput(true);
}
}
} else {
this.TimeZone = newTimeZone;
this.RenderDateInput(this.Elements.Selection, this.Data);
this.RefreshDateInput(true);
}
},
RenderDateInput: function (element, dateISO) {
var obj = this;
if (this.NotFirst && dateISO != this.Data) {
this.Data = dateISO;
if (this.onchange)
this.onchange();
}
this.NotFirst = true;
this.Data = dateISO;
element.DateISO = dateISO;
if (!dateISO)
dateISO = new Date().toISOString();
if (this.EnableRelative && dateISO.indexOf("|") >= 0) {
element.InRelativeEditor = true;
// Show relative editor
element.className = "toolkitDateTimeSelector toolkitDateTimeSelectorRelative";
element.innerHTML = "";
element.onclick = function () { };
var topButtonContainerR = document.createElement("DIV");
topButtonContainerR.className = "topButtonContainer";
var switchRelativeButtonR = document.createElement("DIV");
switchRelativeButtonR.className = "switchRelativeButton";
switchRelativeButtonR.innerHTML = "Relative Date";
switchRelativeButtonR.onclick = function () {
// Switch back
obj.RenderDateInput(element, window.TK.DateTimeRelativeToDateObj(dateISO, obj.GetTimeZone()).toISOString());
};
topButtonContainerR.appendChild(switchRelativeButtonR);
element.appendChild(topButtonContainerR);
var parts = dateISO.split(/\|/g);
var lineContainer = document.createElement("DIV");
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
if (p.length == 0)
continue;
var line = document.createElement("DIV");
line.className = "toolkitRelativeDateLine";
var selectPart = document.createElement("SELECT");
selectPart.appendChild(new Option("Year", "y"));
selectPart.appendChild(new Option("Month", "M"));
selectPart.appendChild(new Option("Day", "d"));
selectPart.appendChild(new Option("Hour", "H"));
selectPart.appendChild(new Option("Minute", "m"));
selectPart.appendChild(new Option("Weekday", "w"));
selectPart.value = p.substr(0, 1);
p = p.substr(1);
line.appendChild(selectPart);
var selectMutation = document.createElement("SELECT");
selectMutation.appendChild(new Option("=>", ""));
selectMutation.appendChild(new Option("+"));
selectMutation.appendChild(new Option("-"));
selectMutation.value = "";
if (p.length > 0 && p.substr(0, 1) == "+" || p.substr(0, 1) == "-") {
selectMutation.value = p.substr(0, 1);
p = p.substr(1);
}
line.appendChild(selectMutation);
var inputValue = document.createElement("INPUT");
line.appendChild(inputValue);
if (p.length > 0) {
inputValue.value = p;
}
var removeLineButton = document.createElement("BUTTON");
removeLineButton.innerHTML = "x";
removeLineButton.onclick = function () {
this.parentNode.parentNode.removeChild(this.parentNode);
};
removeLineButton.className = "removeLineButton";
line.appendChild(removeLineButton);
line.Part = selectPart;
line.Mutation = selectMutation;
line.Value = inputValue;
lineContainer.appendChild(line);
}
lineContainer.GetRelativeDate = function () {
var str = "|";
for (var i = 0; i < this.childNodes.length; i++) {
if (this.childNodes[i].Value.value != "" && !isNaN(parseInt(this.childNodes[i].Value.value)))
str += this.childNodes[i].Part.value + this.childNodes[i].Mutation.value + this.childNodes[i].Value.value + "|";
}
return str;
};
element.appendChild(lineContainer);
var addLineButton = document.createElement("BUTTON");
addLineButton.className = "toolkitAddLineButton";
addLineButton.innerHTML = "+";
addLineButton.onclick = function () {
obj.RenderDateInput(element, lineContainer.GetRelativeDate() + "|d-1");
};
element.appendChild(addLineButton);
var applyButton = document.createElement("BUTTON");
applyButton.className = "toolkitApplyButton";
applyButton.innerHTML = "Apply";
applyButton.onclick = function () {
obj.RenderDateInput(element, lineContainer.GetRelativeDate());
obj.RefreshDateInput();
element.style.display = "none";
};
element.appendChild(applyButton);
obj.Elements.DateInputContainer.Elements.DateInput.focus();
return;
}
element.InRelativeEditor = false;
var dateObj = new Date(dateISO);
element.className = "toolkitDateTimeSelector";
element.innerHTML = "";
element.onclick = function () {
obj.Elements.DateInputContainer.Elements.DateInput.focus();
};
window.TK.DateTimeUpdateDateObject(dateObj, obj.GetTimeZone());
var getButtons = function (text, funcPrevious, funcNext) {
var div = document.createElement("DIV");
div.className = "buttonLine";
div.PreviousButton = document.createElement("BUTTON");
div.PreviousButton.innerHTML = "<";
div.PreviousButton.className = "previousButton";
div.PreviousButton.onclick = funcPrevious;
div.PreviousButton.type = "button";
div.PreviousButton.tabIndex = -1;
div.StatusText = document.createElement("DIV");
div.StatusText.className = "statusText";
div.StatusText.innerHTML = text;
div.NextButton = document.createElement("BUTTON");
div.NextButton.innerHTML = ">";
div.NextButton.onclick = funcNext;
div.NextButton.className = "nextButton";
div.NextButton.type = "button";
div.NextButton.tabIndex = -1;
div.appendChild(div.PreviousButton);
div.appendChild(div.StatusText);
div.appendChild(div.NextButton);
return div;
};
var topButtonContainer = document.createElement("DIV");
topButtonContainer.className = "topButtonContainer";
if (this.EnableTimeZone) {
var switchUTCButton = document.createElement("DIV");
switchUTCButton.className = "switchUTCButton";
switchUTCButton.innerHTML = this.GetTimeZone() == "UTC" ? "UTC" : obj.FormatOffset(-dateObj.getTimezoneOffset());
switchUTCButton.tabIndex = -1;
try {
if (this.GetTimeZone() == "Local") {
var timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
switchUTCButton.title = timeZone;
timeZone = timeZone.replace("/", "");
if (this.DisplayCodes[timeZone]) {
switchUTCButton.innerHTML = this.DisplayCodes[timeZone];
}
}
} catch (errie) { }
switchUTCButton.onclick = function () {
obj.SetTimeZone(obj.GetTimeZone() == "UTC" ? "Local" : "UTC");
};
switchUTCButton.title = dateISO + " - " + dateObj.toLocaleString();
topButtonContainer.appendChild(switchUTCButton);
}
if (this.EnableRelative) {
var switchRelativeButton = document.createElement("DIV");
switchRelativeButton.innerHTML = "Fixed date";
switchRelativeButton.className = "switchRelativeButton";
switchRelativeButton.onclick = function () {
// Switch to relative
obj.RenderDateInput(element, "y" + dateObj.getFullYear() + "|M" + (dateObj.getMonth() + 1) + "|d" + dateObj.getDate() + "|H" + dateObj.getHours() + "|m" + dateObj.getMinutes());
};
switchRelativeButton.tabIndex = -1;
topButtonContainer.appendChild(switchRelativeButton);
}
element.appendChild(topButtonContainer);
element.appendChild(getButtons(dateObj.getFullYear(),
function () {
dateObj.setFullYear(dateObj.getFullYear() - 1);
obj.RenderDateInput(element, dateObj.toISOString());
obj.RefreshDateInput();
},function () {
dateObj.setFullYear(dateObj.getFullYear() + 1);
obj.RenderDateInput(element, dateObj.toISOString());
obj.RefreshDateInput();
obj.Elements.DateInputContainer.Elements.DateInput.focus();
}));
element.appendChild(getButtons(obj.MonthNames[dateObj.getMonth()],
function () {
var expectedMonth = (dateObj.getMonth() - 1) % 12;
dateObj.setMonth(dateObj.getMonth() - 1);
if (dateObj.getMonth() != expectedMonth)
dateObj.setDate(dateObj.getDate() - 1);
obj.RenderDateInput(element, dateObj.toISOString());
obj.RefreshDateInput();
}, function () {
var expectedMonth = (dateObj.getMonth() + 1) % 12;
dateObj.setMonth(dateObj.getMonth() + 1);
if (dateObj.getMonth() != expectedMonth)
dateObj.setDate(dateObj.getDate() - 1);
obj.RenderDateInput(element, dateObj.toISOString());
obj.RefreshDateInput();
}));
var daySelection = getButtons("",
function () {
dateObj.setDate(dateObj.getDate() - 1);
obj.RenderDateInput(element, dateObj.toISOString());
obj.RefreshDateInput();
}, function () {
dateObj.setDate(dateObj.getDate() + 1);
obj.RenderDateInput(element, dateObj.toISOString());
obj.RefreshDateInput();
});
daySelection.StatusText.className = "statusText daySelection";
var firstDay = new Date(dateISO);
firstDay.setDate(1);
var getDay = function (dateObj) {
return (dateObj.getDay() - obj.WeekStart) < 0 ? 7 + (dateObj.getDay() - obj.WeekStart) : (dateObj.getDay() - obj.WeekStart);
};
var lineCount = 0;
for (var i = 1 - getDay(firstDay); i <= 31 || lineCount < 7; i++) {
if (lineCount == 7) {
daySelection.StatusText.appendChild(document.createElement("BR"));
lineCount = 0;
}
lineCount++;
var tmpDateObj = new Date(dateISO);
var curMonth = tmpDateObj.getMonth();
tmpDateObj.setDate(i);
if (i >= 28 && lineCount == 1 && tmpDateObj.getMonth() != curMonth)
break;
var dayItem = document.createElement("BUTTON");
dayItem.innerHTML = tmpDateObj.getDate();
dayItem.className = "dayItem " + (i == dateObj.getDate() ? "selected" : "") + (tmpDateObj.getMonth() != curMonth ? " otherMonth" : "");
//dayItem.title = tmpDateObj.toISOString();
dayItem.DateIndex = i;
dayItem.tabIndex = -1;
dayItem.onclick = function (e) {
dateObj.setDate(this.DateIndex);
dateObj.setMilliseconds(0);
if (obj.AlwaysNavigateToStartOfDay || (!obj.Data && (dateObj.getDate() != new Date().getDate() || dateObj.getDay() != new Date().getDay() || dateObj.getFullYear() != new Date().getFullYear()))) {
// Different day, default to 00:00:00
dateObj.setHours(0);
dateObj.setMinutes(0);
dateObj.setSeconds(0);
}
obj.RenderDateInput(element, dateObj.toISOString());
obj.RefreshDateInput(true);
var event = e || window.event;
event.stopPropagation();
return false;
};
daySelection.StatusText.appendChild(dayItem);
}
element.appendChild(daySelection);
if (this.EnableTime) {
element.appendChild(getButtons(obj.NumberFormat(dateObj.getHours()) + ":" + obj.NumberFormat(dateObj.getMinutes()) + ":" + obj.NumberFormat(dateObj.getSeconds()),
function () {
dateObj.setUTCMinutes(dateObj.getUTCMinutes() - 15);
obj.RenderDateInput(element, dateObj.toISOString());
obj.RefreshDateInput();
}, function () {
dateObj.setUTCMinutes(dateObj.getUTCMinutes() + 15);
obj.RenderDateInput(element, dateObj.toISOString());
obj.RefreshDateInput();
}));
}
//element.appendChild(document.createTextNode(dateObj.toString()));
},
Destroy: function () {
if (this.Elements.Selection)
this.Elements.Selection.Remove();
}
};
window.TK.DateTime.TimeZone = "Local";
window.TK.DateTimeUpdateDateObject = function (dateObj, timeZone) {
if (timeZone == "UTC") {
dateObj.getMonth = dateObj.getUTCMonth;
dateObj.setMonth = dateObj.setUTCMonth;
dateObj.getHours = dateObj.getUTCHours;
dateObj.setHours = dateObj.setUTCHours;
dateObj.getMinutes = dateObj.getUTCMinutes;
dateObj.setMinutes = dateObj.setUTCMinutes;
dateObj.getSeconds = dateObj.getUTCSeconds;
dateObj.setSeconds = dateObj.setUTCSeconds;
dateObj.getDate = dateObj.getUTCDate;
dateObj.setDate = dateObj.setUTCDate;
}
};
window.TK.DateTimeRelativeToDateObj = function (dateStr, timeZone) {
var dateObj = new Date();
window.TK.DateTimeUpdateDateObject(dateObj, timeZone);
dateObj.setSeconds(0);
dateObj.setMilliseconds(0);
var parts = dateStr.split('|');
for (var i = 0; i < parts.length; i++) {
if (parts[i].length < 2)
continue;
if (parts[i][1] == "+" || parts[i][1] == "-") {
var value = parseInt(parts[i].substr(2));
if (parts[i][1] == "-")
value = -value;
if (parts[i][0] == "y")
dateObj.setFullYear(dateObj.getFullYear() + value);
else if (parts[i][0] == "M")
dateObj.setMonth(dateObj.getMonth() + (value));
else if (parts[i][0] == "d")
dateObj.setDate(dateObj.getDate() + value);
else if (parts[i][0] == "H")
dateObj.setHours(dateObj.getHours() + value);
else if (parts[i][0] == "m")
dateObj.setMinutes(dateObj.getMinutes() + value);
else if (parts[i][0] == "s")
dateObj.setSeconds(dateObj.getSeconds() + value);
else if (parts[i][0] == "w") {
var realModification = Math.abs(value);
if (realModification == 7)
realModification = 0;
dateObj.setDate(dateObj.getDate() + (realModification - dateObj.getDay()));
if (dateObj.getDay() < realModification) {
if (value < 0)
dateObj.setDate(dateObj.getDate() - 7);
}
else {
if (value > 0)
dateObj.setDate(dateObj.getDate() + 7);
}
}
} else { // Set
var value = parseInt(parts[i].substr(1));
if (parts[i][0] == "y")
dateObj.setFullYear(value);
else if (parts[i][0] == "M")
dateObj.setMonth(value - 1);
else if (parts[i][0] == "d")
dateObj.setDate(value);
else if (parts[i][0] == "H")
dateObj.setHours(value);
else if (parts[i][0] == "m")
dateObj.setMinutes(value);
else if (parts[i][0] == "s")
dateObj.setSeconds(value);
else if (parts[i][0] == "w") {
var isoDay = dateObj.getDay();
if (isoDay == 0)
isoDay = 7;
dateObj.setDate(dateObj.getDate() + (value - isoDay));
}
}
}
return dateObj;
};
if (window.TK.Form) {
window.TK.Form.DefaultTemplates.datetime = {
_: TK.DateTime
};
window.TK.Form.DefaultTemplates.date = {
_: TK.DateTime,
EnableTime: false
};
window.TK.Form.DefaultTemplates.datetimeasp = {
className: "dateTimeAsp",
Init: function () {
var isoString = null;
if (this.Data) {
isoString = window.ConvertFromASPTime(this.Data);
if (!isoString)
isoString = new Date().toISOString();
}
this.Add({
_: TK.DateTime,
Data: isoString,
disabled: this.disabled,
readOnly: this.readOnly,
onchange: this.onchange,
onfocus: this.onfocus,
onblur: this.onblur,
DataSettings: this.DataSettings
}, "DateInput");
},
GetValue: function () {
var value = this.Elements.DateInput.GetValue();
if (!value)
return value;
var time = new Date(value).getTime();
if (isNaN(time)) {
alert("Date time value of " + value + " is not valid.");
throw "Date time value of " + value + " is not valid.";
}
return "/Date(" + time + ")/";
}
};
}
"use strict";
/* Minify Order(110) */
TK.HtmlEditor = {
className: "toolkitHtmlEditor",
FillContainer: false,
Buttons: ["IncreaseFontSize", "DecreaseFontSize", "Bold", "Italic", "Underline", "AlignLeft", "AlignCenter", "AlignRight", "Indent", "Outdent", "Paragraph", "Header1", "Header2", "Header3", "CodeBlock", "QuoteBlock"],
__RecursivePropertiesButtonTemplates: true,
EnableHTMLPasting: true,
RemoveScripts: true,
RemoveScriptsHandler: function (html) {
var len = -1;
while (len != html.length) {
len = html.length;
html = html.replace(/<(script|link|iframe|noscript|meta|object|embed|frameset|style)/ig, " 1)
this.Parent.CurSize--;
document.execCommand("fontSize", false, this.Parent.CurSize);
this.Near("Editor").focus();
}
},
Bold: {
innerHTML: Svg.Icons.TextBold,
onmousedown: function () {
document.execCommand("bold", false, null);
this.Near("Editor").focus();
}
},
Italic: {
innerHTML: Svg.Icons.TextItalic,
onmousedown: function () {
document.execCommand("italic", false, null);
this.Near("Editor").focus();
}
},
Underline: {
innerHTML: Svg.Icons.TextUnderline,
onmousedown: function () {
document.execCommand("underline", false, null);
this.Near("Editor").focus();
}
},
AlignLeft: {
innerHTML: Svg.Icons.TextAlignLeft,
onmousedown: function () {
document.execCommand("justifyLeft", false, null);
this.Near("Editor").focus();
}
},
AlignCenter: {
innerHTML: Svg.Icons.TextAlignCenter,
onmousedown: function () {
document.execCommand("justifyCenter", false, null);
this.Near("Editor").focus();
}
},
AlignRight: {
innerHTML: Svg.Icons.TextAlignRight,
onmousedown: function () {
document.execCommand("justifyRight", false, null);
this.Near("Editor").focus();
}
},
Indent: {
innerHTML: Svg.Icons.TextIndent,
onmousedown: function () {
document.execCommand("indent", false, null);
this.Near("Editor").focus();
}
},
Outdent: {
innerHTML: Svg.Icons.TextOutdent,
onmousedown: function () {
document.execCommand("outdent", false, null);
this.Near("Editor").focus();
}
},
Paragraph: {
title: "Paragraph",
innerHTML: Svg.Icons.TextParagraph,
onmousedown: function () {
document.execCommand("formatBlock", false, "p");
this.Near("Editor").focus();
}
},
Header1: {
title: "Header 1",
innerHTML: Svg.Icons.TextHeader1,
onmousedown: function () {
document.execCommand("formatBlock", false, "h1");
this.Near("Editor").focus();
}
},
Header2: {
title: "Header 2",
innerHTML: Svg.Icons.TextHeader2,
onmousedown: function () {
document.execCommand("formatBlock", false, "h2");
this.Near("Editor").focus();
}
},
Header3: {
title: "Header 3",
innerHTML: Svg.Icons.TextHeader3,
onmousedown: function () {
document.execCommand("formatBlock", false, "h3");
this.Near("Editor").focus();
}
},
CodeBlock: {
title: "Code block",
innerHTML: Svg.Icons.TextCodeBlock,
onmousedown: function () {
document.execCommand("formatBlock", false, "pre");
this.Near("Editor").focus();
}
},
QuoteBlock: {
title: "Quote block",
innerHTML: Svg.Icons.TextQuoteBlock,
onmousedown: function () {
document.execCommand("formatBlock", false, "blockquote");
}
}
},
Data: null,
Init: function () {
if (this.Data)
this.Elements.Editor.innerHTML = this.RemoveScripts ? this.RemoveScriptsHandler(this.Data) : this.Data;
if (this.FillContainer) {
this.style.position = "absolute";
this.style.top = "0px";
this.style.left = "0px";
this.style.right = "0px";
this.style.bottom = "0px";
this.Elements.MenuBar.style.position = "absolute";
this.Elements.MenuBar.style.top = "0px";
this.Elements.MenuBar.style.left = "0px";
this.Elements.MenuBar.style.right = "0px";
this.Elements.MenuBar.style.height = "35px";
this.Elements.Editor.style.position = "absolute";
this.Elements.Editor.style.top = "35px";
this.Elements.Editor.style.left = "0px";
this.Elements.Editor.style.right = "0px";
this.Elements.Editor.style.bottom = "0px";
}
},
GetValue: function () {
return this.Elements.Editor.innerHTML.replace(//g, "").replace(/<\/b>/g, "").replace(//g, "").replace(/<\/i>/g, "");
},
Elements: {
MenuBar: {
CurSize: 3,
Init: function () {
for (var i = 0; i < this.Parent.Buttons.length;i++) {
if (this.Parent.ButtonTemplates[this.Parent.Buttons[i]])
this.Add({
_: this.Parent.ButtonTemplates[this.Parent.Buttons[i]],
onmouseup: function () {
this.Near("Editor").focus();
}
});
}
},
onselectstart: function () { return false; }
},
Editor: {
contentEditable: true,
onclick: function () {
this.Near("MenuBar").CurSize = 3; // TODO: Handle this a lot better.. but at least this works in Chrome
},
onpaste: function (e) {
if (e.clipboardData) {
e.preventDefault();
if (this.Parent.EnableHTMLPasting && e.clipboardData.types && e.clipboardData.types.indexOf("text/html") >= 0) {
try {
var html = e.clipboardData.getData("text/html");
document.execCommand("insertHTML", false, this.Parent.RemoveScripts ? this.Parent.RemoveScriptsHandler(html) : html);
return;
} catch (errie) { } // If insertHTML is not supported for any reason, we will still paste it as text
}
var text = e.clipboardData.getData("text");
document.execCommand("insertText", false, text);
}
},
onkeydown: function (e) {
if (e.keyCode === 13 && !e.shiftKey) {
this.RemoveFormat = true;
}
},
onkeyup: function (e) {
if (this.RemoveFormat) {
document.execCommand("formatBlock", false, "div");
this.RemoveFormat = null;
}
}
}
}
};
if (window.TK.Form) {
window.TK.Form.DefaultTemplates.html = {
_: TK.HtmlEditor
};
}
"use strict";
/* Minify Skip */
/* Minify Order(150) */
TK.Draw = {
_: "canvas",
Width: 100,
Height: 100,
Scale: 2, // Rendering scale, increase to keep sharpness when zooming in on the page but decrease performance
Zoom: 1,
ViewPortX: 0,
ViewPortY: 0,
EnableNavigation: false, // If true, the canvas can be dragged around and zoomed in/out using mouse wheel
EnableZoom: false,
MinZoom: 0.2,
MaxZoom: 10,
Animations: [],
Init: function () {
this.Context = this.GetContext();
this.Context.CanvasObj = this;
this.SetSize(this.Width, this.Height);
},
SetSize: function (width, height, parsePositionTags) {
this.Width = width;
this.Height = height;
this.width = width * this.Scale;
this.height = height * this.Scale;
this.style.width = width + "px";
this.style.height = height + "px";
if (parsePositionTags && this.SortedElements) {
for (var i = 0; i < this.SortedElements.length; i++) {
if (this.SortedElements[i]._NormalizePositions !== false)
TK.Draw.SetPositionsUsingPositionProperty(this.SortedElements[i]);
if (this.SortedElements[i].Resize)
this.SortedElements[i].Resize();
}
}
this.Refresh();
},
GetContext: function () {
return this.getContext("2d");
},
Refresh: function (skipSortElements) {
if (this.RefreshAlreadyQueued) {
if (!skipSortElements)
this.ForceSortElements = true;
return;
}
if (this.width != this.Width * this.Scale || this.height != this.Height * this.Scale) {
this.width = this.Width;
this.height = this.Height;
}
var obj = this;
var hasAnimation = this.ProcessAnimations();
// TODO: If EnableNavigation is true, Draw on an offscreen canvas
// TODO: Find a way to only redraw whats needed
this.Context.setTransform(this.Scale, 0, 0, this.Scale , 0, 0);
this.Context.clearRect(0, 0, this.Width, this.Height);
if (!skipSortElements || !this.SortedElements || this.ForceSortElements) {
this.SortElements();
}
for (var i = 0; i < this.SortedElements.length; i++) {
this.Context.OffsetX = -this.ViewPortX;
this.Context.OffsetY = -this.ViewPortY;
this.Context.Scale = this.Scale * this.Zoom;
if (this.SortedElements[i].Draw)
this.SortedElements[i].Draw(this.Context);
}
if (hasAnimation) {
this.RefreshAlreadyQueued = true;
requestAnimationFrame(function () { obj.RefreshAlreadyQueued = false; obj.Refresh(true); });
}
},
ProcessAnimations: function () {
// Process animations
var cur = new Date().getTime();
var hasAnimation = false;
for (var i = 0; i < this.Animations.length; i++) {
if (!this.Animations[i])
continue;
var a = this.Animations[i];
var r = (cur - a.S) / a.L; // 500 - 400 = 100 / 400 = 0.25
if (r >= 1) {
r = 1;
this.Animations[i] = null;
if (a.I.AnimationEnded)
a.I.AnimationEnded(a.P);
if (a.AnimationEnded)
a.AnimationEnded(a.P);
}
if (Array.isArray(a.O)) {
var rgba = [0, 0, 0, 0];
for (var j = 0; j < a.O.length; j++) {
if (Array.isArray(a.O[j])) {
// Point array
for (var n = 0; n < a.O[j].length; n++) {
a.I[a.P][j][n] = a.E(a.O[j][n], a.T[j][n], r);
}
} else if (a.O.length == 4) {
// Colors
rgba[j] = a.E(a.O[j], a.T[j], r);
}
}
if (a.O.length == 4) {
a.I[a.P] = "rgba(" + rgba.join(",") + ")";
}
} else {
a.I[a.P] = a.E(a.O, a.T, r);
}
//a.I[a.P] = a.O + ((a.T - a.O) * r);
hasAnimation = true;
if (a.I.Invalidate) {
a.I.Invalidate();
}
}
return hasAnimation;
},
SortElements: function () {
this.ForceSortElements = false;
this.SortedElements = [];
for (var ele in this.Elements) {
if (this.Elements[ele].Draw) {
this.SortedElements.push(this.Elements[ele]);
}
}
this.SortedElements = this.SortedElements.OrderBy(function (a) {
return a.ZIndex;
});
},
onclick: function (e) {
this.HandleMouseEvent(e, "Click");
},
onmousemove: function (e) {
this.HandleMouseEvent(e, "MouseOver");
this.HandleMouseEvent(e, "MouseMove");
this.HandleMouseEvent(e, "MouseOut");
},
ontouchmove: function (e) {
this.HandleMouseEvent(e, "MouseOver");
this.HandleMouseEvent(e, "MouseMove");
this.HandleMouseEvent(e, "MouseOut");
e.preventDefault();
},
onmouseout: function (e) {
this.HandleMouseEvent(e, "MouseOut");
},
onmousedown: function (e) {
this.HandleMouseEvent(e, "MouseDown");
},
ontouchstart: function (e) {
this.HandleMouseEvent(e, "MouseDown");
e.preventDefault();
},
onmouseup: function (e) {
this.HandleMouseEvent(e, "MouseUp");
},
ontouchend: function (e) {
this.HandleMouseEvent(e, "MouseUp");
e.preventDefault();
},
/*onpointerdown: function (e) {
this.HandleMouseEvent(e, "MouseDown");
},
onpointermove: function (e) {
this.HandleMouseEvent(e, "MouseOver");
this.HandleMouseEvent(e, "MouseMove");
this.HandleMouseEvent(e, "MouseOut");
},
onpointerup: function (e) {
this.HandleMouseEvent(e, "MouseUp");
},*/
onwheel: function (event) {
if (this.EnableZoom) {
if (!event)
event = window.event;
if (event.preventDefault)
event.preventDefault();
var zoomInPos = [this.ViewPortX + (this.Width / 2 / this.Zoom), this.ViewPortY + (this.Height / 2 / this.Zoom)];
this.Zoom -= event.deltaY < 0 ? -0.25 : 0.25;
if (this.Zoom < this.MinZoom)
this.Zoom = this.MinZoom;
else if (this.Zoom > this.MaxZoom)
this.Zoom = this.MaxZoom;
// Adjust viewport as we want to zoom in with zoomInPos as center
this.Center(zoomInPos[0], zoomInPos[1]);
this.Refresh(true);
}
},
Center: function (x, y, animateLength, animateEase) { // world space px
// Adjust ViewPortX and ViewPortY so that the x and y positions are in the middle
x = x - ((this.Width / 2) / this.Zoom); // world space px
y = y - ((this.Height / 2) / this.Zoom);
if (animateLength) {
this.Animations.push({ I: this, P: "ViewPortX", O: this.ViewPortX, T: x, L: animateLength, E: animateEase ? animateEase : TK.Draw.EaseExponential, S: new Date().getTime() });
this.Animations.push({ I: this, P: "ViewPortY", O: this.ViewPortY, T: y, L: animateLength, E: animateEase ? animateEase : TK.Draw.EaseExponential, S: new Date().getTime() });
this.Refresh();
} else {
this.ViewPortX = x;
this.ViewPortY = y;
}
},
HandleMouseEvent: function (e, func) {
var eventHandled = false;
var x, y;
try { x = e.clientX; y = e.clientY; } catch (errie) { var e2 = window.event; x = e2.clientX; y = e2.clientY; }
if (e && e.changedTouches && e.changedTouches.length > 0) {
x = e.changedTouches[0].clientX;
y = e.changedTouches[0].clientY;
}
var rect = this.getBoundingClientRect();
// Make sure top/left is always 0,0, then Compensate for the zoom level, then Add the offset from the viewport
x = ((x - rect.left) / this.Zoom) + this.ViewPortX;
y = ((y - rect.top) / this.Zoom) + this.ViewPortY;
var stoppedPropagation = false;
if (!this.SortedElements || this.ForceSortElements) {
this.SortElements();
}
for (var i = this.SortedElements.length - 1; i >= 0; i--) {
var el = this.SortedElements[i];
if (!el[func] || !el.GetRect)
continue;
var r = el.GetRect();
if (r === null)
continue;
//r[0] -= this.ViewPortX;
//r[1] -= this.ViewPortY;
var match = false;
for (var j = 0; this.CurrentMouseDownElements && j < this.CurrentMouseDownElements.length; j++) {
if (this.CurrentMouseDownElements[j] == el) {
match = true;
break;
}
}
if (match || (r[0] < x && r[0] + r[2] > x && r[1] < y && r[1] + r[3] > y && (!el.CheckMouseOver || el.CheckMouseOver(x, y))) && !stoppedPropagation) {
if (func == "MouseDown" && this.CurrentMouseDownElements && this.CurrentMouseDownElements.indexOf(el) >= 0) {
el.CurrentlyMouseOver = true;
eventHandled = true;
continue;
}
if (func != "MouseOut" && (func != "MouseOver" || !el.CurrentlyMouseOver)) {
if (el[func](x, y) === true) {
stoppedPropagation = true;
el.StoppedPropagation = true;
}
eventHandled = true;
}
if (el.CurrentlyMouseOver && el.StoppedPropagation) {
stoppedPropagation = true;
}
if (func == "MouseDown") {
if (!this.CurrentMouseDownElements)
this.CurrentMouseDownElements = [];
this.CurrentMouseDownElements.push(el);
}
el.CurrentlyMouseOver = true;
} else if (func == "MouseOut" && el.CurrentlyMouseOver) {
el[func](x, y);
eventHandled = true;
el.CurrentlyMouseOver = false;
el.StoppedPropagation = false;
}
}
if (func == "MouseUp" && this.CurrentMouseDownElements) {
this.CurrentMouseDownElements = null;
}
x = (x - this.ViewPortX) * this.Zoom;
y = (y - this.ViewPortY) * this.Zoom;
if (this.CurrentCanvasInteraction) {
if (func == "MouseMove") {
this.ViewPortX = this.CurrentCanvasInteraction[2] + ((this.CurrentCanvasInteraction[0] - x) / this.Zoom);
this.ViewPortY = this.CurrentCanvasInteraction[3] + ((this.CurrentCanvasInteraction[1] - y) / this.Zoom);
} else if (func == "MouseUp") {
this.CurrentCanvasInteraction = null;
}
} else if (!eventHandled && !this.CurrentMouseDownElements && this.EnableNavigation && func == "MouseDown") {
// Interaction on the canvas itself
this.CurrentCanvasInteraction = [x, y, this.ViewPortX, this.ViewPortY];
}
this.Refresh();
}
};
TK.Draw.AnimationsEnabled = true;
TK.Draw.AnchorLeft = 1;
TK.Draw.AnchorCenter = 2;
TK.Draw.AnchorRight = 4;
TK.Draw.AnchorTop = 8;
TK.Draw.AnchorMiddle = 16;
TK.Draw.AnchorBottom = 32;
TK.Draw.SmoothNone = 0;
TK.Draw.SmoothQuadratic = 1; // Quadratic curvers with the center in between the two points
TK.Draw.SmoothCorners = 2; // Only use horizontal and vertical lines, or small 90 degree corners
TK.Draw.DirectionTop = 0;
TK.Draw.DirectionRight = 1;
TK.Draw.DirectionBottom = 2;
TK.Draw.DirectionLeft = 3;
TK.Draw.EaseLinear = function (a, b, r) { return a + ((b - a) * r); };
TK.Draw.EaseExponential = function (a, b, r) {
var m;
if (r < 0.5) {
m = ((r == 0) ? 0 : Math.pow(2, 10 * (r * 2 - 1)) - 0.001) * 0.5;
} else {
r = (r * 2) - 1;
m = (r == 1) ? 1 : (-Math.pow(2, -10 * r) + 1);
m = 0.5 + 0.5 * m;
}
return a + ((b - a) * m);
};
TK.Draw.EaseBack = function (a, b, r) {
return a + ((b - a) * (r * r * ((2.70158) * r - 1.70158)));
};
TK.Draw.EaseCircular = function(a, b, r) {
return a + ((b - a) * -(Math.sqrt(1 - r * r) - 1.0));
};
TK.Draw.EaseBounce = function (a, b, r) {
var multiplier = 1;
if (r < (1 / 2.75)) {
multiplier = 7.5625 * r * r;
} else if (r < (2 / 2.75)) {
var t = r - (1.5 / 2.75);
multiplier = 7.5625 * t * t + 0.75;
} else if (r < (2.5 / 2.75)) {
var t = r - (2.25 / 2.75);
multiplier = 7.5625 * t * t + 0.9375;
} else {
var t = r - (2.625 / 2.75);
multiplier = 7.5625 * t * t + 0.984375;
}
return a + ((b - a) * multiplier);
};
TK.Draw.EaseCubic = function (a, b, r) {
return a + ((b - a) * (r * r * r));
};
TK.Draw.EaseElastic = function (a, b, r) {
return a + ((b - a) * (1 + Math.pow(2, -10 * r) * Math.sin((r - (0.3 / 4)) * (Math.PI * 2) / 0.3)));
};
TK.Draw.EaseSine = function (a, b, r) {
return a + ((b - a) * (-Math.cos(r * (Math.PI / 2)) + 1));
};
TK.Draw.EaseStrong = function (a, b, r) {
return a + ((b - a) * (r * r * r * r * r));
};
TK.Draw.GetColor = function (s) {
if (s.substr(0, 4) == "rgba") {
return s.replace("rgba(", "").replace(")", "").split(",").Select(function (a) { return parseFloat(a); });
} else if (s.substr(0, 3) == "rgb") {
return (s.replace("rgb(", "").replace(")", "") + ",1").split(",").Select(function (a) { return parseFloat(a); });
} else if (s.substr(0, 1) == "#") {
var c = s.substring(1).split('');
if (c.length == 3)
c = [c[0], c[0], c[1], c[1], c[2], c[2]];
c = '0x' + c.join('');
return [(c >> 16) & 255, (c >> 8) & 255, c & 255, 1];
}
};
TK.Draw.ColorToDifferentColor = function (s, s2, ratio) {
s = TK.Draw.GetColor(s);
s2 = TK.Draw.GetColor(s2);
if (s.length < 4)
s.push(1);
if (s2.length < 4)
s2.push(1);
for (var i = 0; i < 4; i++) {
s[i] = TK.Draw.EaseLinear(s[i], s2[i], ratio);
}
return "rgba(" + s.join(",") + ")";
};
TK.Draw.ValueToPx = function (v, curIsWidth, totalWidth, totalHeight) {
if (!v.substr)
return v;
var total = curIsWidth ? totalWidth : totalHeight;
if (v.indexOf("px") >= 0)
return parseFloat(v.replace("px", ""));
if (v.indexOf("%") >= 0)
return total * (parseFloat(v.replace("%", "")) / 100);
if (v.indexOf("vw") >= 0)
return totalWidth * (parseFloat(v.replace("%", "")) / 100);
if (v.indexOf("vh") >= 0)
return totalHeight * (parseFloat(v.replace("%", "")) / 100);
return parseFloat(v);
};
TK.Draw.SetPositionsUsingPositionProperty = function (drawableObject) {
var t = drawableObject;
if (!t._Position)
return;
var p = t.Parent;
while (p !== undefined && p.ProcessAnimations === undefined) // find the TK.Draw component
p = p.Parent;
if (!p)
return;
var anchorV = TK.Draw.AnchorTop | TK.Draw.AnchorMiddle | TK.Draw.AnchorBottom;
var anchorH = TK.Draw.AnchorLeft | TK.Draw.AnchorCenter | TK.Draw.AnchorRight;
var p = window.TK.ParsePosition(t._Position);
var totalWidth = t.Parent.Width;
var totalHeight = t.Parent.Height;
var isSet = function (v) {
return !(v === undefined || v === null);
};
if (isSet(p[0]) && isSet(p[2])) {
t.Y = TK.Draw.ValueToPx(p[0], false, totalWidth, totalHeight); // 50% -> 150px
t.H = (totalHeight - TK.Draw.ValueToPx(p[2], false, totalWidth, totalHeight)) - t.Y; // 25% -> (300 - 75) = 225 - 150 = 75
t.Anchor = (t.Anchor & anchorH) | TK.Draw.AnchorTop;
} else if (isSet(p[0])) {
t.Y = TK.Draw.ValueToPx(p[0], false, totalWidth, totalHeight);
t.Anchor = (t.Anchor & anchorH) | TK.Draw.AnchorTop;
} else if (isSet(p[2])) {
t.Y = totalHeight - TK.Draw.ValueToPx(p[2], false, totalWidth, totalHeight);
t.Anchor = (t.Anchor & anchorH) | TK.Draw.AnchorBottom;
}
if (isSet(p[1]) && isSet(p[3])) {
t.X = TK.Draw.ValueToPx(p[3], true, totalWidth, totalHeight);
t.W = (totalWidth - TK.Draw.ValueToPx(p[1], true, totalWidth, totalHeight)) - t.X;
t.Anchor = (t.Anchor & anchorV) | TK.Draw.AnchorLeft;
} else if (isSet(p[1])) {
t.X = totalWidth - TK.Draw.ValueToPx(p[1], true, totalWidth, totalHeight);
t.Anchor = (t.Anchor & anchorV) | TK.Draw.AnchorRight;
} else if (isSet(p[3])) {
t.X = TK.Draw.ValueToPx(p[3], true, totalWidth, totalHeight);
t.Anchor = (t.Anchor & anchorV) | TK.Draw.AnchorLeft;
}
if (isSet(p[4]))
t.W = TK.Draw.ValueToPx(p[4], true, totalWidth, totalHeight);
if (isSet(p[5]))
t.H = TK.Draw.ValueToPx(p[5], false, totalWidth, totalHeight);
if (isSet(p[6])) {
if (p[6].indexOf("middle") >= 0)
t.Anchor = (t.Anchor & anchorH) | TK.Draw.AnchorMiddle;
if (p[6].indexOf("top") >= 0)
t.Anchor = (t.Anchor & anchorH) | TK.Draw.AnchorTop;
if (p[6].indexOf("bottom") >= 0)
t.Anchor = (t.Anchor & anchorH) | TK.Draw.AnchorBottom;
if (p[6].indexOf("left") >= 0)
t.Anchor = (t.Anchor & anchorV) | TK.Draw.AnchorLeft;
if (p[6].indexOf("center") >= 0)
t.Anchor = (t.Anchor & anchorV) | TK.Draw.AnchorCenter;
if (p[6].indexOf("right") >= 0)
t.Anchor = (t.Anchor & anchorV) | TK.Draw.AnchorRight;
}
};
// Draws all child elements
TK.Draw.Group = {
DrawType: "Group",
X: 0,
Y: 0,
// Optional, set these so all child elements can use anchor top/left, while the full group respects it's own anchor setting
// This is useful to make self-contained drawable components, and required when wanting to use the _Positions tag
_NormalizePositions: false,
Anchor: null,
W: null, H: null,
Init: function () {
if (this._NormalizePositions)
TK.Draw.SetPositionsUsingPositionProperty(this);
},
Draw: function (c) {
var x = 0;
var y = 0;
if (this._NormalizePositions && this.Anchor !== null && this.W && this.H) {
if ((this.Anchor & TK.Draw.AnchorCenter) > 0) {
x = -(this.W * 0.5);
} else if ((this.Anchor & TK.Draw.AnchorRight) > 0) {
x = -this.W;
}
if ((this.Anchor & TK.Draw.AnchorMiddle) > 0) {
y = -(this.H * 0.5);
} else if ((this.Anchor & TK.Draw.AnchorBottom) > 0) {
y = -this.H;
}
}
c.OffsetX += this.X + x;
c.OffsetY += this.Y + y;
for (var i in this.Elements) {
if (this.Elements[i].Draw)
this.Elements[i].Draw(c);
}
c.OffsetX -= this.X + x;
c.OffsetY -= this.Y + y;
},
GetRect: function () {
return this._NormalizePositions ? TK.Draw.DrawableObject.GetRect.apply(this) : null;
},
Overlaps: function (otherDrawableObject) {
return this._NormalizePositions ? TK.Draw.DrawableObject.Overlaps.apply(this, [otherDrawableObject]) : null;
},
Animate: function (propName, targetValue, ms, easing) {
return TK.Draw.DrawableObject.Animate.apply(this, [propName, targetValue, ms, easing]);
}
};
TK.Draw.DrawableObject = {
DrawType: "DrawableObject",
Fill: null, // Color
Stroke: null, // Color
BlendMode: null, // Any value of globalCompositeOperation
LineWidth: 1,
LineCap: null,
Rotate: null,
Shadow: null, // [X, Y, Size, Color]
ShadowForLine: false,
Anchor: TK.Draw.AnchorLeft | TK.Draw.AnchorTop,
ZIndex: 1,
X: 0, Y: 0, W: 0, H: 0,
_Position: null, // Alternative way of setting positions, similar to the normal toolkit method, but with added anchor support
Opacity: 1,
Init: function () {
TK.Draw.SetPositionsUsingPositionProperty(this);
},
Transform: function (c) {
if (this.DrawAndTransformDisabled) {
c.setTransform(c.Scale, 0, 0, c.Scale, c.OffsetX * c.Scale, c.OffsetY * c.Scale);
return;
}
var x = 0;
var y = 0;
if ((this.Anchor & TK.Draw.AnchorCenter) > 0) {
x = -(this.W * 0.5);
} else if ((this.Anchor & TK.Draw.AnchorRight) > 0) {
x = -this.W;
}
if ((this.Anchor & TK.Draw.AnchorMiddle) > 0) {
y = -(this.H * 0.5);
} else if ((this.Anchor & TK.Draw.AnchorBottom) > 0) {
y = -this.H;
}
c.SetOffsetX = (c.OffsetX + x);
c.SetOffsetY = (c.OffsetY + y);
c.setTransform(c.Scale, 0, 0, c.Scale, (c.OffsetX + x) * c.Scale, (c.OffsetY + y) * c.Scale);
if (this.Rotate) {
var translateX = this.X - x;
var translateY = this.Y - y;
c.translate(translateX, translateY);
//c.ellipse(0, 0, 35, 35, 0, 0, (2 * Math.PI));
c.rotate(this.Rotate * Math.PI / 180);
c.translate(-translateX, -translateY);
}
},
DrawFS: function (c) {
if (this.BlendMode) {
c.globalCompositeOperation = this.BlendMode;
}
if (this.Shadow) {
c.shadowOffsetX = this.Shadow[0];
c.shadowOffsetY = this.Shadow[1];
c.shadowBlur = this.Shadow[2];
c.shadowColor = this.Shadow[3];
} else {
c.shadowColor = "rgba(0,0,0,0)";
c.shadowBlur = 0;
}
c.globalAlpha = this.Opacity;
if (this.Fill) {
if (this.Fill.length > 7 && (this.Fill.substr(0, 7) == "radial " || this.Fill.substr(0, 7) == "linear ")) {
// Support for gradients
if (this._CachedFillStyleKey != this.Fill) {
this._CachedFillStyleKey = this.Fill;
var parts = this.Fill.split(/ /g);
var g = null;
var stopOffset = 5;
// TODO: Make sure positions and percentages are relative from the current drawableObject
if (parts[0] == "radial") {
g = c.createRadialGradient(
(this.X + TK.Draw.ValueToPx(parts[1], true, this.W, this.H)) /*- c.OffsetX*/, // inner circle X
(this.Y + TK.Draw.ValueToPx(parts[2], false, this.W, this.H)) /*- c.OffsetY*/, // inner circle Y
TK.Draw.ValueToPx(parts[3], true, this.W, this.H), // inner circle Radius
(this.X + TK.Draw.ValueToPx(parts[4], true, this.W, this.H)) /*- c.OffsetX*/, // outer circle X
(this.Y + TK.Draw.ValueToPx(parts[5], false, this.W, this.H)) /*- c.OffsetY*/, // outer circle Y
TK.Draw.ValueToPx(parts[6], true, this.W, this.H)); // outer circle Radius
stopOffset = 7;
} else {
g = c.createLinearGradient(
(this.X + TK.Draw.ValueToPx(parts[1], true, this.W, this.H)) /*- c.OffsetX*/, // Start gradient X
(this.Y + TK.Draw.ValueToPx(parts[2], false, this.W, this.H)) /*- c.OffsetY*/, // Start gradient Y
(this.X + TK.Draw.ValueToPx(parts[3], true, this.W, this.H)) /*- c.OffsetX*/, // End gradient X
(this.Y + TK.Draw.ValueToPx(parts[4], false, this.W, this.H)) /*- c.OffsetY*/); // End gradient Y
}
for (var i = stopOffset; i + 1 < parts.length; i += 2) {
g.addColorStop(parseFloat(parts[i]), parts[i + 1]);
}
this._CachedFillStyle = g;
}
c.fillStyle = this._CachedFillStyle;
} else {
c.fillStyle = this.Fill;
}
if (!this.DrawAndTransformDisabled)
c.fill();
}
if (this.LineCap) {
c.lineCap = this.LineCap;
}
if (!this.ShadowForLine) {
c.shadowColor = "rgba(0,0,0,0)";
c.shadowBlur = 0;
}
c.lineWidth = this.LineWidth;
if (this.Stroke) {
c.strokeStyle = this.Stroke;
if (!this.DrawAndTransformDisabled)
c.stroke();
}
c.globalAlpha = 1;
if (this.BlendMode) {
c.globalCompositeOperation = "source-over"; // default
}
},
Animate: function (propName, targetValue, ms, easing) {
if (!easing)
easing = TK.Draw.EaseLinear;
var p = this.Parent;
while (p !== undefined && p.ProcessAnimations === undefined) // find the TK.Draw component
p = p.Parent;
if (!TK.Draw.AnimationsEnabled) {
this[propName] = targetValue;
if (this.AnimationEnded)
this.AnimationEnded();
if (p)
p.Refresh();
return this;
}
if (p) {
var s = new Date().getTime();
if (p.Animations.length > 100) // Clear all deleted animations from the array
p.Animations = p.Animations.Where(function (a) { return a; });
var animObj = null;
for (var i = 0; i < p.Animations.length; i++) {
if (p.Animations[i] && p.Animations[i].I == this && p.Animations[i].P == propName) {
animObj = p.Animations[i];
break;
}
}
if (animObj == null) {
animObj = {
I: this,
P: propName,
};
p.Animations.push(animObj);
}
animObj.L = ms; // Total animation length
animObj.E = easing;
animObj.S = s; // Start time
if (typeof this[propName] === 'string' && typeof targetValue === 'string') {
// Colors
animObj.O = TK.Draw.GetColor(this[propName]);
animObj.T = TK.Draw.GetColor(targetValue);
//p.Animations.push({ I: this, P: propName, O: TK.Draw.GetColor(this[propName]), T: TK.Draw.GetColor(targetValue), L: ms, E: easing, S: s });
} else if (Array.isArray(this[propName])) {
animObj.O = JSON.parse(JSON.stringify(this[propName]));
animObj.T = targetValue;
//p.Animations.push({ I: this, P: propName, O: JSON.parse(JSON.stringify(this[propName])), T: targetValue, L: ms, E: easing, S: s });
} else {
animObj.O = parseFloat(this[propName]);
animObj.T = targetValue;
//p.Animations.push({ I: this, P: propName, O: parseFloat(this[propName]), T: targetValue, L: ms, E: easing, S: s });
}
p.Refresh();
}
return this;
},
GetRect: function () {
var x = this.X;
var y = this.Y;
if ((this.Anchor & TK.Draw.AnchorCenter) > 0) {
x -= this.W * 0.5;
} else if ((this.Anchor & TK.Draw.AnchorRight) > 0) {
x -= this.W;
}
if ((this.Anchor & TK.Draw.AnchorMiddle) > 0) {
y -= this.H * 0.5;
} else if ((this.Anchor & TK.Draw.AnchorBottom) > 0) {
y -= this.H;
}
return [x, y, this.W, this.H];
},
Overlaps: function (otherDrawableObject) {
var rectA = this.GetRect();
var rectB = otherDrawableObject.GetRect();
return (rectA[0] < (rectB[0] + rectB[2]) && (rectA[0] + rectA[2]) > rectB[0] && rectA[1] < (rectB[1] + rectB[3]) && (rectA[1] + rectA[3]) > rectB[1]);
},
Invalidate: function () {
// Called whenever a property is changed
}
};
"use strict";
/* Minify Skip */
/* Minify Order(155) */
TK.Draw.Circle = {
DrawType: "Circle",
_: TK.Draw.DrawableObject,
Angle: 0, Size: null, DonutSize: null, Extrude: 0,
Draw: function (c) {
c.beginPath();
this.Transform(c);
if (this.Size || this.DonutSize) {
// Complicated (slower) method for partial circles
var outerRadius = this.W * 0.5;
var innerRadius = outerRadius * this.DonutSize;
var centerPosX = this.X + this.W * 0.5;
var centerPosY = this.Y + this.H * 0.5;
if (this.Extrude) {
var extrudeAngle = (this.Angle + (this.Size * 0.5)) * Math.PI / 180;
centerPosX += Math.cos(extrudeAngle) * this.Extrude;
centerPosY += Math.sin(extrudeAngle) * this.Extrude;
}
var th1 = this.Angle * Math.PI / 180; // 0 = begin angle
var th2 = (this.Size + this.Angle) * Math.PI / 180; // 45 = end angle
var startOfOuterArcX = outerRadius * Math.cos(th2) + centerPosX;
var startOfOuterArcY = outerRadius * Math.sin(th2) + centerPosY;
c.arc(centerPosX, centerPosY, innerRadius, th1, th2, false);
c.lineTo(startOfOuterArcX, startOfOuterArcY);
c.arc(centerPosX, centerPosY, outerRadius, th2, th1, true);
} else {
// Simple (faster) method for simple circles
c.ellipse(this.X + this.W * 0.5, this.Y + this.H * 0.5, this.W * 0.5, this.H * 0.5, 0, 0, (2 * Math.PI));
}
this.DrawFS(c);
c.closePath();
},
CheckMouseOver: function (x, y) {
var cx = (this.Anchor & TK.Draw.AnchorLeft) ? this.X + (this.W / 2) : (this.Anchor & TK.Draw.AnchorRight) ? this.X - (this.W / 2) : this.X;
var cy = (this.Anchor & TK.Draw.AnchorTop) ? this.Y + (this.H / 2) : (this.Anchor & TK.Draw.AnchorBottom) ? this.Y - (this.H / 2) : this.Y;
if (this.Extrude) {
var extrudeAngle = (this.Angle + (this.Size * 0.5)) * Math.PI / 180;
cx += Math.cos(extrudeAngle) * this.Extrude;
cy += Math.sin(extrudeAngle) * this.Extrude;
}
if (this.Size && this.Size < 360) {
var deg = Math.atan2(y - cy, x - cx) * 180.0 / Math.PI;
if (deg < 0)
deg = 360 + deg; // Turn into a value between 0 and 360
var checkFrom = this.Angle % 360;
if (checkFrom < 0)
checkFrom = 360 + checkFrom; // Start is also in a value between 0 and 360
var checkTo = (checkFrom + this.Size) % 360;
if (deg < checkFrom && (checkTo > checkFrom || deg > checkTo))
return false;
if (deg > checkTo && (checkFrom < checkTo || deg < checkTo))
return false;
}
var dist = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2));
if (this.DonutSize && dist <= (this.W / 2) * this.DonutSize)
return false;
return (dist <= this.W / 2);
}
};
"use strict";
/* Minify Skip */
/* Minify Order(155) */
TK.Draw.Image = {
DrawType: "Image",
_: TK.Draw.DrawableObject,
//RoundCorners: [15,15,15,15],
Img: null,
Src: null,
Scaling: 0, // 0 Scretch to fit, 1 Contain, 2 Cover
ImageAlign: TK.Draw.AnchorCenter | TK.Draw.AnchorMiddle,
Draw: function (c) {
var obj = this;
if (!this.Img && this.Src) {
this.Img = new Image();
this.Img.onload = function () {
// Refresh draw
c.CanvasObj.Refresh();
};
this.Img.src = this.Src;
return;
}
if (!this.Img)
return;
c.beginPath();
this.Transform(c);
this.DrawFS(c);
try {
c.globalAlpha = this.Opacity;
var drawX = this.X;
var drawY = this.Y;
var drawWidth = this.W;
var drawHeight = this.H;
var sourceX = 0;
var sourceY = 0;
var sourceWidth = this.Img.width;
var sourceHeight = this.Img.height;
if (this.Scaling == 1) {
// Get the aspect ratios
var imgAspectRatio = this.Img.width / this.Img.height;
var boxAspectRatio = this.W / this.H;
if (imgAspectRatio > boxAspectRatio) {
// Image is wider relative to the box
drawWidth = this.W;
drawHeight = this.W / imgAspectRatio;
if ((this.ImageAlign & TK.Draw.AnchorMiddle) != 0)
drawY = this.Y + (this.H - drawWidth) / 2;
else if ((this.ImageAlign & TK.Draw.AnchorBottom) != 0)
drawY = this.Y + (this.H - drawWidth);
} else {
// Image is taller (or same aspect ratio) relative to the box
drawHeight = this.H;
drawWidth = this.H * imgAspectRatio;
if ((this.ImageAlign & TK.Draw.AnchorCenter) != 0)
drawX = this.X + (this.W - drawWidth) / 2;
else if ((this.ImageAlign & TK.Draw.AnchorRight) != 0)
drawX = this.X + (this.W - drawWidth);
}
} else if (this.Scaling == 2) {
// Get the aspect ratios
var imgAspectRatio = this.Img.width / this.Img.height;
var boxAspectRatio = this.W / this.H;
if (imgAspectRatio > boxAspectRatio) {
sourceWidth = (sourceWidth / imgAspectRatio) / 2;
if ((this.ImageAlign & TK.Draw.AnchorCenter) != 0)
sourceX = (this.Img.width - sourceWidth) / 2;
else if ((this.ImageAlign & TK.Draw.AnchorRight) != 0)
sourceX = this.Img.width - sourceWidth;
} else {
sourceHeight = (sourceHeight * imgAspectRatio) / 2;
if ((this.ImageAlign & TK.Draw.AnchorMiddle) != 0)
sourceY = (this.Img.height - sourceHeight) / 2;
else if ((this.ImageAlign & TK.Draw.AnchorBottom) != 0)
sourceY = this.Img.height - sourceHeight;
}
}
c.drawImage(this.Img, sourceX, sourceY, sourceWidth, sourceHeight, drawX, drawY, Math.round(drawWidth), Math.round(drawHeight));
c.globalAlpha = 1;
} catch (errie) { }
c.closePath();
}
};"use strict";
/* Minify Skip */
/* Minify Order(155) */
TK.Draw.Line = {
DrawType: "Line",
_: TK.Draw.DrawableObject,
Draw: function (c) {
c.beginPath();
this.Transform(c);
c.moveTo(this.X, this.Y);
if (this.X2 != undefined) {
c.lineTo(this.X2, this.Y2);
} else {
c.lineTo(this.X + this.W, this.Y + this.H);
}
this.DrawFS(c);
c.closePath();
}
};
"use strict";
/* Minify Skip */
/* Minify Order(155) */
TK.Draw.LineThroughPoints = {
DrawType: "LineThroughPoints",
_: TK.Draw.DrawableObject,
Points: [], // [ [x,y], [x, y] ], optionally a third parameter (direction) can be passed as well [x, y, direction]
Heights: [], // Array with heights for each point, for creating an area chart or sankey lines
Smoothing: TK.Draw.SmoothNone,
DefaultDirection: TK.Draw.DirectionRight, // Default direction if not set at point level, used for smoothing
CornerRadius: 10,
Draw: function (c) {
c.beginPath();
if (!this.W) {
this.W = 0;
for (var i = 0; i < this.Points.length; i++) {
if (this.Points[i][0] > this.W)
this.W = this.Points[i][0];
if (this.Points[i][1] > this.H)
this.H = this.Points[i][1];
}
}
this.Transform(c);
var obj = this;
var passes = this.Heights && this.Heights.length >= this.Points.length ? 2 : 1;
var points = this.Points.slice();
var cornersEndPos = function (point, otherPoint, reverseDir) {
point = point.slice();
var dir = point.length > 2 && point[2] !== null && point[2] !== undefined ? point[2] : obj.DefaultDirection;
var cornerSize = obj.CornerRadius;
if (reverseDir)
dir = (dir + 2) % 4;
if (dir == TK.Draw.DirectionTop) {
point[2] = otherPoint[0] >= point[0] ? TK.Draw.DirectionRight : TK.Draw.DirectionLeft;
point[1] -= cornerSize;
point[0] += otherPoint[0] >= point[0] ? cornerSize : -cornerSize;
} else if (dir == TK.Draw.DirectionRight) {
point[2] = otherPoint[1] >= point[1] ? TK.Draw.DirectionBottom : TK.Draw.DirectionTop;
point[1] += otherPoint[1] >= point[1] ? cornerSize : -cornerSize;
point[0] += cornerSize;
} else if (dir == TK.Draw.DirectionBottom) {
point[2] = otherPoint[0] >= point[0] ? TK.Draw.DirectionRight : TK.Draw.DirectionLeft;
point[1] += cornerSize;
point[0] += otherPoint[0] >= point[0] ? cornerSize : -cornerSize;
} else if (dir == TK.Draw.DirectionLeft) {
point[2] = otherPoint[1] >= point[1] ? TK.Draw.DirectionBottom : TK.Draw.DirectionTop;
point[1] += otherPoint[1] >= point[1] ? cornerSize : -cornerSize;
point[0] -= cornerSize;
}
return point;
};
var cornersDrawCurve = function (point, otherPoint, dir) {
// Dir should be the direction after the curve
if (dir == TK.Draw.DirectionTop || dir == TK.Draw.DirectionBottom) {
c.quadraticCurveTo(otherPoint[0] + obj.X, point[1] + obj.Y, otherPoint[0] + obj.X, otherPoint[1] + obj.Y);
} else {
c.quadraticCurveTo(point[0] + obj.X, otherPoint[1] + obj.Y, otherPoint[0] + obj.X, otherPoint[1] + obj.Y);
}
//c.lineTo(otherPoint[0], otherPoint[1]);
};
for (var pass = 0; pass < passes; pass++) {
if (pass == 1) {
// If the heights for all points is set, we will loop through the points a second time
// in reverse order with the added heights and reversed directions so we can make a full closed loop.
points = points.map(function (p, index) {
var newP = p.slice();
newP[1] += obj.Heights[index];
newP[2] = ((newP[2] !== undefined && newP[2] !== null ? newP[2] : obj.DefaultDirection) + 2) % 4;
return newP;
});
points = points.reverse();
}
for (var i = 0; i < points.length; i++) {
var p = points[i];
var dir = p.length >= 3 && p[2] !== null && p[2] !== undefined ? p[2] : this.DefaultDirection;
if (i == 0) {
if (pass == 0)
c.moveTo(p[0] + this.X, p[1] + this.Y);
else
c.lineTo(p[0] + this.X, p[1] + this.Y);
continue;
}
var lp = points[i - 1];
var ldir = lp.length >= 3 && lp[2] !== null && lp[2] !== undefined ? lp[2] : this.DefaultDirection;
var x_mid = (lp[0] + p[0]) / 2;
var y_mid = (lp[1] + p[1]) / 2;
if (!this.Smoothing) {
c.lineTo(p[0] + this.X, p[1] + this.Y);
} else if (this.Smoothing == TK.Draw.SmoothQuadratic) {
if (ldir == TK.Draw.DirectionRight || ldir == TK.Draw.DirectionLeft) {
var cp_x1 = (x_mid + lp[0]) / 2;
var cp_x2 = (x_mid + p[0]) / 2;
c.quadraticCurveTo(cp_x1 + this.X, lp[1] + this.Y, x_mid + this.X, y_mid + this.Y);
c.quadraticCurveTo(cp_x2 + this.X, p[1] + this.Y, p[0] + this.X, p[1] + this.Y);
} else if (ldir == TK.Draw.DirectionTop || ldir == TK.Draw.DirectionBottom) {
var cp_y1 = (y_mid + lp[1]) / 2;
var cp_y2 = (y_mid + p[1]) / 2;
c.quadraticCurveTo(lp[0] + this.X, cp_y1 + this.Y, x_mid + this.X, y_mid + this.Y);
c.quadraticCurveTo(p[0] + this.X, cp_y2 + this.Y, p[0] + this.X, p[1] + this.Y);
}
} else if (this.Smoothing == TK.Draw.SmoothCorners) {
// TODO:
// - Check if it's nearby, we might need to reduce the corner radius
// - Do multiple corners if we are not in the correct direction yet
//var startPoint = cornersEndPos(lp, p);
var startPoint = [lp[0], lp[1], ldir];
var endPoint = cornersEndPos(p, lp, true);
var revDirEnd = (endPoint[2] + 2) % 4;
var max = 100;
while (startPoint[0] != endPoint[0] || startPoint[1] != endPoint[1]) {
max--;
if (max == 0) {
console.log("max reached");
break;
}
var startDirHorizontal = startPoint[2] == TK.Draw.DirectionLeft || startPoint[2] == TK.Draw.DirectionRight;
if (startPoint[2] == revDirEnd && startDirHorizontal && startPoint[1] == endPoint[1]) {
// If already at the right height, just need 1 line to connect
c.lineTo(endPoint[0] + this.X, endPoint[1] + this.Y);
break;
} else if (startPoint[2] == revDirEnd && !startDirHorizontal && startPoint[0] == endPoint[0]) {
// If already at the right x pos, just need 1 line to connect
c.lineTo(endPoint[0] + this.X, endPoint[1] + this.Y);
break;
} else {
// Make a line towards the right direction
var newPos = startPoint.slice();
if (startPoint[2] == TK.Draw.DirectionRight) {
if (endPoint[2] == TK.Draw.DirectionLeft)
newPos[0] = endPoint[0] - (2 * this.CornerRadius);
else if (endPoint[2] == TK.Draw.DirectionTop || endPoint[2] == TK.Draw.DirectionBottom)
newPos[0] = endPoint[0] - this.CornerRadius;
else
newPos[0] = endPoint[0];
startPoint[0] = newPos[0] > startPoint[0] ? newPos[0] : startPoint[0];
} else if (startPoint[2] == TK.Draw.DirectionLeft) {
if (endPoint[2] == TK.Draw.DirectionRight)
newPos[0] = endPoint[0] + (2 * this.CornerRadius);
else if (endPoint[2] == TK.Draw.DirectionTop || endPoint[2] == TK.Draw.DirectionBottom)
newPos[0] = endPoint[0] + this.CornerRadius;
else
newPos[0] = endPoint[0];
startPoint[0] = newPos[0] < startPoint[0] ? newPos[0] : startPoint[0];
} else if (startPoint[2] == TK.Draw.DirectionBottom) {
if (endPoint[2] == TK.Draw.DirectionTop)
newPos[1] = endPoint[1] - (2 * this.CornerRadius);
else if (endPoint[2] == TK.Draw.DirectionLeft || endPoint[2] == TK.Draw.DirectionRight)
newPos[1] = endPoint[1] - this.CornerRadius;
else
newPos[1] = endPoint[1];
startPoint[1] = newPos[1] > startPoint[1] ? newPos[1] : startPoint[1];
} else if (startPoint[2] == TK.Draw.DirectionTop) {
if (endPoint[2] == TK.Draw.DirectionRight)
newPos[1] = endPoint[1] + (2 * this.CornerRadius);
else if (endPoint[2] == TK.Draw.DirectionLeft || endPoint[2] == TK.Draw.DirectionRight)
newPos[1] = endPoint[1] + this.CornerRadius;
else
newPos[1] = endPoint[1];
startPoint[1] = newPos[1] < startPoint[1] ? newPos[1] : startPoint[1];
}
c.lineTo(startPoint[0] + this.X, startPoint[1] + this.Y);
// Corner into the right direction and update our start pos
var newStartPoint = cornersEndPos(startPoint, p);
cornersDrawCurve(startPoint, newStartPoint, newStartPoint[2]);
startPoint = newStartPoint;
}
}
//c.moveTo(p[0],p[1])
cornersDrawCurve(startPoint, p, dir);
}
}
if (pass == 1 && this.Points.length > 0) {
c.lineTo(this.Points[0][0] + this.X, this.Points[0][1] + this.Y);
}
}
this.DrawFS(c);
c.closePath();
}
};
"use strict";
/* Minify Skip */
/* Minify Order(155) */
TK.Draw.Rect = {
DrawType: "Rect",
_: TK.Draw.DrawableObject,
//RoundCorners: [15,15,15,15],
ShadeSize: 0,
ShadePosition: 1,
Extrude: 0, // Does not work with RoundCorners yet
DrawRoundedRect: function (c, x, y, w, h, corners) {
if (!corners || (corners[0] == 0 && corners[1] == 0 && corners[2] == 0 && corners[3] == 0)) {
c.rect(x, y, w, h);
return;
}
c.moveTo(x + corners[0], y);
c.lineTo(x + w - corners[1], y);
c.quadraticCurveTo(x + w, y, x + w, y + corners[1]);
c.lineTo(x + w, y + h - corners[2]);
c.quadraticCurveTo(x + w, y + h, x + w - corners[2], y + h);
c.lineTo(x + corners[3], y + h);
c.quadraticCurveTo(x, y + h, x, y + h - corners[3]);
c.lineTo(x, y + corners[0]);
c.quadraticCurveTo(x, y, x + corners[0], y);
},
Draw: function (c) {
c.beginPath();
this.Transform(c);
var corners = null;
if (this.RoundCorners && this.RoundCorners.length == 4) {
corners = this.RoundCorners.slice();
var w = this.W;
var h = this.H;
var f = 2;
if (corners[0] * f > w || corners[1] * f > w || corners[2] * f > w || corners[3] * f > w || corners[0] * f > h || corners[1] * f > h || corners[2] * f > h || corners[3] * f > h)
corners = null;
}
this.DrawRoundedRect(c, this.X, this.Y, this.W, this.H, corners);
this.DrawFS(c);
c.closePath();
if (this.Extrude) {
if (this.Extrude > 0) {
// Outside, Draw lighter color above, darker color on the right
c.beginPath();
c.fillStyle = this.FillExtrudeLightColor ? this.FillExtrudeLightColor : TK.Draw.ColorToDifferentColor(this.Fill, "#FFF", 0.4);
c.moveTo(this.X, this.Y);
c.lineTo(this.X + this.Extrude, this.Y - this.Extrude);
c.lineTo(this.X + this.W + this.Extrude, this.Y - this.Extrude);
c.lineTo(this.X + this.W, this.Y);
c.lineTo(this.X, this.Y);
c.fill();
c.closePath();
c.beginPath();
c.fillStyle = this.FillExtrudeDarkColor ? this.FillExtrudeDarkColor : TK.Draw.ColorToDifferentColor(this.Fill, "#000", 0.4);
c.moveTo(this.X + this.W, this.Y);
c.lineTo(this.X + this.W + this.Extrude, this.Y - this.Extrude);
c.lineTo(this.X + this.W + this.Extrude, this.Y + this.H - this.Extrude);
c.lineTo(this.X + this.W, this.Y + this.H);
c.lineTo(this.X + this.W, this.Y);
c.fill();
c.closePath();
} else if (this.Extrude < 0) {
// Inside
c.beginPath();
//c.fillStyle = colorToDifferentColor(this.Fill, "#FFF", 0.4);
c.fillStyle = this.FillExtrudeDarkColor ? this.FillExtrudeDarkColor : TK.Draw.ColorToDifferentColor(this.Fill, "#000", 0.4);
c.moveTo(this.X, this.Y);
c.lineTo(this.X + -this.Extrude, this.Y);
c.lineTo(this.X + -this.Extrude, this.Y + this.H - -this.Extrude);
c.lineTo(this.X, this.Y + this.H);
c.lineTo(this.X, this.Y);
c.fill();
c.closePath();
c.beginPath();
c.fillStyle = this.FillExtrudeLightColor ? this.FillExtrudeLightColor : TK.Draw.ColorToDifferentColor(this.Fill, "#000", 0.1);
c.moveTo(this.X, this.Y + this.H);
c.lineTo(this.X + -this.Extrude, this.Y + this.H - -this.Extrude);
c.lineTo(this.X + this.W, this.Y + this.H - -this.Extrude);
c.lineTo(this.X + this.W, this.Y + this.H);
c.lineTo(this.X, this.Y + this.H);
c.fill();
c.closePath();
}
}
if (this.ShadeSize) {
c.beginPath();
this.Transform(c);
var origFill = this.Fill;
var origStroke = this.Stroke;
this.Fill = "rgba(0,0,0,0.2)";
this.Stroke = null;
if (!corners)
corners = [0, 0, 0, 0];
if (this.ShadePosition == 0)
this.DrawRoundedRect(c, this.X, this.Y, this.W, this.ShadeSize, [corners[0], corners[1], 0, 0]);
else if (this.ShadePosition == 1)
this.DrawRoundedRect(c, (this.X + this.W) - this.ShadeSize, this.Y, this.ShadeSize, this.H, [0, corners[1], corners[2], 0]);
else if (this.ShadePosition == 2)
this.DrawRoundedRect(c, this.X, (this.Y + this.H) - this.ShadeSize, this.W, this.ShadeSize, [0, 0, corners[2], corners[3]]);
else if (this.ShadePosition == 3)
this.DrawRoundedRect(c, this.X, this.Y, this.ShadeSize, this.H, [corners[1], 0, 0, 0]);
this.DrawFS(c);
c.closePath();
this.Fill = origFill;
this.Stroke = origStroke;
}
}
};
"use strict";
/* Minify Skip */
/* Minify Order(155) */
TK.Draw.TextScalingNormal = 0; // None
TK.Draw.TextScalingWhiteSpaceBreak = 1; // Continue on next line to make text fit
TK.Draw.TextScalingResize = 2; // Always resize to fit the full frame, while keeping aspect ratio
TK.Draw.TextScalingResizeIfNeeded = 3; // Only resize if the text doesn't fit, while keeping aspect ratio
TK.Draw.Text = {
DrawType: "Text",
_: TK.Draw.DrawableObject,
BlockedText: false, // Static TK.Draw.Text.BlockedText, If set to true only colored rects will be drawed instead of text, useful for testing or visual censoring
Text: "Text", Font: "30pt Arial",
Scaling: TK.Draw.TextScalingNormal,
LineSpacingRatio: 1.1,
WidthPadding: 2,
HeightPadding: 2,
TextAlign: TK.Draw.AnchorCenter | TK.Draw.AnchorMiddle,
Invalidate: function () {
this.CachedImage = null;
},
Draw: function (c) {
if (this.Text === null || this.Text === undefined)
return;
if (this.Text.substring === undefined)
this.Text = this.Text.toString();
c.beginPath();
if (!this.W) {
this.W = this.MeasureWidth(this.Text);
}
if (!this.H) {
this.H = this.MeasureHeight(this.Text, this.Font);
}
if (this.Rotate) {
var translateX = this.X;
var translateY = this.Y;
c.translate(translateX, translateY);
//c.ellipse(0, 0, 35, 35, 0, 0, (2 * Math.PI));
c.rotate(this.Rotate * Math.PI / 180);
c.translate(-translateX, -translateY);
}
this.Transform(c);
if (TK.Draw.Text.BlockedText) {
c.fillRect(this.X, this.Y, this.W, this.H);
} else {
if (!this.CachedImage) {
this.CachedImage = document.createElement("CANVAS");
this.CachedImage.width = Math.round(this.W * c.Scale);
this.CachedImage.height = Math.round(this.H * c.Scale);
this.CachedImage.style.width = Math.round(this.W * c.Scale) + "px";
this.CachedImage.style.width = Math.round(this.H * c.Scale) + "px";
var text = this.Text;
var scaleFactor = 1;
var lineHeight = this.MeasureHeight(this.Text, this.Font);
if (this.Scaling == TK.Draw.TextScalingWhiteSpaceBreak) {
// Try to insert line breaks
// TODO: Support text with provided linebreaks
var parts = this.Text.split(/ /g);
var newText = "";
var sentenceLength = 0;
for (var i = 0; i < parts.length; i++) {
var curText = parts[i] + (i + 1 == parts.length ? "" : " ");
var curWidth = Math.ceil(this.MeasureWidth(curText, this.Font));
if (sentenceLength > 0 && sentenceLength + curWidth >= this.W) {
newText += "\n";
sentenceLength = curWidth;
} else {
sentenceLength += curWidth;
}
newText += curText;
}
text = newText;
} else if (this.Scaling == TK.Draw.TextScalingResize || this.Scaling == TK.Draw.TextScalingResizeIfNeeded) {
// Calculate factor the font size needs to be changed to make it fill the frame
// TODO: Support text with provided linebreaks
var widthRatio = this.W / this.MeasureWidth(this.Text, this.Font);
var heightRatio = this.H / lineHeight;
if (this.Scaling == TK.Draw.TextScalingResize || widthRatio < 1 || heightRatio < 1) {
scaleFactor = Math.min(widthRatio, heightRatio);
lineHeight *= scaleFactor;
}
}
lineHeight = Math.ceil(lineHeight); // unscaled
var cachedContext = this.CachedImage.getContext("2d");
cachedContext.imageSmoothingEnabled = false;
cachedContext.textAlign = "left";
cachedContext.textBaseline = "top";
cachedContext.font = this.Font;
this.DrawFS(cachedContext);
cachedContext.setTransform(c.Scale * scaleFactor, 0, 0, c.Scale * scaleFactor, 0, 0);
var correctionFactor = 1 / scaleFactor;
var lines = text.split(/\n/g);
var curY = 0;
var totalHeight = lines.length == 0 ? 0 : ((lines.length - 1) * lineHeight * this.LineSpacingRatio) + lineHeight;
if ((this.TextAlign & TK.Draw.AnchorMiddle) > 0) {
curY = (this.H / 2) - (totalHeight / 2);
} else if ((this.TextAlign & TK.Draw.AnchorBottom) > 0) {
curY = this.H - totalHeight;
}
curY = Math.ceil(curY * correctionFactor);
for (var i = 0; i < lines.length; i++) {
var curX = 0;
var lineWidth = this.MeasureWidth(lines[i], this.Font);
if (scaleFactor == 1 && (this.TextAlign & TK.Draw.AnchorCenter) > 0)
curX = (this.W / 2) - (lineWidth / 2);
else if (scaleFactor == 1 && (this.TextAlign & TK.Draw.AnchorRight) > 0)
curX = this.W - lineWidth;
else if (scaleFactor != 1 && lineWidth * scaleFactor >= this.H && (this.TextAlign & TK.Draw.AnchorCenter) > 0) {
// Make sure its centered after scaling
curX = ((this.W / 2) - ((lineWidth * scaleFactor) / 2)) * correctionFactor;
} else if (scaleFactor != 1 && lineWidth * scaleFactor >= this.H && (this.TextAlign & TK.Draw.AnchorRight) > 0) {
// Make sure its centered after scaling
curX = (this.W - (lineWidth * scaleFactor)) * correctionFactor;
}
if (this.Fill)
cachedContext.fillText(lines[i], curX, curY);
if (this.Stroke) {
cachedContext.miterLimit = 3;
cachedContext.strokeText(lines[i], curX, curY);
}
curY += Math.ceil(lineHeight * this.LineSpacingRatio * correctionFactor);
}
}
c.drawImage(this.CachedImage, Math.floor(this.X), Math.floor(this.Y), Math.round(this.W), Math.round(this.H));
}
c.closePath();
},
FillWidthHeight: function () {
this.W = this.MeasureWidth(this.Text, this.Font);
this.H = this.MeasureHeight(this.Text, this.Font);
},
MeasureHeight: function (txt, font) {
var extra = this.HeightPadding + (this.LineWidth ? this.LineWidth * 2 : 0);
var m = this.MeasureText(txt, font);
if (m.actualBoundingBoxDescent !== undefined)
return Math.ceil(m.actualBoundingBoxAscent + m.actualBoundingBoxDescent) + extra;
var height = 16;
var f = font.split(' ');
if (f.length > 1) {
height = parseInt(f[0]);
if (f[0].indexOf("pt") > 0) {
height *= 1.34; // TODO: Fix for different user settings
} else if (f[0].indexOf("em") > 0) {
height *= 16;
}
}
return Math.ceil(height) + extra;
},
MeasureWidth: function (txt, font) {
var extra = this.WidthPadding + (this.LineWidth ? this.LineWidth * 2 : 0);
var m = this.MeasureText(txt, font);
if (m.actualBoundingBoxRight !== undefined)
return Math.ceil(m.actualBoundingBoxLeft + m.actualBoundingBoxRight) + extra;
return Math.ceil(m.width) + extra; // fallback
},
MeasureText: function (txt, font) {
if (txt == undefined)
txt = this.Text;
if (font == undefined)
font = this.Font;
if (!TK.Draw.Text.MeasuringCanvas) {
TK.Draw.Text.MeasuringCanvas = document.createElement("CANVAS");
TK.Draw.Text.MeasuringCanvasContext = TK.Draw.Text.MeasuringCanvas.getContext("2d");
}
var c = TK.Draw.Text.MeasuringCanvasContext;
c.textAlign = "left";
c.textBaseline = "top";
c.font = font;
return c.measureText(txt);
}
};
"use strict";
/* Minify Order(200) */
window.TK.ButtonSwitcher = {
className: "toolkitButtonSwitcher",
Data: null,
Init: function () {
if (!this.DataSettings) {
this.DataSettings = {
Options: this.Options,
Multiple: this.Multiple,
MultipleCheck: this.MultipleCheck
};
}
var obj = this;
for (var i = 0; i < this.DataSettings.Options.length; i++) {
var isActive = this.DataSettings.Multiple ? this.Data && this.Data.indexOf(this.DataSettings.Options[i].Value) >= 0 : this.Data == this.DataSettings.Options[i].Value;
this.Add({
style: {
backgroundImage: this.DataSettings.Options[i].Image ? "url('" + this.DataSettings.Options[i].Image + "')" : null
},
className: "toolkitButtonSwitchOption " + (isActive ? "toolkitButtonSwitchActive" : ""),
title: this.DataSettings.Options[i].Title ? this.DataSettings.Options[i].Title : "",
innerHTML: this.DataSettings.Options[i].Text ? this.DataSettings.Options[i].Text : " ",
Value: this.DataSettings.Options[i].Value,
onclick: function () {
var buttons = obj.Elements.ToArray();
var multiple = obj.DataSettings.Multiple;
var currentChecked = this.className.indexOf("toolkitButtonSwitchActive") >= 0;
if (obj.DataSettings.MultipleCheck && !currentChecked) {
var curSelected = obj.GetValue();
if (curSelected == null)
curSelected = [];
if (!obj.DataSettings.MultipleCheck(curSelected, this.Value)) {
multiple = false; // deselect rest as this combination isn't allowed
}
}
if (!multiple) {
for (var i = 0; i < buttons.length; i++) {
buttons[i].className = buttons[i].className.replace(/toolkitButtonSwitchActive/g, "");
}
this.className += " toolkitButtonSwitchActive";
} else {
if (currentChecked) {
var curSelected = obj.GetValue();
if (!obj.DataSettings.Required || (curSelected && curSelected.length > 1))
this.className = this.className.replace(/toolkitButtonSwitchActive/g, "");
} else
this.className += " toolkitButtonSwitchActive";
}
obj.Data = this.Value;
if (obj.onchange)
obj.onchange();
}
});
}
},
GetValue: function () {
if (this.DataSettings.Multiple) {
var buttons = this.Elements.ToArray();
var selected = [];
for (var i = 0; i < buttons.length; i++) {
if (buttons[i].className.indexOf("toolkitButtonSwitchActive") >= 0) {
selected.push(buttons[i].Value);
}
}
return selected.length > 0 ? selected : null;
}
return this.Data;
}
};
if (window.TK.Form) {
window.TK.Form.DefaultTemplates.buttonSwitcher = {
_: TK.ButtonSwitcher
};
}"use strict";
/* Minify Skip */
/* Minify Order(200) */
TK.Chart = {
_: "div",
DefaultColors: ["#0081D5", "#FF9947", "#03BD5B", "#A939B9", "#D1335B", "#53657D", "#339999", "#999933", "#993399", "#333399", "#999933"],
Width: 700,
Height: 400,
__RecursivePropertiesSeries: true,
Series: [
// Style (flags): 1 Line, 2 Bar, 4 Points, 8 Area, 16 Text with line and point to the value position
// Data is array with X,Y values, X value can be a number, or date-string, or a color
//{ Title: "Test series 1", Axis: "X,Y1", Color: "#0081D5",StackGroup: "b", Style: 2, Smoothing: 1, Data: [["2010-01-01", 100], ["2010-01-02", 100], ["2010-01-03", 50], ["2010-01-04", 100], ["2010-01-05", 75]] },
//{ Title: "Test series 2", Axis: "X,Y1", Color: "#FF9947", StackGroup: "b", Style: 2, Smoothing: 1, LineWidth: 2, Data: [["2010-01-01", 10], ["2010-01-02", 20], ["2010-01-03", 10], ["2010-01-04", 10], ["2010-01-05", 20]] },
//{ Title: "Test series 3", Axis: "X,Y1", Color: "#990000", Style: 2, Smoothing: 1, LineWidth: 2, Data: [["2010-01-01", 20], ["2010-01-02", 30], ["2010-01-03", 20], ["2010-01-04", 30], ["2010-01-05", 20]] },
],
__RecursivePropertiesAxis: true,
Axis: {
X: {
//Type: 0, // 0 - Numbers, 1 - DateTime
Type: 1,
Labels: 0, // 0 - Automatic
Range: null, // [null, null] Fixed min/max, null/undefined for automatic, values outside this range will be filtered
LabelFormat: null,
LabelFormatEdge: null,
Title: "",
Location: 2, // Bottom ( Top,Right,Bottom,Left,Hidden X,Hidden Y,Size,Color)
},
Y1: {
Type: 0, // 0 - Numbers, 1 - DateTime (Mapped on epoch), 2 - DateTime (Mapped on labels), 3 - Labels
Labels: 0, // 0 - Automatic
Range: null, // [null, null] Fixed min/max, null/undefined for automatic, values outside this range will be filtered
Title: null,
ColorLine: "#1d1d1d",
ColorSteps: "#999",
ColorMinorSteps: "#CCC",
ColorLabels: "#999",
ColorTitle: "#999",
FontTitle: "12pt Arial",
Location: 3, // Left
Reverse: true,
Title: ""
},
Size: {
RangeResult: null, // [10, 25],
Location: 8
},
Color: {
RangeResult: null, //["#CCC", "#F00"],
Location: 7
}
},
AxisPadding: 5,
LabelSpacing: 60,
LegendLocation: 2,
FontLegend: "10pt Arial",
ColorLegend: "#333",
TimeZone: "UTC",
ShadeSize: 0.1,
RoundCorners: [5, 5, 5, 5],
Scale: 2,
MinChartPadding: 35,
EnableNavigator: false,
NavigatorStartValue: null,
NavigatorEndValue: null,
FixedNavigator: false,
Navigate: function (minValue, maxValue, final) {
},
NavigatorLineWidth: 1,
ColorNavigatorActive: "#999",
ColorNavigatorInactive: "#EEE",
ColorNavigatorLine: "#333",
ColorNavigatorOutside: "rgba(0,0,0,0.3)",
LegendTemplate: {
_: TK.Draw.Group,
Series: null,
Chart: null,
Init: function () {
this.Add({
_: TK.Draw.Rect,
X: 0, Y: 0, W: 14, H: 14,
Fill: this.Series.Color,
ShadePosition: 2,
ShadeSize: 3,
RoundCorners: [3, 3, 3, 3],
Anchor: TK.Draw.AnchorLeft | TK.Draw.AnchorTop,
});
this.Add({
_: TK.Draw.Text,
X: 20, Y: 0,
Fill: this.Chart.ColorLegend,
Font: this.Chart.FontLegend,
Text: this.Series.Title,
Anchor: TK.Draw.AnchorLeft | TK.Draw.AnchorTop,
});
},
GetWidth: function () {
return TK.Draw.Text.MeasureWidth(this.Series.Title, this.Chart.FontLegend) + 40;
}
},
FormatDate: function (timeStamp, format) {
var disableAutoSmaller = false;
if (format.substr(0, 1) == "!") {
disableAutoSmaller = true;
format = format.substr(1);
}
var date = new Date(timeStamp);
var p = function (d) { return (d < 10 ? "0" + d : d.toString()); };
if (this.TimeZone == "UTC") {
format = format.replace("YYYY", date.getUTCFullYear()).replace("MM", date.getUTCMonth() + 1).replace("DD", date.getUTCDate()).replace("HH", p(date.getUTCHours())).replace("mm", p(date.getUTCMinutes())).replace("ss", p(date.getUTCSeconds()));
} else {
if (this.TimeZone != "Local" && window.moment && window.moment.tz) {
format = moment(timeStamp).tz(this.TimeZone).format(format);
} else {
format = format.replace("YYYY", date.getFullYear()).replace("MM", date.getMonth() + 1).replace("DD", date.getDate()).replace("HH", p(date.getHours())).replace("mm", p(date.getMinutes())).replace("ss", p(date.getSeconds()));
}
}
return disableAutoSmaller ? format : format.replace("00:00:00", "").replace(" 00:00", "").replace(/:00$/, "");
},
Init: function () {
this.Refresh();
},
Refresh: function () {
if (!this.Elements.Canvas) {
this.Add({
_: TK.Draw,
Scale: this.Scale,
Width: this.Width,
Height: this.Height
}, "Canvas");
} else {
this.Elements.Canvas.Clear();
this.Elements.Canvas.Width = this.Width;
this.Elements.Canvas.Height = this.Height;
this.Elements.Canvas.Scale = this.Scale;
this.Elements.Canvas.Init();
}
this.RefreshAxises();
this.RefreshData();
if (this.EnableNavigator) {
this.AddNavigator(this.NavigatorStartValue, this.NavigatorEndValue);
} else {
delete this.AxisesDetected;
}
//console.log(this.AxisesDetected);
//delete this.AxisesDetected;
this.Elements.Canvas.Refresh();
},
AddNavigator: function (from, till) { // Add or set navigator points
var obj = this;
var d = this.AxisesDetected["X"];
var minPX = d.Position[0];
var maxPX = d.Position[0] + d.Position[2];
var heightPX = d.Position[1];
if (heightPX == 0)
heightPX = this.Height;
var fromPX = minPX;
var tillPX = maxPX;
if (from !== undefined && from !== null)
fromPX = d.ValueToPX(from);
if (till !== undefined && till !== null)
tillPX = d.ValueToPX(till);
var cObj = this.Elements.Canvas.Elements;
if (cObj.NavigatorCenterBlock) {
// Already added, just update
cObj.NavigatorMinBlock.X = fromPX;
cObj.NavigatorMaxBlock.X = tillPX;
cObj.NavigatorMinLine.X = fromPX;
cObj.NavigatorMinOutside.W = fromPX - minPX;
cObj.NavigatorMaxLine.X = tillPX;
cObj.NavigatorMaxOutside.X = tillPX;
cObj.NavigatorMaxOutside.W = maxPX - tillPX;
this.Elements.Canvas.Refresh();
return;
}
var outsideConfig = {
_: TK.Draw.Rect,
Fill: this.ColorNavigatorOutside,
X: 0, Y: 0, W: 0, H: heightPX,
Anchor: TK.Draw.AnchorLeft | TK.Draw.AnchorTop,
};
var lineConfig = {
_: TK.Draw.Line,
Stroke: this.ColorNavigatorLine,
LineWidth: this.NavigatorLineWidth,
X: 0, Y: 0, W: 1, H: heightPX,
Anchor: TK.Draw.AnchorCenter | TK.Draw.AnchorTop,
};
var blockConfig = {
_: TK.Draw.Rect,
X: 0, Y: (heightPX / 2) - Math.round(heightPX * 0.15), W: 10, H: Math.round(heightPX * 0.3), Fill: this.ColorNavigatorInactive, Stroke: this.ColorNavigatorLine, LineWidth: this.NavigatorLineWidth,
Anchor: TK.Draw.AnchorRight | TK.Draw.AnchorTop,
MouseDown: function (x, y) {
this.Fill = obj.ColorNavigatorActive;
var offsetX = this.X - x;
this.MouseMove = function (x2, y2) {
this.X = x2 + offsetX;
if (this.X < minPX)
this.X = minPX;
if (this.X > maxPX)
this.X = maxPX;
if (this.LeftSide && this.X > cObj.NavigatorMaxBlock.X) {
this.X = cObj.NavigatorMaxBlock.X;
} else if (!this.LeftSide && this.X < cObj.NavigatorMinBlock.X) {
this.X = cObj.NavigatorMinBlock.X;
}
//this.Y = y2 + offsetY;
if (this.LeftSide) {
cObj.NavigatorMinLine.X = this.X;
cObj.NavigatorMinOutside.W = this.X - minPX;
} else {
cObj.NavigatorMaxLine.X = this.X;
cObj.NavigatorMaxOutside.X = this.X;
cObj.NavigatorMaxOutside.W = maxPX - this.X;
}
cObj.NavigatorCenterBlock.W = cObj.NavigatorMaxLine.X - cObj.NavigatorMinLine.X;
cObj.NavigatorCenterBlock.X = cObj.NavigatorMinLine.X;
if (obj.Navigate)
obj.Navigate(cObj.NavigatorMinBlock.GetPositionAsValue(), cObj.NavigatorMaxBlock.GetPositionAsValue(), false);
return true;
};
},
MouseUp: function (x, y) {
this.Fill = obj.ColorNavigatorInactive;
this.MouseMove = null;
if (obj.Navigate)
obj.Navigate(cObj.NavigatorMinBlock.GetPositionAsValue(), cObj.NavigatorMaxBlock.GetPositionAsValue(), true);
},
GetPositionAsValue: function () { // Convert X value to actual value
var r = (this.X - minPX) / (maxPX - minPX);
if (this.X - 3 < minPX) // If its near start end, pick the start value
r = 0;
if (this.X + 3 > maxPX) // If its near the end, pick the end value
r = 1;
return (r * (d.ScaleMax - d.ScaleMin)) + d.ScaleMin;
}
};
this.Elements.Canvas.Add({ _: outsideConfig, X: minPX, W: fromPX - minPX }, "NavigatorMinOutside");
this.Elements.Canvas.Add({ _: outsideConfig, X: tillPX, W: maxPX - tillPX }, "NavigatorMaxOutside");
this.Elements.Canvas.Add({ _: lineConfig, X: fromPX }, "NavigatorMinLine");
this.Elements.Canvas.Add({ _: lineConfig, X: tillPX }, "NavigatorMaxLine");
var minBlock, maxBlock;
if (!this.FixedNavigator) {
minBlock = this.Elements.Canvas.Add({ _: blockConfig, X: fromPX, LeftSide: true }, "NavigatorMinBlock");
maxBlock = this.Elements.Canvas.Add({ _: blockConfig, Anchor: TK.Draw.AnchorLeft | TK.Draw.AnchorTop, X: tillPX, LeftSide: false }, "NavigatorMaxBlock");
}
this.Elements.Canvas.Add({
_: TK.Draw.Rect,
X: fromPX,
Y: 0,
W: (tillPX - fromPX),
H: heightPX,
Fill: "rgba(0,0,0,0)",
MouseOver: function () {
obj.Elements.Canvas.style.cursor = "grab";
},
MouseOut: function () {
obj.Elements.Canvas.style.cursor = "";
},
MouseDown: function (x, y) {
var offsetX = this.X - x;
obj.Elements.Canvas.style.cursor = "grabbing";
this.MouseMove = function (x2, y2) {
this.X = x2 + offsetX;
if (this.X < minPX)
this.X = minPX;
if (this.X + this.W > maxPX)
this.X = maxPX - this.W;
cObj.NavigatorMinLine.X = this.X;
cObj.NavigatorMinOutside.W = this.X - minPX;
if (minBlock)
minBlock.X = this.X;
if (maxBlock)
maxBlock.X = this.X + this.W;
cObj.NavigatorMaxLine.X = this.X + this.W;
cObj.NavigatorMaxOutside.X = this.X + this.W;
cObj.NavigatorMaxOutside.W = maxPX - (this.X + this.W);
if (obj.Navigate)
obj.Navigate(cObj.NavigatorCenterBlock.GetPositionAsValue(true), cObj.NavigatorCenterBlock.GetPositionAsValue(false), false);
return true;
};
return true;
},
MouseUp: function (x, y) {
this.MouseMove = null;
obj.Elements.Canvas.style.cursor = "grab";
if (obj.Navigate)
obj.Navigate(this.GetPositionAsValue(true), this.GetPositionAsValue(false), true);
},
GetPositionAsValue: function (start) { // Convert X value to actual value
var x = (this.X + (start ? 0 : this.W));
var r = (x - minPX) / (maxPX - minPX);
if (x - 3 < minPX) // If its near start end, pick the start value
r = 0;
if (x + 3 > maxPX) // If its near the end, pick the end value
r = 1;
return (r * (d.ScaleMax - d.ScaleMin)) + d.ScaleMin;
}
}, "NavigatorCenterBlock");
},
RefreshAxises: function () {
var defaultColorIndex = 0;
// Analyse data so we know what Axises we have to generate
var detected = {};
var stackGroupData = {};
for (var i = 0; i < this.Series.length; i++) {
if (!this.Series[i].Data || this.Series[i].Data.length == 0 || !this.Series[i].Axis)
continue;
if (!this.Series[i].Color)
this.Series[i].Color = this.DefaultColors[defaultColorIndex++];
var sizePerValue = null;
if ((this.Series[i].Style & 4) > 0)
sizePerValue = 8;
else if ((this.Series[i].Style & 2) == 0)
sizePerValue = 1;
var axisesUsed = this.Series[i].Axis.split(',');
var axises = [];
for (var j = 0; j < axisesUsed.length; j++) {
var axisName = axisesUsed[j];
if (!detected[axisName]) {
detected[axisName] = {
Min: this.Axis[axisName] && this.Axis[axisName].Range ? this.Axis[axisName].Range[0] : null,
Max: this.Axis[axisName] && this.Axis[axisName].Range ? this.Axis[axisName].Range[1] : null,
RangeResult: this.Axis[axisName] && this.Axis[axisName].RangeResult ? this.Axis[axisName].RangeResult : null,
Location: this.Axis[axisName] && this.Axis[axisName].Location !== undefined ? this.Axis[axisName].Location : axisName == "X" ? 2 : axisName == "Y1" ? 3 : 1,
Type: this.Axis[axisName] ? this.Axis[axisName].Type : 0,
Reverse: this.Axis[axisName] && this.Axis[axisName].Reverse !== undefined ? this.Axis[axisName].Reverse : axisName == "X" || axisName.length > 2 ? false : true,
Size: this.Axis[axisName] && this.Axis[axisName].Size ? this.Axis[axisName].Size : sizePerValue,
Color: this.Axis[axisName] && this.Axis[axisName].Color ? this.Axis[axisName].Color : "#999",
ColorLine: this.Axis[axisName] && this.Axis[axisName].ColorLine ? this.Axis[axisName].ColorLine : "#333",
ColorSteps: this.Axis[axisName] && this.Axis[axisName].ColorSteps ? this.Axis[axisName].ColorSteps : "#333",
ColorMinorSteps: this.Axis[axisName] && this.Axis[axisName].ColorMinorSteps ? this.Axis[axisName].ColorMinorSteps : "#999",
ColorLabels: this.Axis[axisName] && this.Axis[axisName].ColorLabels ? this.Axis[axisName].ColorLabels : "#999",
FontLabels: this.Axis[axisName] && this.Axis[axisName].FontLabels ? this.Axis[axisName].FontLabels : "9pt Arial",
ColorTitle: this.Axis[axisName] && this.Axis[axisName].ColorTitle ? this.Axis[axisName].ColorTitle : "#999",
FontTitle: this.Axis[axisName] && this.Axis[axisName].FontTitle ? this.Axis[axisName].FontTitle : "12pt Arial",
Title: this.Axis[axisName] && this.Axis[axisName].Title ? this.Axis[axisName].Title : "",
Labels: this.Axis[axisName] && this.Axis[axisName].Labels ? this.Axis[axisName].Labels : 0,
LabelFormat: this.Axis[axisName] && this.Axis[axisName].LabelFormat ? this.Axis[axisName].LabelFormat : "dd-MM-yyyy",
LabelFormatEdge: this.Axis[axisName] && this.Axis[axisName].LabelFormatEdge ? this.Axis[axisName].LabelFormatEdge : "dd-MM-yyyy",
ValueCount: this.Series[i].Data.length,
SizeBetweenValues: null,
Series: []
};
}
axises.push(detected[axisName]);
detected[axisName].Series.push(i);
}
var primaryAxis = null;
var secondaryAxis = null;
if (this.Series[i].StackGroup) {
if (!stackGroupData[this.Series[i].StackGroup])
stackGroupData[this.Series[i].StackGroup] = {};
var sg = stackGroupData[this.Series[i].StackGroup];
}
// Find our primary axis and secondary axis
for (var n = 0; n < axises.length; n++) {
if (axises[n].Location >= 0 || axises[n].Location < 6) {
if (primaryAxis === null) {
primaryAxis = n;
} else if (secondaryAxis === null) {
secondaryAxis = n;
}
}
}
if (this.Series[i].StackGroup) {
// Merge with existing stackGroup
this.Series[i].Offsets = [];
for (var n = 0; n < this.Series[i].Data.length; n++) {
var item = this.Series[i].Data[n];
if (sg[item[primaryAxis]] === undefined) {
this.Series[i].Offsets.push(0);
sg[item[primaryAxis]] = item[secondaryAxis];
} else {
this.Series[i].Offsets.push(sg[item[primaryAxis]]);
sg[item[primaryAxis]] += item[secondaryAxis];
}
}
}
for (var j = 0; j < axises.length; j++) {
var d = axises[j];
var first = this.Series[i].Data[0][j];
var isDate = first.toLowerCase && d.Location != 7 ? true : false;
if (d.Location < 6 && first.toLowerCase && (d.Type === undefined || d.Type === null)) {
d.Type = 1;
}
if (d.Type == 3) { // Labels
if (!d.LabelMapping) {
d.LabelMapping = {};
d.CustomSteps = [];
}
d.Min = 0;
for (var n = 0; n < this.Series[i].Data.length; n++) {
if (d.LabelMapping[this.Series[i].Data[n][j]] !== undefined)
continue;
d.LabelMapping[this.Series[i].Data[n][j]] = d.CustomSteps.length;
d.CustomSteps.push({ Text: this.Series[i].Data[n][j], Value: d.CustomSteps.length });
}
d.Max = d.CustomSteps.length - 1;
continue;
}
for (var n = 0; n < this.Series[i].Data.length; n++) {
var value = isDate ? new Date(this.Series[i].Data[n][j]).getTime() : this.Series[i].Data[n][j];
if (value == null || isNaN(value))
continue;
if (j == secondaryAxis && this.Series[i].Offsets) {
value += this.Series[i].Offsets[n];
} else if (j == primaryAxis && n > 0) {
var difference = (this.Series[i].Data[n][j].toLowerCase) ? new Date(this.Series[i].Data[n][j]).getTime() - new Date(this.Series[i].Data[n - 1][j]).getTime() : this.Series[i].Data[n][j] - this.Series[i].Data[n - 1][j];
if (d.SizeBetweenValues === null || d.SizeBetweenValues > difference)
d.SizeBetweenValues = difference;
}
if (d.Min === null || d.Min > value)
d.Min = value;
if (d.Max === null || d.Max < value)
d.Max = value;
}
if (d.Location >= 6 && !d.RangeResult) {
d.RangeResult = [d.Min, d.Max];
}
}
}
// Calculated required widths/heights
var offsets = [0, 0, 0, 0]; // top, right, bottom, left
for (var axisName in detected) {
var d = detected[axisName];
if (d.Min == d.Max) {
if (d.Max > 0)
d.Min = 0;
else if (d.Min < 0)
d.Max = 0;
else if (d.Min == 0)
d.Max += 1;
else {
d.Min -= 1;
d.Max += 1;
}
}
d.Position = [0, 0, 0, 0]; // left, top, width, height
if (d.Location == 0 || d.Location == 2) { // Top, Bottom
var reqSize = 35 + (this.LegendLocation % 2 == d.Location % 2 ? 25 : 0);
d.Position[3] = reqSize;
d.Position[1] = (d.Location == 0 ? 0 : this.Height - reqSize);
} else if (d.Location == 1 || d.Location == 3) { // Right, Left
var reqSize = 75 + (this.LegendLocation % 2 == d.Location % 2 ? 100 : 0);
d.Position[2] = reqSize;
d.Position[0] = (d.Location == 3 ? 0 : this.Width - reqSize);
}
offsets[d.Location] += reqSize;
}
for (var i = 0; i < 4; i++)
offsets[i] = offsets[i] == 0 ? this.MinChartPadding : offsets[i] + this.AxisPadding; // Generic axis padding
for (var axisName in detected) {
var d = detected[axisName];
if (d.Location == 0 || d.Location == 2 || d.Location == 4) { // Top/Bottom, use max width minus any offsets claimed on the left/right
d.Position[2] = this.Width - (offsets[1] + offsets[3]);
d.Position[0] = offsets[3];
if (!d.Size) {
var pxPerValue = d.Position[2] / (d.Max - d.Min);
if (d.SizeBetweenValues && !isNaN(d.SizeBetweenValues)) {
d.Size = pxPerValue * d.SizeBetweenValues * 0.7;
} else if (d.CustomSteps) {
d.Size = (d.Position[2] / d.CustomSteps.length) * 0.7;
}
if (d.Size < 1)
d.Size = 1;
d.Position[0] += Math.ceil(d.Size / 1.2);
d.Position[2] -= Math.ceil(d.Size / 1.2) * 2;
}
} else if (d.Location == 1 || d.Location == 3 || d.Location == 5) { // Right/Left
d.Position[3] = this.Height - (offsets[0] + offsets[2]);
d.Position[1] = offsets[0];
if (!d.Size) {
var pxPerValue = d.Position[3] / (d.Max - d.Min);
if (d.SizeBetweenValues && !isNaN(d.SizeBetweenValues)) {
d.Size = pxPerValue * d.SizeBetweenValues * 0.7;
} else if (d.CustomSteps) {
d.Size = (d.Position[3] / d.CustomSteps.length) * 0.7;
}
if (d.Size < 1)
d.Size = 1;
d.Position[1] += Math.ceil(d.Size / 1.2);
d.Position[3] -= Math.ceil(d.Size / 1.2) * 2;
}
} else if (d.Location >= 6) {
continue;
}
// Find out the optimal label count/step
var stepCount = Math.floor(d.Position[(d.Location % 2) == 0 ? 2 : 3] / this.LabelSpacing); // Optimal(max) label count
if (stepCount < 2)
stepCount = 2;
if (d.Type == 1 || d.Type == 2) { // DateTime, mapped on time || DateTime, mapped on labels
// Date time
var labelFormat = d.LabelFormat;
var labelFormatEdge = d.LabelFormatEdge;
var timeDifference = (d.Max - d.Min) / 1000;
if (d.Labels == 0) { // Automatic, find out what labels to use based on the time difference
if (timeDifference > 60 * 60 * 24 * 365) {
d.Labels = 1; // Years
labelFormatEdge = "DD-MM-YYYY";
labelFormat = "YYYY";
} else if (timeDifference > 60 * 60 * 24 * 35) {
d.Labels = 2; // Months
labelFormatEdge = "DD-MM-YYYY";
labelFormat = "DD-MM-YYYY";
} else if (timeDifference > 60 * 60 * 24 * 2) {
d.Labels = 4; // Days
labelFormatEdge = "DD-MM-YYYY HH:mm";
labelFormat = "DD";
} else if (timeDifference > 60 * 60 * 5) {
d.Labels = 8; // Hours
labelFormatEdge = "DD-MM-YYYY HH:mm";
labelFormat = "HH";
} else if (timeDifference > 60 * 2) {
d.Labels = 16; // Minutes
labelFormatEdge = "DD-MM-YYYY HH:mm:ss";
labelFormat = "HH:mm";
} else {
d.Labels = 32; // Seconds
labelFormatEdge = "DD-MM-YYYY HH:mm:ss";
labelFormat = "mm:ss";
}
}
d.CustomSteps = [];
d.LabelMapping = {};
d.ScaleMin = d.Min;
var cur = d.Min;
d.CustomSteps.push({ Text: this.FormatDate(d.Min, labelFormatEdge), Value: d.Min });
while (cur < d.Max) {
// Note: Make sure the labels will fall at exact day/month/year changes
if (d.Labels == 32) { // Seconds
cur += 1 * 1000;
cur = cur - (cur % 1000);
} else if (d.Labels == 16) { // Minutes
cur += 60 * 1000;
cur = cur - (cur % (60 * 1000)); // Round down
} else if (d.Labels == 8) { // Hours
cur += 60 * 60 * 1000;
cur = cur - (cur % (60 * 60 * 1000)); // Round down
} else if (d.Labels == 4) { // Days
var tmp = new Date(cur);
if (this.TimeZone == "UTC") {
tmp.setUTCDate(tmp.getUTCDate() + 1);
tmp.setUTCHours(0);
tmp.setUTCMinutes(0);
tmp.setUTCSeconds(0);
} else {
tmp.setDate(tmp.getDate() + 1);
tmp.setHours(0);
tmp.setMinutes(0);
tmp.setSeconds(0);
}
cur = tmp.getTime();
} else if (d.Labels == 2) { // Months
var tmp = new Date(cur);
if (this.TimeZone == "UTC") {
tmp.setUTCMonth(tmp.getUTCMonth() + 1);
tmp.setUTCDate(1);
tmp.setUTCHours(0);
tmp.setUTCMinutes(0);
tmp.setUTCSeconds(0);
} else {
tmp.setMonth(tmp.getMonth() + 1);
tmp.setDate(1);
tmp.setHours(0);
tmp.setMinutes(0);
tmp.setSeconds(0);
}
cur = tmp.getTime();
} else if (d.Labels == 1) { // Years
var tmp = new Date(cur);
if (this.TimeZone == "UTC") {
tmp.setUTCFullYear(tmp.getUTCFullYear() + 1);
tmp.setUTCMonth(0);
tmp.setUTCDate(1);
tmp.setUTCHours(0);
tmp.setUTCMinutes(0);
tmp.setUTCSeconds(0);
} else {
tmp.setFullYear(tmp.getFullYear() + 1);
tmp.setMonth(0);
tmp.setDate(1);
tmp.setHours(0);
tmp.setMinutes(0);
tmp.setSeconds(0);
}
cur = tmp.getTime();
} else {
cur = d.Max;
}
d.LabelMapping[cur] = d.CustomSteps.length;
d.CustomSteps.push({ Text: this.FormatDate(cur >= d.Max ? d.Max : cur, (cur >= d.Max ? labelFormatEdge : labelFormat)), Value: cur >= d.Max ? d.Max : cur });
d.ScaleMax = cur >= d.Max ? d.Max : cur;
}
if (d.CustomSteps.length > stepCount) {
// Reduce amount of labels
// TODO: Try to make more logical/nicer steps
var stepAmount = Math.ceil(d.CustomSteps.length / stepCount);
for (var i = 0; i < d.CustomSteps.length - 1; i += 1) {
if (i % stepAmount > 0 || i + stepAmount*0.8 > d.CustomSteps.length) {
d.CustomSteps[i].Text = "";
}
}
}
}
if (!d.CustomSteps || d.CustomSteps.length == 0) {
// https://stackoverflow.com/questions/237220/tickmark-algorithm-for-a-graph-axis
var epsilon = (d.Max - d.Min) / 1e6;
var max = d.Max/* + epsilon*/;
var min = d.Min/* - epsilon*/;
var range = max - min;
var roughStep = range / (stepCount - 1);
var goodNormalizedSteps = [1, 1.5, 2, 2.5, 5, 7.5, 10];
Math.log10 = Math.log10 || function (x) {
return Math.log(x) * Math.LOG10E;
};
var stepPower = Math.pow(10, -Math.floor(Math.log10(Math.abs(roughStep))));
var normalizedStep = roughStep * stepPower;
var goodNormalizedStep = goodNormalizedSteps.First(function (n) { return n >= normalizedStep; });
d.Step = goodNormalizedStep / stepPower;
if (!d.Reverse) {
d.ScaleMax = Math.ceil(max / d.Step) * d.Step;
if (d.ScaleMax + d.Step <= d.Max) d.ScaleMax = d.Max;
d.ScaleMin = Math.floor(min / d.Step) * d.Step;
if (d.ScaleMin - d.Step >= d.Min) d.ScaleMin = d.Min;
d.StepCount = ((d.ScaleMax - d.ScaleMin) / d.Step) + 1;
} else {
d.ScaleMax = Math.floor(min / d.Step) * d.Step;
if (d.ScaleMax + d.Step <= d.Min) d.ScaleMax = d.Min;
d.ScaleMin = Math.ceil(max / d.Step) * d.Step;
if (d.ScaleMin - d.Step >= d.Max) d.ScaleMin = d.Max;
d.StepCount = ((d.ScaleMin - d.ScaleMax) / d.Step) + 1;
d.Step = 0 - d.Step;
}
} else {
d.StepCount = d.CustomSteps.length;
if (d.ScaleMin === undefined) {
d.ScaleMin = d.Min;
d.ScaleMax = d.Max;
}
if (d.Reverse)
d.CustomSteps = d.CustomSteps.reverse();
}
d.ValueToPX = function (value, excludeOwnPosition) {
if (value && value.toLowerCase) {
if (this.LabelMapping[value] !== undefined) {
value = this.LabelMapping[value];
} else if (this.Type == 1 || this.Type == 2) {
value = new Date(value).getTime();
}
}
var sizePX = this.Position[(this.Location % 2) == 0 ? 2 : 3];
if (this.Reverse) { // Reverse
var difference = (this.ScaleMin - this.ScaleMax);
return Math.round(sizePX - (((value - this.ScaleMax) / difference) * sizePX)
+ (excludeOwnPosition ? 0 : this.Position[(this.Location % 2) == 0 ? 0 : 1]));
}
return Math.round((((value - this.ScaleMin) / (this.ScaleMax - this.ScaleMin)) * sizePX)
+ (excludeOwnPosition ? 0 : this.Position[(this.Location % 2) == 0 ? 0 : 1]));
};
// Draw axis and legend
var stepTexts = [];
if (d.Location == 2 || d.Location == 0) { // Bottom, Top
var y = d.Location == 2 ? d.Position[1] : d.Position[3] + d.Position[1];
if (d.Title) {
this.Elements.Canvas.Add({
_: TK.Draw.Text, X: d.Position[2] + d.Position[0], Y: (d.Location == 2 ? y + 30 : y - 30),
Anchor: TK.Draw.AnchorRight | (d.Location == 2 ? TK.Draw.AnchorTop : TK.Draw.AnchorBottom),
Fill: d.ColorTitle,
Font: d.FontTitle,
Text: d.Title
});
}
this.Elements.Canvas.Add({
_: TK.Draw.Line, X: d.Position[0], Y: y, W: d.Position[2], H: 0, Stroke: d.ColorLine
});
for (var i = 0; i < d.StepCount; i++) {
var posX = (d.Position[0] + (d.Position[2] / (d.StepCount - 1)) * i);
if (d.CustomSteps && d.CustomSteps[i] && d.CustomSteps[i].Value !== null && d.CustomSteps[i].Value !== undefined)
posX = d.ValueToPX(d.CustomSteps[i].Value);
if (d.CustomSteps && d.CustomSteps[i] && d.CustomSteps[i].Text == "") {
this.Elements.Canvas.Add({
_: TK.Draw.Line, X: posX, Y: (d.Location == 2 ? y : y - 5), W: 0, H: 5, Stroke: d.ColorMinorSteps
});
continue;
}
this.Elements.Canvas.Add({
_: TK.Draw.Line, X: posX, Y: (d.Location == 2 ? y : y - 10), W: 0, H: 10, Stroke: d.ColorSteps
});
stepTexts[i] = this.Elements.Canvas.Add({
_: TK.Draw.Text,
X: posX, Y: (d.Location == 2 ? y + 15 : y - 15),
Fill: d.ColorLabels,
Font: d.FontLabels,
Text: d.CustomSteps && d.CustomSteps[i] ? d.CustomSteps[i].Text : Math.round((d.ScaleMin + (d.Step * i)) * 10000)/ 10000,
Anchor: TK.Draw.AnchorCenter | (d.Location == 2 ? TK.Draw.AnchorTop : TK.Draw.AnchorBottom),
});
if (i + 1 == d.StepCount) {
var width = stepTexts[i].MeasureWidth();
// Move label if text goes outside the canvas
if (posX + width / 2 > (this.Width - 5))
stepTexts[i].X = this.Width - ((width / 2) + 5);
// Hide overlapping labels
for (var n = i - 1; n >= 0; n--) {
if (!stepTexts[n])
continue;
var curWidth = stepTexts[n].MeasureWidth();
if (stepTexts[n].X + (curWidth / 2) + 10 < stepTexts[i].X - (width / 2))
break;
stepTexts[n].Text = "";
}
if (stepTexts[0] && stepTexts[0].Text) {
width = stepTexts[0].MeasureWidth();
for (var n = 1; n < i - 1; n++) {
if (!stepTexts[n])
continue;
var curWidth = stepTexts[n].MeasureWidth();
if (stepTexts[n].X - ((curWidth / 2) + 10) > stepTexts[0].X + (width / 2))
break;
stepTexts[n].Text = "";
}
}
}
}
if (this.LegendLocation == 2 || this.LegendLocation == 0) {
var curPos = 25;
if (this.LegendLocation == 0)
y = -25;
for (var i = 0; i < this.Series.length; i++) {
if (!this.Series[i].Title || this.Series[i].Title == "" || this.Series[i].HiddenInLegend)
continue;
var legendBlock = this.Elements.Canvas.Add({
_: this.LegendTemplate,
X: curPos,
Y: y + 35,
Series: this.Series[i],
Chart: this
});
curPos += legendBlock.GetWidth();
}
}
} else if (d.Location == 1 || d.Location == 3) { // Right, Left
var x = d.Location == 1 ? d.Position[0] : d.Position[2] + d.Position[0];
if (d.Title) {
this.Elements.Canvas.Add({
_: TK.Draw.Text, X: d.Location == 3 ? 5 : this.Width - 5, Y: d.Position[1] + (d.Position[3] / 2),
Anchor: TK.Draw.AnchorCenter | TK.Draw.AnchorTop,
Fill: d.ColorTitle,
Font: d.FontTitle,
Text: d.Title,
Rotate: d.Location == 3 ? -90 : 90
});
}
this.Elements.Canvas.Add({
_: TK.Draw.Line, X: x, Y: d.Position[1], W: 0, H: d.Position[3], Stroke: d.ColorLine
});
for (var i = 0; i < d.StepCount; i++) {
var posY = (d.Position[1] + (d.Position[3] / (d.StepCount - 1)) * i);
if (d.CustomSteps && d.CustomSteps[i] && d.CustomSteps[i].Value !== null && d.CustomSteps[i].Value !== undefined)
posY = d.ValueToPX(d.CustomSteps[i].Value);
if (d.CustomSteps && d.CustomSteps[i] && d.CustomSteps[i].Text == "") {
this.Elements.Canvas.Add({
_: TK.Draw.Line, X: (d.Location == 1 ? x : x - 5), Y: posY, W: 5, H: 0, Stroke: d.ColorMinorSteps
});
continue;
}
this.Elements.Canvas.Add({
_: TK.Draw.Line, X: (d.Location == 1 ? x : x - 10), Y: posY, W: 10, H: 0, Stroke: d.ColorSteps
});
this.Elements.Canvas.Add({
_: TK.Draw.Text,
X: (d.Location == 1 ? x + 15 : x - 15), Y: posY,
Fill: d.ColorLabels,
Font: d.FontLabels,
Text: d.CustomSteps && d.CustomSteps[i] ? d.CustomSteps[i].Text : Math.round((d.ScaleMin + (d.Step * i)) * 10000) / 10000,
Anchor: (d.Location == 1 ? TK.Draw.AnchorLeft : TK.Draw.AnchorRight) | TK.Draw.AnchorMiddle,
});
}
}
}
this.AxisesDetected = detected;
},
RefreshData: function () {
for (var i = 0; i < this.Series.length; i++) {
var s = this.Series[i];
if (!s.Data || s.Data.length == 0 || !s.Axis)
continue;
var axisesUsed = s.Axis.split(',');
var pos = [];
var firstAxis = null;
for (var j = 0; j < axisesUsed.length; j++) {
var axisName = axisesUsed[j];
var d = this.AxisesDetected[axisName];
if (!d)
continue;
if (!firstAxis)
firstAxis = d;
for (var n = 0; n < s.Data.length; n++) {
var value = s.Data[n][j];
if (!pos[n])
pos[n] = [0, 0, d.Size, s.Color, 0, 15]; // X px center, Y px center, Size Primary, Color, Offset secondary axis,Size Secondary
if (d.Location < 6) {
var px = d.ValueToPX(value);
if (!d.OffsetsPX)
d.OffsetsPX = {};
if (firstAxis != d) {
if (s.Offsets) {
pos[n][4] = d.ValueToPX(s.Offsets[n] + d.ScaleMax) - d.ValueToPX(d.ScaleMax);
}
var key = ((d.Location % 2 == 1) ? pos[n][0] : pos[n][1]);
key += "-" + (s.StackGroup ? s.StackGroup : Math.random());
var max = firstAxis.Location == 0 || firstAxis.Location == 3 ? ((d.Location % 2 == 0) ? d.Position[0] : d.Position[1]) : ((d.Location % 2 == 1) ? d.Position[3] + d.Position[1] : d.Position[2] + d.Position[0]);
if (d.OffsetsPX[key] === undefined)
d.OffsetsPX[key] = max;
var height = 0;
if (firstAxis.Location == 0 || firstAxis.Location == 3) {
height = (px + pos[n][4]) - d.OffsetsPX[key];
d.OffsetsPX[key] += height;
} else {
height = d.OffsetsPX[key] - (px + pos[n][4]);
d.OffsetsPX[key] -= height;
}
pos[n][5] = height;
}
if (d.Location % 2 == 0) {
pos[n][0] = px;
} else {
pos[n][1] = px;
}
} else if (d.Location == 8) { // Size
if (d.Max == d.Min)
pos[n][2] = d.RangeResult[1];
else
pos[n][2] = (((value - d.Min) / (d.Max - d.Min)) * (d.RangeResult[1] - d.RangeResult[0])) + d.RangeResult[0];
} else if (d.Location == 7) { // Color
if (value.toLowerCase) {
pos[n][3] = value;
} else {
var colorA = TK.Draw.GetColor(d.RangeResult[0]), colorB = TK.Draw.GetColor(d.RangeResult[1]);
for (var n2 = 0; n2 < colorA.length; n2++) {
if (d.Max == d.Min) {
colorA[n2] = colorB[n2];
} else {
colorA[n2] = (((value - d.Min) / (d.Max - d.Min)) * (colorB[n2] - colorA[n2])) + colorA[n2];
}
}
pos[n][3] = "rgba(" + colorA.join(",") + ")";
}
}
}
}
var curStackGroups = {};
var barCount = 0;
var barIndex = 0;
for (var j = 0; j < firstAxis.Series.length; j++) {
var otherSerie = this.Series[firstAxis.Series[j]];
if ((otherSerie.Style & 2) == 0) { // Check if this serie has bars
continue;
}
if (otherSerie.StackGroup && curStackGroups[otherSerie.StackGroup] !== undefined) {
if (firstAxis.Series[j] == i)
barIndex = curStackGroups[otherSerie.StackGroup];
continue;
}
if (otherSerie.StackGroup)
curStackGroups[otherSerie.StackGroup] = barCount;
if (firstAxis.Series[j] == i)
barIndex = barCount;
barCount++;
}
for (var j = 0; j < pos.length; j++) {
if ((s.Style & 4) > 0) { // Points
this.Elements.Canvas.Add({
_: TK.Draw.Circle,
X: pos[j][0], Y: pos[j][1] + pos[j][4], W: pos[j][2], H: pos[j][2],
Fill: pos[j][3],
Anchor: TK.Draw.AnchorCenter | TK.Draw.AnchorMiddle,
Click: s.Click,
MouseOver: s.MouseOver,
MouseOut: s.MouseOut
});
}
if ((s.Style & 2) > 0) { // Bars, We use our first axis as 'base'
var size = (pos[j][2] / barCount) * 0.8;
var offset = barIndex * size - (pos[j][2] / 2 - pos[j][2] * 0.1);
var barRect = {
_: TK.Draw.Rect,
Fill: pos[j][3],
Click: s.Click,
MouseOver: s.MouseOver,
MouseOut: s.MouseOut,
RoundCorners: this.RoundCorners,
ShadeSize: this.ShadeSize ? Math.round(size * this.ShadeSize) : 0
};
if (firstAxis.Location == 2 || firstAxis.Location == 0) {
barRect.X = pos[j][0] + offset;
barRect.Y = pos[j][1] + pos[j][4];
barRect.W = size;
barRect.H = pos[j][5];
barRect.ShadePosition = 1;
if (firstAxis.Location == 2)
barRect.Anchor = TK.Draw.AnchorLeft | TK.Draw.AnchorTop;
else
barRect.Anchor = TK.Draw.AnchorLeft | TK.Draw.AnchorBottom;
} else if (firstAxis.Location == 3 || firstAxis.Location == 1) {
barRect.X = (pos[j][0] + pos[j][4]);
barRect.Y = pos[j][1] + offset;
barRect.W = pos[j][5];
barRect.H = size;
barRect.ShadePosition = 2;
if (firstAxis.Location == 3)
barRect.Anchor = TK.Draw.AnchorRight | TK.Draw.AnchorTop;
else
barRect.Anchor = TK.Draw.AnchorLeft | TK.Draw.AnchorTop;
}
this.Elements.Canvas.Add(barRect);
}
}
if ((s.Style & 1) > 0 || (s.Style & 8) > 0) {
//console.log(pos);
var heights = [];
for (var n = 0; n < pos.length; n++) {
pos[n][(firstAxis.Location == 2 || firstAxis.Location == 0) ? 1 : 0] += pos[n][4];
if ((s.Style & 8) > 0) {
heights.push(pos[n][5]);
}
}
this.Elements.Canvas.Add({
_: TK.Draw.LineThroughPoints,
X: 0, Y: 0,
LineWidth: s.LineWidth,
Heights: heights,
Fill: s.Fill,
Points: pos.Select(function (a) { return [a[0], a[1]] }),
Stroke: pos[0][3],
Smoothing: s.Smoothing,
Anchor: TK.Draw.AnchorLeft | TK.Draw.AnchorTop
});
}
}
}
};
"use strict";
/* Minify Skip */
/* Minify Order(200) */
TK.Donut = {
_: "div",
Values: [
/*
{ Name: "Value A", Color: "#F00", ColorLabel: "#F00", Value: 1, Extrude: 10, Label: "Label 123" },
{ Name: "Value B", Color: "#090", Value: 2 },
{ Name: "Value B", Color: "#009", Value: 2 } */
],
Width: 400,
Height: 200,
Size: null,
DonutStartX: null,
DonutStartY: null,
FinalSizeRatio: 0.8,
DonutSize: 0.5,
StartAngle: -90,
EnableLabels: true,
FontLabels: "10pt Verdana",
ColorLabels: "rgba(0,0,0,0.5)",
ColorLabelLines: "rgba(0,0,0,0.5)",
LabelStyle: 2, // 0 = Name only, 1 = Value only, 2 = Both
ShowValueAsPercentage: true,
AnimationLength: 1000,
HideZeroes: true,
EnableLegend: false,
LocationLegend: 1, // 0 = Top, 1 = Right, 2 = Bottom, 3 = Left
ColorLegend: "rgba(0,0,0,0.8)",
FontLegend: "10pt Verdana",
LegendStyle: 0, // 0 = Name only, 1 = Value only, 2 = Both
LegendSize: 0, // 0 = Auto
LegendLineHeight: 25,
Click: null, // function (valuePart) { },
Init: function () {
if (!this.Size)
this.Size = (this.Width > this.Height ? this.Height : this.Width);
this.Clear();
this.Canvas = this.Add({
_: TK.Draw,
Width: this.Width,
Height: this.Height
}, "Canvas");
this.Refresh();
},
Refresh: function () {
this.Canvas.Clear();
var obj = this;
var total = 0;
var countLegend = 0;
for (var i = 0; i < this.Values.length; i++) {
if (this.Values[i].Value && this.Values[i].Value < 0)
this.Values[i].Value = 0;
if (this.Values[i].HideZeroes && !this.Values[i].Value)
continue;
total += this.Values[i].Value;
countLegend++;
}
var donutStartX = this.DonutStartX;
var donutStartY = this.DonutStartY;
if (donutStartX === null)
donutStartX = Math.round((this.Width - this.Size) / 2);
if (donutStartY === null)
donutStartY = Math.round((this.Height - this.Size) / 2);
if (this.EnableLegend) {
if (this.LegendSize == 0) {
if (this.LocationLegend == 0 || this.LocationLegend == 2) {
this.LegendSize = this.Width * 0.9;
} else {
// Find max width of the legend labels
var maxWidth = 10;
for (var i = 0; i < this.Values.length; i++) {
var labelLegend = this.Values[i].Name;
if (this.LegendStyle != 0) {
labelLegend = (this.LegendStyle == 2 ? labelLegend + ": " : "") + (this.ShowValueAsPercentage ? "100 %" : this.Values[i].Value);
}
var curWidth = TK.Draw.Text.MeasureWidth(labelLegend, this.FontLegend);
if (curWidth > maxWidth)
maxWidth = curWidth;
}
this.LegendSize = maxWidth + 20; // Extra padding
}
}
var legendSize = (this.LocationLegend == 0 || this.LocationLegend == 2) ? this.LegendLineHeight * countLegend : this.LegendSize;
if ((this.LocationLegend == 0 || this.LocationLegend == 2) && this.Size > this.Height - legendSize) {
this.Size = this.Height - legendSize;
donutStartX = Math.round((this.Width - this.Size) / 2);
donutStartY = Math.round((this.Height - this.Size) / 2);
} else if ((this.LocationLegend == 1 || this.LocationLegend == 3) && this.Size > this.Width - legendSize) {
this.Size = this.Width - legendSize;
donutStartX = Math.round((this.Width - this.Size) / 2);
donutStartY = Math.round((this.Height - this.Size) / 2);
}
if (this.LocationLegend == 0)
donutStartY = legendSize + (((this.Height - legendSize) / 2) - (this.Size / 2));
else if (this.LocationLegend == 1)
donutStartX = ((this.Width - legendSize) - this.Size) / 2;
else if (this.LocationLegend == 2)
donutStartY = ((this.Height - legendSize) - this.Size) / 2;
else if (this.LocationLegend == 3)
donutStartX = legendSize + (((this.Width - legendSize) / 2) - (this.Size / 2));
}
var middlePointX = (this.Size * 0.5) + donutStartX;
var middlePointY = (this.Size * 0.5) + donutStartY;
var curAngle = this.StartAngle;
var textElements = [];
for (var i = 0; i < this.Values.length; i++) {
if (this.Values[i].HideZeroes && !this.Values[i].Value)
continue;
var size = (this.Values[i].Value / total) * 360;
var donutPart = this.Canvas.Add({
_: TK.Draw.Circle,
DonutSize: this.DonutSize,
X: middlePointX, Y: middlePointY, W: this.Size, H: this.Size, Size: size, Angle: curAngle, Extrude: 10,
Fill: this.Values[i].Color,
Value: this.Values[i],
Anchor: window.TK.Draw.AnchorCenter | window.TK.Draw.AnchorMiddle,
MouseOver: function () {
if (obj.EnableLegend || obj.Click) {
if (this.Value.LegendElement)
this.Value.LegendElement.Elements.Text.Animate("X", 20, 150);
this.Animate("Extrude", 10, 150);
}
},
MouseOut: function () {
if (obj.EnableLegend || obj.Click) {
if (this.Value.LegendElement)
this.Value.LegendElement.Elements.Text.Animate("X", 15, 150);
this.Animate("Extrude", this.Value.Extrude ? this.Value.Extrude : 0, 150);
}
},
Click: function () {
if (obj.Click)
obj.Click(this.Value);
}
});
donutPart.Animate("W", this.Size * this.FinalSizeRatio, this.AnimationLength, window.TK.Draw.EaseBounce);
donutPart.Animate("Extrude", this.Values[i].Extrude ? this.Values[i].Extrude : 0, this.AnimationLength, window.TK.Draw.EaseBounce);
// Generate labels (line from the middle)
var label = this.Values[i].Name;
if (this.LabelStyle != 0) {
label = (this.LabelStyle == 2 ? label + ": " : "") + (this.ShowValueAsPercentage ? Math.round(this.Values[i].Value / total * 100) + " %" : this.Values[i].Value);
}
if (this.Values[i].Label) {
label = this.Values[i].Label;
}
var labelLegend = this.Values[i].Name;
if (this.LegendStyle != 0) {
labelLegend = (this.LegendStyle == 2 ? labelLegend + ": " : "") + (this.ShowValueAsPercentage ? Math.round(this.Values[i].Value / total * 100) + " %" : this.Values[i].Value);
}
if (this.EnableLabels && label && !this.Values[i].DisableLabel) {
var maxSizeFromMiddle = this.Size * this.FinalSizeRatio * 0.5;
if (this.Values[i].Extrude) {
maxSizeFromMiddle += this.Values[i].Extrude;
}
var middleRad = (curAngle + (size * 0.5)) * Math.PI / 180;
var x = Math.cos(middleRad) * maxSizeFromMiddle * (this.DonutSize * 1.5);
var y = Math.sin(middleRad) * maxSizeFromMiddle * (this.DonutSize * 1.5);
var xText = Math.cos(middleRad) * maxSizeFromMiddle * 1.1;
var yText = Math.sin(middleRad) * maxSizeFromMiddle * 1.1;
var middleCircle, line1, line2, text;
middleCircle = this.Canvas.Add({
_: TK.Draw.Circle,
X: middlePointX + x, Y: middlePointY + y, W: 10, H: 10,
ZIndex: 10,
Fill: "rgba(0,0,0,0)",
Anchor: window.TK.Draw.AnchorCenter | window.TK.Draw.AnchorMiddle,
});
line1 = this.Canvas.Add({
_: TK.Draw.Line,
X: middlePointX + x, Y: middlePointY + y, X2: middlePointX + xText, Y2: middlePointY + yText,
ZIndex: 10,
Stroke: "rgba(0,0,0,0)",
Anchor: window.TK.Draw.AnchorTop | window.TK.Draw.AnchorLeft,
});
if (xText < 0) {
line2 = this.Canvas.Add({
_: TK.Draw.Line,
X: middlePointX + xText, Y: middlePointY + yText, X2: middlePointX + xText + -5, Y2: middlePointY + yText,
ZIndex: 10,
Stroke: "rgba(0,0,0,0)",
Anchor: window.TK.Draw.AnchorTop | window.TK.Draw.AnchorLeft,
});
text = this.Canvas.Add({
_: TK.Draw.Text,
X: middlePointX + xText + -10, Y: middlePointY + yText,
ZIndex: 100,
Fill: "rgba(0,0,0,0)",
Text: label,
Font: this.FontLabels,
Anchor: window.TK.Draw.AnchorMiddle | window.TK.Draw.AnchorRight,
});
} else {
line2 = this.Canvas.Add({
_: TK.Draw.Line,
X: middlePointX + xText, Y: middlePointY + yText, X2: middlePointX + xText + 5, Y2: middlePointY + yText,
ZIndex: 10,
Stroke: "rgba(0,0,0,0)",
Anchor: window.TK.Draw.AnchorTop | window.TK.Draw.AnchorLeft,
});
text = this.Canvas.Add({
_: TK.Draw.Text,
X: middlePointX + xText + 10, Y: middlePointY + yText,
ZIndex: 100,
Fill: "rgba(0,0,0,0)",
Text: label,
Font: this.FontLabels,
Anchor: window.TK.Draw.AnchorMiddle | window.TK.Draw.AnchorLeft,
});
}
text.FillWidthHeight();
//console.log(text.GetRect());
for (var textI = 0; textI < textElements.length; textI++) {
while (text.Overlaps(textElements[textI])) {
if (xText < 0)
text.Y -= 1;
else
text.Y += 1;
line1.Y2 = text.Y;
line2.Y = text.Y;
line2.Y2 = text.Y;
}
}
textElements.push(text);
var finalColor = this.Values[i].ColorLabel ? this.Values[i].ColorLabel : this.ColorLabels;
var finalColorLine = this.Values[i].ColorLabelLine ? this.Values[i].ColorLabelLine : this.ColorLabelLines;
middleCircle.Animate("Fill", finalColorLine, this.AnimationLength, TK.Draw.EaseExponential);
line1.Animate("Stroke", finalColorLine, this.AnimationLength, TK.Draw.EaseExponential);
line2.Animate("Stroke", finalColorLine, this.AnimationLength, TK.Draw.EaseExponential);
text.Animate("Fill", finalColor, this.AnimationLength, TK.Draw.EaseExponential);
}
if (this.EnableLegend) {
var obj = this;
var legend = {
_: TK.Draw.Group,
DonutPart: donutPart,
ValuesObj: this.Values[i],
X: 0, Y: i * 25,
Anchor: window.TK.Draw.AnchorMiddle | window.TK.Draw.AnchorLeft,
Elements: {
Circle: {
_: TK.Draw.Circle,
X: 0, Y: this.LegendLineHeight / 2, W: 10, H: 10,
Fill: this.Values[i].Color,
Anchor: window.TK.Draw.AnchorMiddle | window.TK.Draw.AnchorLeft,
},
Text: {
_: TK.Draw.Text,
X: 15, Y: this.LegendLineHeight / 2,
Fill: this.ColorLegend,
Text: labelLegend,
Font: this.FontLegend,
Anchor: window.TK.Draw.AnchorMiddle | window.TK.Draw.AnchorLeft,
}
},
GetRect: function () {
return [this.X, this.Y, obj.LegendSize, obj.LegendLineHeight];
},
MouseOver: function () {
this.Elements.Text.Animate("X", 20, 150);
this.DonutPart.Animate("Extrude", 10, 150);
},
MouseOut: function () {
this.Elements.Text.Animate("X", 15, 150);
this.DonutPart.Animate("Extrude", this.ValuesObj.Extrude ? this.ValuesObj.Extrude : 0, 150);
}
};
if (this.LocationLegend == 0) {
legend.Y = (i * this.LegendLineHeight);
legend.X = (this.Width / 2) - (this.LegendSize / 2);
legend.Anchor = window.TK.Draw.AnchorTop | window.TK.Draw.AnchorLeft;
} else if (this.LocationLegend == 1) {
legend.X = this.Width - this.LegendSize;
legend.Y = ((this.Height / 2) - ((this.LegendLineHeight * countLegend) / 2)) + (i * this.LegendLineHeight);
} else if (this.LocationLegend == 2) {
legend.Y = (this.Height - (this.LegendLineHeight * countLegend)) + (i * this.LegendLineHeight);
legend.X = (this.Width / 2) - (this.LegendSize / 2);
legend.Anchor = window.TK.Draw.AnchorTop | window.TK.Draw.AnchorLeft;
} else if (this.LocationLegend == 3) {
legend.Y = ((this.Height / 2) - ((this.LegendLineHeight * countLegend) / 2)) + (i * this.LegendLineHeight);
}
this.Values[i].LegendElement = this.Canvas.Add(legend);
}
curAngle += size;
}
this.Canvas.Refresh();
}
};"use strict";
/* Minify Order(200) */
window.TK.Dropdown = {
_: "div",
className: "toolkitDropdown",
Data: null, // Selected value(s)
Options: [], // Array of { Value: ..., Text: ... }
Multiple: false, // Allow multiple selections
Placeholder: "Select...",
SelectedText: "{0} selected",
PaddingCheckSelectedFit: 10,
MaxDisplayItems: 10, // Maximum items to show before scrolling
SelectedClass: "toolkitDropdownSelected", // Class for selected items
OpenClass: "toolkitDropdownOpen", // Class when dropdown is open
ListItemTemplate: {
_: "li",
Dropdown: null,
Data: null,
Init: function () {
this.innerText = this.Data.Text;
this.Value = this.Data.Value;
this.className = this.Dropdown.IsSelected(this.Data.Value) ? this.Dropdown.SelectedClass : "";
},
onclick: function (a) {
this.Dropdown.SelectItem(this.Value);
if (!this.Dropdown.Multiple) {
this.Dropdown.ToggleDropdown();
}
}
},
Init: function () {
var obj = this;
if (this.DataSettings) {
var fields = ["Placeholder", "MaxDisplayItems", "Multiple", "Options", "SelectedClass", "OpenClass"];
for (var i = 0; i < fields.length; i++) {
if (this.DataSettings[fields[i]] !== undefined)
this[fields[i]] = this.DataSettings[fields[i]];
}
}
this.Clear();
this.Add({
_: "div",
className: "toolkitDropdownDisplay",
onclick: function (a) { obj.ToggleDropdown() },
Elements: {
SelectedItems: {
_: "ul",
style: { listStyle: "none", padding: 0, margin: 0 },
},
Placeholder: {
_: "span",
innerText: this.Placeholder,
style: { display: this.Data ? "none" : "inline" },
},
},
}, "Display");
this.Add({
_: "div",
className: "toolkitDropdownOptions",
style: { display: "none", maxHeight: this.MaxDisplayItems * 35 + "px" },
Elements: {
OptionsList: {
_: "ul",
style: { listStyle: "none", padding: 0, margin: 0 },
},
},
}, "Options");
this.RefreshOptions();
this.UpdateDisplay();
},
RefreshOptions: function () {
var obj = this;
this.Elements.Options.Elements.OptionsList.Clear();
for (var i = 0; i < this.Options.length;i++) {
var option = this.Options[i];
if (option.Text === undefined || option.Text === null)
option.Text = option.Value;
else if (option.Value === undefined || option.Value === null)
option.Value = option.Text;
if (option.Text === undefined || option.Text === null)
continue;
this.Elements.Options.Elements.OptionsList.Add({
_: this.ListItemTemplate,
Dropdown: this,
Data: option
});
}
},
SelectItem: function (value) {
if (this.Multiple) {
if (!this.Data)
this.Data = [];
if (this.IsSelected(value)) {
this.Data.splice(this.Data.indexOf(value), 1);
} else {
this.Data.push(value);
}
} else {
this.Data = value;
}
this.RefreshOptions();
this.UpdateDisplay();
if (this.onchange) this.onchange();
},
IsSelected: function (value) {
return this.Multiple ? this.Data && this.Data.indexOf(value) >= 0 : this.Data === value;
},
UpdateDisplay: function () {
var obj = this;
this.Elements.Display.Elements.SelectedItems.Clear();
if (!this.Data)
return;
var bboxDisplay = this.Elements.Display.getBoundingClientRect();
var first = true;
if (this.Multiple && this.Data) {
for (var i = 0; i < this.Data.length; i++) {
var value = this.Data[i];
var option = this.Options.First(function (a) {
return a.Value == value;
});
if (option) {
if (!first) {
this.Elements.Display.Elements.SelectedItems.Add({
_: "span",
innerText: ", ",
});
}
first = false;
var item = this.Elements.Display.Elements.SelectedItems.Add({
_: "li",
innerText: option.Text,
});
var bboxItem = item.getBoundingClientRect();
if (bboxItem.right > bboxDisplay.right - this.PaddingCheckSelectedFit) {
this.Elements.Display.Elements.SelectedItems.Clear();
this.Elements.Display.Elements.SelectedItems.Add({
_: "li",
innerText: this.SelectedText.replace(/\{0\}/g, this.Data.length),
});
break;
}
}
}
} else if (!this.Multiple && this.Data) {
var option = this.Options.First(function (a) {
return a.Value == obj.Data;
});
if (option) {
first = false;
this.Elements.Display.Elements.SelectedItems.Add({
_: "li",
innerText: option.Text,
});
}
}
if (first) {
this.Elements.Display.Elements.SelectedItems.Add({
_: "span",
innerText: this.Placeholder,
});
}
this.Elements.Display.Elements.Placeholder.style.display = this.Data ? "none" : "inline";
},
ToggleDropdown: function () {
this.Elements.Options.style.display = this.Elements.Options.style.display === "none" ? "block" : "none";
this.className = this.className.indexOf(this.OpenClass) >= 0 ? this.className.replace(this.OpenClass, "") : this.className + " " + this.OpenClass;
},
GetValue: function () {
return this.Data;
}
};
if (window.TK.Form) {
window.TK.Form.DefaultTemplates.dropdown = {
_: TK.Dropdown,
};
}
"use strict";
/* Minify Skip */
/* Minify Order(200) */
TK.Gauge = {
_: "div",
Ranges: [
/*
{ MinValue: 0, MaxValue: 5, Color: "#C00" },
{ MinValue: 5, MaxValue: 15, Color: "#FC0" },
{ MinValue: 15, MaxValue: 30, Color: "#090" }
*/
],
Width: 400,
Height: 200,
Value: 0,
StartAngle: -180,
EndAngle: 0,
DonutSize: 0.8,
Label: "",
EnableValue: true,
ColorLabel: "#666",
FontLabel: "12pt Verdana",
ColorValue: null, // Automatic (pick range color)
FontValue: "14pt Verdana",
TextValue: null, // Automatic (Use actual value)
EnableShadow: true,
ColorCursor: "#666",
AnimationLength: 1000,
ExtraSpacingBottom: 0,
Style: 0, // 0: Circular gauge, 1: Horizontal Gauge
SizeBar: 20,
Init: function () {
this.Clear();
this.Canvas = this.Add({
_: TK.Draw,
Width: this.Width,
Height: this.Height
}, "Canvas");
this.Refresh();
},
Refresh: function () {
this.Canvas.Clear();
var centerX = this.Width / 2;
var extraSpacingHeight = (this.Height * 0.1) + this.ExtraSpacingBottom;
if (this.Label)
extraSpacingHeight += 25;
if (this.EnableValue)
extraSpacingHeight += 25;
var centerY = this.Height - extraSpacingHeight;
var size = this.Width > centerY * 2 ? centerY * 2 : this.Width;
this.MinValue = this.Ranges.Min(function (a) { return a.MinValue; });
this.MaxValue = this.Ranges.Max(function (a) { return a.MaxValue; });
this.Difference = this.MaxValue - this.MinValue;
this.DifferenceAngles = this.EndAngle - this.StartAngle;
for (var i = 0; i < this.Ranges.length; i++) {
if (this.Style == 0) {
var startAngle = this.StartAngle + (((this.Ranges[i].MinValue - this.MinValue) / this.Difference) * this.DifferenceAngles);
var sizeAngle = ((this.Ranges[i].MaxValue - this.Ranges[i].MinValue) / this.Difference) * this.DifferenceAngles;
this.Canvas.Add({
_: TK.Draw.Circle,
X: centerX, Y: centerY, W: size, H: size,
Fill: this.Ranges[i].Color, DonutSize: this.DonutSize, Angle: startAngle, Size: sizeAngle,
Anchor: window.TK.Draw.AnchorCenter | window.TK.Draw.AnchorMiddle,
});
if (this.EnableShadow) {
this.Canvas.Add({
_: TK.Draw.Circle,
X: centerX, Y: centerY, W: size * (this.DonutSize + 0.05), H: size * (this.DonutSize + 0.05),
Fill: "rgba(0,0,0,0.1)", DonutSize: 0.85, Angle: startAngle, Size: sizeAngle,
Anchor: window.TK.Draw.AnchorCenter | window.TK.Draw.AnchorMiddle,
});
}
} else if (this.Style == 1) {
var fromX = ((this.Ranges[i].MinValue - this.MinValue) / this.Difference) * this.Width;
var widthX = ((this.Ranges[i].MaxValue - this.Ranges[i].MinValue) / this.Difference) * this.Width;
this.Canvas.Add({
_: TK.Draw.Rect,
X: fromX, Y: 10, W: widthX, H: this.SizeBar,
Fill: this.Ranges[i].Color,
Anchor: window.TK.Draw.AnchorLeft| window.TK.Draw.AnchorTop,
});
if (this.EnableShadow) {
this.Canvas.Add({
_: TK.Draw.Rect,
X: fromX, Y: this.SizeBar + 5, W: widthX, H: 5,
Fill: "rgba(0,0,0,0.1)",
Anchor: window.TK.Draw.AnchorLeft | window.TK.Draw.AnchorTop,
});
}
}
}
// Draw cursor
if (this.Style == 0) {
this.Cursor = this.Canvas.Add({
_: TK.Draw.Rect,
X: centerX, Y: centerY, W: size * 0.025, H: size * (0.5 - ((1 - this.DonutSize) * 0.25)),
Fill: this.ColorCursor,
Rotate: 0,
Anchor: window.TK.Draw.AnchorCenter | window.TK.Draw.AnchorBottom,
});
this.Canvas.Add({
_: TK.Draw.Circle,
X: centerX, Y: centerY, W: size * 0.1, H: size * 0.1,
Fill: this.ColorCursor,
Anchor: window.TK.Draw.AnchorCenter | window.TK.Draw.AnchorMiddle,
});
} else {
this.Cursor = this.Canvas.Add({
_: TK.Draw.Rect,
X: 0, Y: 0, W: 2, H: this.SizeBar + 20,
Fill: this.ColorCursor,
Anchor: window.TK.Draw.AnchorCenter | window.TK.Draw.AnchorTop,
});
}
var curY = centerY + (size * 0.1);
if (this.Label) {
this.LabelText = this.Canvas.Add({
_: TK.Draw.Text,
X: centerX, Y: curY,
Fill: this.ColorLabel,
Font: this.FontLabel,
Text: this.Label,
Anchor: window.TK.Draw.AnchorCenter | window.TK.Draw.AnchorMiddle,
});
curY += 25;
}
if (this.EnableValue) {
this.ValueText = this.Canvas.Add({
_: TK.Draw.Text,
X: centerX, Y: curY,
Fill: this.ColorValue ? this.ColorValue : "#000",
Font: this.FontValue,
Text: this.Value,
Anchor: window.TK.Draw.AnchorCenter | window.TK.Draw.AnchorMiddle,
});
}
this.SetValue(this.Value);
this.Canvas.Refresh();
},
SetValue: function (newValue) {
var animation = window.TK.Draw.EaseExponential;
if (newValue >= this.MaxValue) {
animation = window.TK.Draw.EaseBounce;
newValue = this.MaxValue;
} else if (newValue <= this.MinValue) {
animation = window.TK.Draw.EaseBounce;
newValue = this.MinValue;
}
if (this.EnableValue) {
this.ValueText.Text = this.TextValue ? this.TextValue : newValue;
var activeRange = this.Ranges.Where(function (a) { return a.MinValue <= newValue && a.MaxValue >= newValue; });
if (activeRange.length > 0 && !this.ColorValue) {
this.ValueText.Fill = activeRange[activeRange.length - 1].Color;
}
}
if (this.Style == 0) {
var valueAngle = this.StartAngle + (((newValue - this.MinValue) / this.Difference) * this.DifferenceAngles);
this.Cursor.Animate("Rotate", valueAngle + 90, this.AnimationLength, animation);
} else if (this.Style == 1) {
var valueX = (((newValue - this.MinValue) / this.Difference) * this.Width - 2) + 1;
this.Cursor.Animate("X", valueX, this.AnimationLength, animation);
}
// Move cursor
this.Value = newValue;
}
};"use strict";
/* Minify Skip */
/* Minify Order(200) */
TK.ImageEditor = {
className: "toolkitImageEditor",
Data: null,
SpecificSize: null, // TODO: Resize uploaded image to [x, y] and force aspect ratio
ValueType: "dataUrl", // by default, a data:image/jpeg;base64 value is used.
Mime: "image/jpeg",
Quality: 0.9,
StorageClientId: undefined,
StorageContainer: undefined,
StoragePath: undefined,
onchange: null,
// Auto resize when image is larger than width and/or height
MaxWidth: null,
MaxHeight: null,
Init: function () {
var obj = this;
if (this.DataSettings) {
if (this.DataSettings.Mime !== undefined)
this.Mime = this.DataSettings.Mime;
if (this.DataSettings.Quality !== undefined)
this.Quality = this.DataSettings.Quality;
if (this.DataSettings.ValueType !== undefined)
this.ValueType = this.DataSettings.ValueType;
if (this.DataSettings.StorageContainer !== undefined)
this.StorageContainer = this.DataSettings.StorageContainer;
if (this.DataSettings.StorageClientId !== undefined)
this.StorageClientId = this.DataSettings.StorageClientId;
if (this.DataSettings.StoragePath !== undefined)
this.StoragePath = this.DataSettings.StoragePath;
}
if (this.Data == "loading") {
this.Elements.DropArea.style.backgroundImage = "";
this.Elements.DropArea.innerHTML = "Uploading...";
} else if (this.Data) {
if (window.Blob && this.Data instanceof Blob) {
this.Elements.DropArea.style.backgroundImage = "";
var fileReader = new FileReader();
fileReader.onload = function (e) {
obj.Elements.DropArea.style.backgroundImage = "url('"+e.target.result+"')";
};
fileReader.readAsDataURL(this.Data);
} else { // Url or dataUrl
this.Elements.DropArea.style.backgroundImage = "url('" + this.Data + "')";
}
this.Elements.DropArea.innerHTML = " ";
} else {
this.Elements.DropArea.style.backgroundImage = "";
this.Elements.DropArea.innerHTML = Svg.Icons.Image;
}
},
StorageHandlers: {
dataUrl: function (imageEditor, canvas, callBackValue) {
callBackValue(canvas.toDataURL(imageEditor.Mine, imageEditor.Quality));
},
url: function (imageEditor, canvas, callBackValue) {
if (!TK.ServerStorage)
return;
var serverStorage = TK.Initialize({
_: TK.ServerStorage,
Container: imageEditor.StorageClientId,
ClientId: imageEditor.ClientId
});
// Turn canvas into [Blob]
canvas.toBlob(function (blob) {
console.log(blob);
var fileName = imageEditor.StoragePath ? imageEditor.StoragePath : imageEditor.Mime.replace("/", ".");
serverStorage.Store(fileName, blob, function (fileMetaData) {
console.log(fileMetaData);
if (fileMetaData && fileMetaData.url)
callBackValue(fileMetaData.url);
else
alert('Error uploading image');
});
}, imageEditor.Mime, imageEditor.Quality);
/*var fd = new FormData();
fd.append("file", blob, "hello.txt");
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server.php', true);
xhr.onload = function(){
alert('upload complete');
};
xhr.send(fd);*/
},
blob: function (imageEditor, canvas, callBackValue) {
// Turn the value into a [Blob]
canvas.toBlob(function (blob) {
callBackValue(blob);
}, imageEditor.Mime, imageEditor.Quality);
}
},
PopupTemplate: {
_: TK.Popup,
EnableResize: false,
Title: "Edit image",
Width: 600,
Height: 500,
EnableBackDrop: true,
ImageEditorInstance: null,
Template: {
Elements: {
CanvasContainer: {
Elements: {
Buttons: {
style: {
position: "relative",
height: "30px"
},
Elements: {
Slider: {
_: "input",
type: "range",
min: 0,
max: 360,
value: 0,
step: 5,
style: {
width: "99%"
},
onchange: function () {
this.Parent.Parent.Elements.SelectionCanvas.Rotation = parseFloat(this.value.toString());
this.Parent.Parent.Elements.SelectionCanvas.UpdateBoxPosition();
this.Parent.Parent.Elements.SelectionCanvas.Refresh();
},
oninput: function () {
this.onchange();
}
}
}
},
SelectionCanvas: {
_: TK.Draw,
Width: 580,
Height: 370,
style: {
backgroundColor: "#000"
},
CropTL: [50, 50],
CropBR: [200, 200],
NavigationEnabled: true,
ZoomEnabled: true,
Rotation: 0, // 0 Normal, 1 CW, 2 Upside down, 3 CC
Init: function () {
// Draw bounding box
var obj = this;
this.Add({
_: TK.Draw.Image,
X: 10, Y: 10, W: 100, H: 100, Anchor: TK.Draw.AnchorCenter | TK.Draw.AnchorMiddle
}, "Image");
this.Add({
_: TK.Draw.Rect, Stroke: "#CCC",
MouseDown: function (x, y) {
this.Dragging = true;
this.StartPos = [x, y];
},
MouseMove: function (x, y) {
if (!this.Dragging)
return;
var differenceX = x - this.StartPos[0];
var differenceY = y - this.StartPos[1];
obj.CropTL[0] += differenceX;
obj.CropTL[1] += differenceY;
obj.CropBR[0] += differenceX;
obj.CropBR[1] += differenceY;
if (obj.CropBR[0] >= obj.Width) {
obj.CropTL[0] -= (obj.CropBR[0] - obj.Width);
obj.CropBR[0] = obj.Width;
}
if (obj.CropBR[1] >= obj.Height) {
obj.CropTL[1] -= (obj.CropBR[1] - obj.Height);
obj.CropBR[1] = obj.Height;
}
if (obj.CropTL[0] < 0) {
obj.CropBR[0] += -obj.CropTL[0];
obj.CropTL[0] = 0;
}
if (obj.CropTL[1] < 0) {
obj.CropBR[1] += -obj.CropTL[1];
obj.CropTL[1] = 0;
}
this.StartPos = [x, y];
obj.UpdateBoxPosition();
},
MouseUp: function (x, y) {
this.Dragging = false;
}
}, "Box");
var boxSize = 15;
var boxes = ["TL", "TR", "BL", "BR"];
for (var i = 0; i < boxes.length; i++) {
this.Add({
_: TK.Draw.Rect,
Box: boxes[i],
Anchor: boxes[i] == "TL" ? TK.Draw.AnchorRight | TK.Draw.AnchorBottom :
boxes[i] == "TR" ? TK.Draw.AnchorLeft | TK.Draw.AnchorBottom :
boxes[i] == "BL" ? TK.Draw.AnchorRight | TK.Draw.AnchorTop :
boxes[i] == "BR" ? TK.Draw.AnchorLeft | TK.Draw.AnchorTop :
TK.Draw.AnchorCenter | TK.Draw.AnchorBottom,
Fill: "#FFF",
W: boxSize, H: boxSize,
MouseDown: function (x, y) {
this.Dragging = true;
},
MouseMove: function (x, y) {
this.Fill = "#999";
if (this.Box == "TL")
obj.style.cursor = "nw-resize";
else if (this.Box == "TR")
obj.style.cursor = "ne-resize";
else if (this.Box == "BL")
obj.style.cursor = "sw-resize";
else if (this.Box == "BR")
obj.style.cursor = "se-resize";
if (!this.Dragging)
return;
if (this.Box == "TL") {
obj.CropTL[0] = x;
obj.CropTL[1] = y;
} else if (this.Box == "TR") {
obj.CropBR[0] = x;
obj.CropTL[1] = y;
} else if (this.Box == "BL") {
obj.CropTL[0] = x;
obj.CropBR[1] = y;
} else if (this.Box == "BR") {
obj.CropBR[0] = x;
obj.CropBR[1] = y;
}
obj.UpdateBoxPosition();
},
MouseOut: function () {
this.Fill = "#FFF";
obj.style.cursor = "default";
},
MouseUp: function (x, y) {
this.Dragging = false;
}
}, "Box"+boxes[i]);
}
this.UpdateBoxPosition();
this.Refresh();
},
UpdateBoxPosition: function () {
this.Elements.Image.Rotate = this.Rotation;
this.Elements.Box.X = this.CropTL[0];
this.Elements.Box.Y = this.CropTL[1];
this.Elements.Box.W = this.CropBR[0] - this.CropTL[0];
this.Elements.Box.H = this.CropBR[1] - this.CropTL[1];
this.Elements.BoxTL.X = this.CropTL[0];
this.Elements.BoxTL.Y = this.CropTL[1];
this.Elements.BoxTR.X = this.CropBR[0];
this.Elements.BoxTR.Y = this.CropTL[1];
this.Elements.BoxBL.X = this.CropTL[0];
this.Elements.BoxBL.Y = this.CropBR[1];
this.Elements.BoxBR.X = this.CropBR[0];
this.Elements.BoxBR.Y = this.CropBR[1];
},
}
}
}
}
},
Buttons: {
Apply: function () {
var popup = this.Parent.Parent;
var canvas = popup.Elements.Content.Elements.CanvasContainer.Elements.SelectionCanvas;
// Apply transformations to image, upload and return url
popup.ImageEditorInstance.Data = "loading";
popup.ImageEditorInstance.Init();
setTimeout(function () {
var resizeAndCropCanvas = document.createElement("CANVAS");
//canvas.Scale;
resizeAndCropCanvas.width = (canvas.CropBR[0] - canvas.CropTL[0]) / canvas.Ratio;
resizeAndCropCanvas.height = (canvas.CropBR[1] - canvas.CropTL[1]) / canvas.Ratio;
var offsetX = ((canvas.Elements.Image.X - canvas.Elements.Image.W / 2) - canvas.CropTL[0]) / canvas.Ratio;
var offsetY = ((canvas.Elements.Image.Y - canvas.Elements.Image.H / 2) - canvas.CropTL[1]) / canvas.Ratio;
var context = resizeAndCropCanvas.getContext("2d");
context.imageSmoothingQuality = 'high';
// TODO: Rotation canvas.Elements.Image.Rotate
if (canvas.Elements.Image.Rotate) {
var translateX = offsetX + (canvas.Elements.Image.Img.width / 2);
var translateY = offsetY + (canvas.Elements.Image.Img.height / 2);
context.translate(translateX, translateY);
context.rotate(canvas.Elements.Image.Rotate * Math.PI / 180);
context.translate(-translateX, -translateY);
//context.translate(offsetX, offsetY);
}
context.drawImage(canvas.Elements.Image.Img, offsetX, offsetY, canvas.Elements.Image.Img.width, canvas.Elements.Image.Img.height);
var inst = popup.ImageEditorInstance;
// Resize if needed
if ((inst.MaxWidth !== null && canvas.Elements.Image.Img.width > inst.MaxWidth) || (inst.MaxHeight !== null && canvas.Elements.Image.Img.height > inst.MaxHeight)) {
var ratioW = 9999;
var ratioH = 9999;
var newWidth = 0;
var newHeight = 0;
if (inst.MaxWidth !== null)
ratioW = inst.MaxWidth / resizeAndCropCanvas.width ; // 200 / 800 = 0.25
if (inst.MaxHeight !== null)
ratioH = inst.MaxHeight / resizeAndCropCanvas.height; // 200 / 1000 = 0.2
if (ratioW < ratioH) {
newWidth = inst.MaxWidth;
newHeight = Math.floor(ratioW * resizeAndCropCanvas.height);
} else {
newWidth = Math.floor(ratioH * resizeAndCropCanvas.width);
newHeight = inst.MaxHeight;
}
var resizeAndCropCanvas2 = document.createElement("CANVAS");
resizeAndCropCanvas2.width = newWidth;
resizeAndCropCanvas2.height = newHeight;
var context2 = resizeAndCropCanvas2.getContext("2d");
context2.imageSmoothingQuality = 'high';
context2.drawImage(resizeAndCropCanvas, 0, 0, newWidth, newHeight);
resizeAndCropCanvas = resizeAndCropCanvas2;
}
if (inst.ValueType && inst.StorageHandlers[inst.ValueType]) {
inst.StorageHandlers[inst.ValueType](inst, resizeAndCropCanvas, function (value) {
inst.Data = value;
inst.Init();
if (inst.onchange)
inst.onchange();
});
} else {
var url = resizeAndCropCanvas.toDataURL(inst.Mine, inst.Quality);
inst.Data = url;
inst.Init();
if (inst.onchange)
inst.onchange();
}
}, 1);
},
Cancel: function () { }
},
ImageLoaded: function (dataUri) {
var canvas = this.Elements.Content.Elements.CanvasContainer.Elements.SelectionCanvas;
this.ImageUrl = dataUri;
var img = new Image();
img.onload = function () {
canvas.Elements.Image.Img = this;
var padding = 20;
// Fill image into selection canvas (with some padding at the sides)
var maxWidth = canvas.Width - (padding * 2), maxHeight = canvas.Height - (padding * 2);
var imgWidth = this.width, imgHeight = this.height;
var widthRatio = maxWidth / imgWidth, heightRatio = maxHeight / imgHeight;
var bestRatio = Math.min(widthRatio, heightRatio);
var newWidth = imgWidth * bestRatio, newHeight = imgHeight * bestRatio;
canvas.Ratio = bestRatio;
canvas.Elements.Image.X = (canvas.Width / 2);
canvas.Elements.Image.Y = (canvas.Height / 2);
canvas.Elements.Image.W = newWidth;
canvas.Elements.Image.H = newHeight;
canvas.CropTL = [canvas.Elements.Image.X - (newWidth / 2), canvas.Elements.Image.Y - (newHeight / 2)];
canvas.CropBR = [canvas.Elements.Image.X + (newWidth / 2), canvas.Elements.Image.Y + (newHeight / 2)];
canvas.UpdateBoxPosition();
canvas.Refresh();
};
img.src = dataUri;
}
},
GetValue: function () {
if (this.Data == "loading")
return null;
return this.Data;
},
HandleFiles: function (files) {
var file = files[0]; // TODO: Support multiple files in the future
var popup = this.Add({
_: this.PopupTemplate,
ImageEditorInstance: this
});
var reader = new FileReader();
reader.onload = function (e2) { popup.ImageLoaded(e2.target.result); };
reader.readAsDataURL(file);
},
Elements: {
DropArea: {
onclick: function () {
this.Near("FileUploadField").click();
},
ondragover: function (ev) {
this.style.borderColor = "#1d1d1d";
ev.preventDefault();
},
ondragexit: function (ev) {
this.style.borderColor = "";
ev.preventDefault();
},
ondrop: function (ev) {
ev.preventDefault();
if (!ev.dataTransfer || !ev.dataTransfer.files)
return;
this.Parent.HandleFiles(ev.dataTransfer.files);
}
},
FileUploadField: {
_: "input",
type: "file",
accept:"image/*",
style: {
display: "none"
},
onchange: function (e) {
if (!e || !e.target || !e.target.files || e.target.files.length == 0)
return;
//alert(e.target.files[0].name);
this.Parent.HandleFiles(e.target.files);
}
}
}
};
if (window.TK.Form) {
window.TK.Form.DefaultTemplates.image = {
_: TK.ImageEditor
};
}
if (window.TK.HtmlEditor) {
window.TK.HtmlEditor.ButtonTemplates.InsertImage = {
innerHTML: Svg.Icons.Image,
title: "Insert image",
onmousedown: function () {
var randId = "img" + new Date().getTime();
var html = "";
this.Near("Editor").focus();
document.execCommand("insertHTML", false, html);
var img = document.getElementById(randId);
if (img) {
var tempEditor = TK.Initialize({
_: TK.ImageEditor,
style: { display: "none" },
onchange: function () {
var dataUrl = this.GetValue();
if (dataUrl) {
img.src = dataUrl;
}
}
});
tempEditor.Elements.FileUploadField.click();
}
}
};
}"use strict";
/* Minify Order(200) */
TK.Interface = {
CurrentUserTemplate: null,
CurrentLogoTemplate: null,
DefaultContent: "Index",
className: "toolkitInterface",
MenuIconSize: 50,
MenuTextSize: 150,
ResponsiveThreshold: 400,
ResponsiveFullThreshold: 700,
EnableMenu: true,
Content: {},
HamburgerIcon: null, // data
Embedded: false,
ShowMenu: false, // Show menu in mobile view (Hamburger menu icon toggles this)
Init: function () {
var obj = this;
if (!this.EnableMenu) {
this.MenuIconSize = 0;
this.MenuTextSize = 0;
}
var header = this.Add({
_Position: "0px,0px,,0px,,40px",
style: {
zIndex: "1000"
},
Elements: {
CurrentUser: {
_Position: "0px,9px",
style: {
lineHeight: "40px"
}
},
CurrentLogo: {
_Position: "0px,,,9px",
style: {
lineHeight: "40px"
}
}
},
Init: function() {
if (obj.EnableMenu) {
this.Add({
innerHTML: obj.HamburgerIcon ? obj.HamburgerIcon : window.Svg && Svg.Icons && Svg.Icons.Hamburger ? Svg.Icons.Hamburger : "",
onclick: function() {
// Toggle menu
obj.ShowMenu = !obj.ShowMenu;
obj.ProcessResize();
},
_Position: "5px,,,5px,30px,30px"
}, "HamburgerMenu");
}
}
}, "Header");
var menu = null;
if (this.EnableMenu) {
var menu = this.Add({
_: "ul",
style: {
listStyle: "none",
margin: "0px",
padding: "0px",
zIndex: "1000",
display: "none"
},
_Position: "40px,,0px,0px," + (this.MenuIconSize + this.MenuTextSize) + "px,"
}, "Menu");
}
var content = {
_: TK.Navigator,
_Position: "40px,0px,0px," + (this.MenuIconSize + this.MenuTextSize) +"px",
style: {
overflow: "auto"
},
Templates: {},
DefaultHash: this.DefaultContent,
Navigate: function(page) {
if (!menu)
return;
var menuItems = obj.Elements.Menu.Elements.ToArray();
for (var i = 0; i < menuItems.length;i++)
menuItems[i].className = menuItems[i].className.replace("toolkitActive", "");
if (menu.Elements["MenuItem" + page])
menu.Elements["MenuItem" + page].className += " toolkitActive";
}
};
if (!this.Embedded) {
content._Position = null;
document.body.style.paddingTop = "40px";
document.body.style.paddingLeft = (this.MenuIconSize + this.MenuTextSize) + "px";
content.style.overflow = "";
header.style.position = "fixed";
if (menu)
menu.style.position = "fixed";
}
for (var name in this.Content) {
if (!this.Content[name].Hidden && menu) {
var menuItem = menu.Add({
_: "li",
style: {
position: "relative",
//width: (this.MenuIconSize + this.MenuTextSize) + "px",
height: this.MenuIconSize + "px",
lineHeight: this.MenuIconSize + "px",
textAlign: "left",
overflow: "hidden"
},
title: this.Content[name].Name,
Hash: name,
onclick: function () {
if (obj.ShowMenu) {
obj.ShowMenu = !obj.ShowMenu;
obj.ProcessResize();
}
window.location.hash = "#" + this.Hash;
},
Elements: {}
}, "MenuItem" + name);
if (this.Content[name].Icon) {
menuItem.Add({
innerHTML: this.Content[name].Icon,
style: {
position: "absolute",
top: "5px",
left: "5px",
width: (this.MenuIconSize - 10) + "px",
height: (this.MenuIconSize - 10) + "px"
}
}, "Icon");
}
menuItem.Add({
_: "span",
style: {
position: "absolute",
top: "0px",
left: (this.MenuIconSize+5)+"px",
right: "0px",
height: this.MenuIconSize + "px"
},
innerHTML: this.Content[name].Name ? this.Content[name].Name : name
}, "Title");
}
if (this.Content[name].Content) { // Divided in subpages
content.Templates[name] = {
_: "div",
className: "toolkitInterfaceSubPages",
Templates: {},
MenuTemplate: {
_: "ul",
style: {
position: !this.Embedded ? "fixed" : "absolute",
zIndex: "990",
},
Elements: {}
},
Elements: {
SubContent: {
_: TK.Navigator,
Templates: {},
NavigatorLevel: 1,
DefaultHash: this.Content[name].DefaultContent ? this.Content[name].DefaultContent : this.DefaultContent,
Navigate: function (page) {
if (obj.SubMenu) {
obj.SubMenu.Remove();
}
obj.SubMenu = obj.Add(this.Parent.MenuTemplate, "SubMenu");
var menuItems = obj.SubMenu.Elements.ToArray();
for (var i = 0; i < menuItems.length; i++)
menuItems[i].className = menuItems[i].className.replace("toolkitActive", "");
if (obj.SubMenu.Elements["MenuItem" + page])
obj.SubMenu.Elements["MenuItem" + page].className += " toolkitActive";
obj.ProcessResize();
},
Destroy: function () {
this.Navigate = null;
window.removeEventListener("hashchange", this.onHashChangeHandler);
if (obj.SubMenu)
obj.SubMenu.Remove();
obj.ProcessResize();
}
}
}
};
for (var subName in this.Content[name].Content) {
var contentObj = this.Content[name].Content[subName];
if (!contentObj.Hidden) {
var menuItemTemplate = {
_: "li",
className: "toolkitActive",
innerHTML: contentObj.Name ? contentObj.Name : subName,
Hash: name + "/" + subName,
onclick: function () {
window.location.hash = "#" + this.Hash;
},
Elements: {
}
};
if (contentObj.Icon) {
menuItemTemplate.className += " menuButtonWithIcon";
menuItemTemplate.Elements.Icon = {
innerHTML: contentObj.Icon
};
}
content.Templates[name].MenuTemplate.Elements["MenuItem" + subName] = menuItemTemplate;
}
content.Templates[name].Elements.SubContent.Templates[subName] = contentObj.Template;
}
} else {
content.Templates[name] = this.Content[name].Template;
}
}
this.Add(content, "Content");
if (this.CurrentUserTemplate) {
header.Elements.CurrentUser.Add(this.CurrentUserTemplate, "User");
}
if (this.CurrentLogoTemplate) {
header.Elements.CurrentLogo.Add(this.CurrentLogoTemplate, "Logo");
}
this.OnResizeListener = function () {
obj.ProcessResize();
};
window.addEventListener("resize", this.OnResizeListener);
setTimeout(function () {
obj.ProcessResize();
},1);
},
ProcessResize: function () {
var obj = this;
var w = (this.Embedded ? this.offsetWidth : document.body.offsetWidth);
if (w < this.ResponsiveThreshold) { // Small view
//this.Elements.Menu.style.width = (this.MenuIconSize + this.MenuTextSize) + "px";
if (this.Elements.Menu) {
this.Elements.Menu.style.width = "100%";
this.Elements.Menu.style.display = this.ShowMenu ? "" : "none";
if (this.Elements.Menu.className.indexOf("toolkitDocked") >= 0) {
this.Elements.Menu.className = this.Elements.Menu.className.replace(/toolkitDocked/g, "");
}
this.Elements.Header.Elements.HamburgerMenu.style.display = "";
this.Elements.Header.Elements.HamburgerMenu.className = "Element-HamburgerMenu " + (this.ShowMenu ? "toolkitActive" : "");
this.Elements.Header.Elements.CurrentLogo.style.left = "43px";
if (this.Embedded) {
this.Elements.Content.style.left = "0px";
} else {
document.body.style.paddingLeft = "0px";
}
}
if (this.className.indexOf("toolkitSizeMedium") >= 0)
this.className = this.className.replace(/toolkitSizeMedium/g, "");
if (this.className.indexOf("toolkitSizeSmall") < 0)
this.className += " toolkitSizeSmall";
if (this.Embedded) {
this.Elements.Content.style.top = this.Elements.Header.style.height;
} else {
document.body.style.paddingTop = this.Elements.Header.style.height;
}
if (this.Elements.SubMenu) {
this.Elements.SubMenu.style.top = "";
this.Elements.SubMenu.style.bottom = "0px";
this.Elements.SubMenu.style.left = "0px";
this.Elements.SubMenu.style.right = "0px";
if (this.Embedded) {
this.Elements.Content.style.bottom = "60pt";
} else {
document.body.style.paddingBottom = "60pt";
}
} else {
if (this.Embedded) {
this.Elements.Content.style.bottom = "0px";
} else {
document.body.style.paddingBottom = "0px";
}
}
this.CurrentScrollElement = this.Embedded ? this.Elements.Content : window;
this.CurrentScrollPosition = this.CurrentScrollElement.scrollY === undefined ? this.CurrentScrollElement.scrollTop : this.CurrentScrollElement.scrollY;
if (!this.OnScrollListener) {
var scrollUpCounter = 0;
var scrollDownCounter = 0;
this.OnScrollListener = function () {
obj.ShowMenu = false;
if (obj.Elements.Menu) {
obj.Elements.Menu.style.display = "none";
obj.Elements.Header.Elements.HamburgerMenu.className = "Element-HamburgerMenu";
}
if (obj.Embedded) {
var newScroll = obj.CurrentScrollElement.scrollTop;
var oldScroll = obj.CurrentScrollPosition;
obj.CurrentScrollPosition = newScroll;
if (newScroll + obj.CurrentScrollElement.offsetHeight + 50 > obj.CurrentScrollElement.scrollHeight)
return;
if (newScroll < oldScroll) {
scrollUpCounter += oldScroll - newScroll;
scrollDownCounter = 0;
} else {
scrollUpCounter = 0;
scrollDownCounter += newScroll - oldScroll;
}
if (scrollDownCounter > 40 && newScroll > 50) {
// Hide menu
obj.Elements.Header.style.height = "0px";
obj.Elements.Content.style.top = "0px";
if (obj.Elements.Menu)
obj.Elements.Menu.style.top = "0px";
} else if (scrollUpCounter > 40) {
obj.Elements.Header.style.height = "40px";
obj.Elements.Content.style.top = "40px";
if (obj.Elements.Menu)
obj.Elements.Menu.style.top = "40px";
}
} else {
var newScroll = obj.CurrentScrollElement.scrollY;
var oldScroll = obj.CurrentScrollPosition;
obj.CurrentScrollPosition = newScroll;
if (newScroll + window.innerHeight + 50 > document.documentElement.scrollHeight)
return;
if (newScroll < oldScroll) {
scrollUpCounter += oldScroll - newScroll;
scrollDownCounter = 0;
} else {
scrollUpCounter = 0;
scrollDownCounter += newScroll - oldScroll;
}
if (scrollDownCounter > 40 && newScroll > 50) {
// Hide menu
obj.Elements.Header.style.height = "0px";
} else if (scrollUpCounter > 40) {
obj.Elements.Header.style.height = "40px";
}
}
};
this.CurrentScrollElement.addEventListener("scroll", this.OnScrollListener);
}
} else {
this.ShowMenu = false;
var paddingLeft = 0;
if (this.className.indexOf("toolkitSizeSmall") >= 0)
this.className = this.className.replace(/toolkitSizeSmall/g, "");
if (w < this.ResponsiveFullThreshold) { // Medium view
paddingLeft = (this.MenuIconSize);
if (this.className.indexOf("toolkitSizeMedium") < 0)
this.className += " toolkitSizeMedium";
} else { // Big/default view
if (this.className.indexOf("toolkitSizeMedium") >= 0)
this.className = this.className.replace(/toolkitSizeMedium/g, "");
paddingLeft = (this.MenuIconSize + this.MenuTextSize);
}
if (this.Elements.Menu) {
this.Elements.Menu.style.display = "";
this.Elements.Header.Elements.HamburgerMenu.style.display = "none";
this.Elements.Header.Elements.CurrentLogo.style.left = "9px";
if (w < this.ResponsiveFullThreshold) { // Medium view
// Just show icons
if (this.Elements.Menu.className.indexOf("toolkitDocked") < 0)
this.Elements.Menu.className += " toolkitDocked";
} else {
// Show icons and text
if (this.Elements.Menu.className.indexOf("toolkitDocked") >= 0)
this.Elements.Menu.className = this.Elements.Menu.className.replace(/toolkitDocked/g, "");
}
if (this.Embedded) {
this.Elements.Content.style.left = paddingLeft + "px";
this.Elements.Content.style.top = "40px";
} else {
document.body.style.paddingLeft = paddingLeft + "px";
document.body.style.paddingTop = "40px";
}
this.Elements.Header.style.height = "40px";
this.Elements.Menu.style.top = "40px";
this.Elements.Menu.style.width = paddingLeft + "px";
} else {
paddingLeft = 0;
}
if (this.Elements.SubMenu) {
this.Elements.SubMenu.style.bottom = "";
this.Elements.SubMenu.style.top = "40px";
this.Elements.SubMenu.style.left = paddingLeft + "px";
this.Elements.SubMenu.style.right = "0px";
if (this.Embedded) {
this.Elements.Content.style.top = "80px";
} else {
document.body.style.paddingTop = "80px";
}
}
if (this.Embedded) {
this.Elements.Content.style.bottom = "0px";
} else {
document.body.style.paddingBottom = "0px";
}
if (this.OnScrollListener) {
this.CurrentScrollElement.removeEventListener("scroll", this.OnScrollListener);
this.OnScrollListener = null;
}
}
},
Destroy: function () {
window.removeEventListener("resize", this.OnResizeListener);
if (this.OnScrollListener) {
this.CurrentScrollElement.removeEventListener("scroll", this.OnScrollListener);
}
if (!this.Embedded) {
document.body.style.paddingTop = "";
document.body.style.paddingLeft = "";
}
},
Elements: {}
};"use strict";
/* Minify Order(200) */
window.TK.Slider = {
TextBefore: "",
TextAfter: "",
Min: 0,
Max: 100,
Width: 200,
StepSize: 0, // 0 to disable
ShowSteps: false,
Data: 0,
className: "toolkitSlider",
readOnly: false,
disabled: false,
onchange: function () { },
Init: function () {
if (this.DataSettings) {
var fields = ["TextBefore", "TextAfter", "Min", "Max", "StepSize", "ShowSteps"];
for (var i = 0; i < fields.length; i++) {
if (this.DataSettings[fields[i]] !== undefined)
this[fields[i]] = this.DataSettings[fields[i]];
}
}
this.Elements.SliderContainer.Elements.Steps.style.display = this.ShowSteps && this.StepSize > 0 ? "" : "none";
if (this.StepSize > 0) {
var stepCount = Math.floor((this.Max - this.Min) / this.StepSize) + 1;
this.Elements.SliderContainer.Elements.Steps.Clear();
for (var i = 0; i < stepCount; i++) {
var stepDataValue = this.Min + (this.StepSize * i);
this.Elements.SliderContainer.Elements.Steps.Add({
style: {
left: this.DataValueToPX(stepDataValue) + "px"
},
className: stepDataValue <= this.Data ? "stepActive" : "stepInactive"
}, "Step" + i);
}
} else {
this.Elements.SliderContainer.Elements.Steps.Clear();
}
this.Elements.TextBefore.innerText = this.TextBefore;
this.Elements.TextBefore.style.display = this.TextBefore ? "" : "none";
this.Elements.TextAfter.innerText = this.TextAfter;
this.Elements.TextAfter.style.display = this.TextAfter ? "" : "none";
this.Elements.SliderContainer.style.width = this.Width + "px";
var curPx = this.DataValueToPX(this.Data);
this.Elements.SliderContainer.Elements.Indicator.style.left = curPx + "px";
this.Elements.SliderContainer.Elements.FillBar.style.width = curPx + "px";
},
DataValueToPX: function (dataValue) {
return Math.round(((dataValue - this.Min) / (this.Max - this.Min)) * this.Width);
},
PXToDataValue: function (px, roundStepSize) {
if (roundStepSize) {
var tmp = ((px / this.Width) * (this.Max - this.Min));
tmp += (roundStepSize / 2);
tmp = (tmp - (tmp % roundStepSize)) + this.Min;
if (tmp > this.Max)
tmp = this.Max;
return tmp;
}
return ((px / this.Width) * (this.Max - this.Min)) + this.Min;
},
GetValue: function () {
return this.Data;
},
Elements: {
TextBefore: {},
SliderContainer: {
onmousdown: function (ev) {
ev.preventDefault();
},
ontouchstart: function (e) {
ev.preventDefault();
},
Elements: {
Steps: {},
FillBar: {},
Indicator: {
ontouchstart: function (e) {
this.onmousedown(e.touches[0]);
e.stopPropagation();
},
onmousedown: function (e) {
var x, y;
try { x = e.clientX; y = e.clientY; } catch (errie) { var e2 = window.event; x = e2.clientX; y = e2.clientY; }
var startPos = this.Parent.Parent.DataValueToPX(this.Parent.Parent.Data);
var obj = this;
window.onmousemove = function (e) {
var x2, y2;
try { x2 = e.clientX; y2 = e.clientY; } catch (errie) { var e2 = window.event; x2 = e2.clientX; y2 = e2.clientY; }
var newPos = startPos + (x2 - x);
if (newPos < 0)
newPos = 0;
else if (newPos > obj.Parent.Parent.Width)
newPos = obj.Parent.Parent.Width;
// Jump to the nearest step and calculate data value based on new pos
obj.Parent.Parent.Data = obj.Parent.Parent.PXToDataValue(newPos, obj.Parent.Parent.StepSize);
// Redraw elements
if (obj.Parent.Parent.onchange)
obj.Parent.Parent.onchange();
obj.Parent.Parent.Init();
};
window.onmouseup = function () {
window.onmousemove = null;
window.onmouseup = null;
window.onselectstart = null;
window.ontouchmove = null;
window.ontouchend = null;
};
window.ontouchmove = function (e) {
if (window.onmousemove)
window.onmousemove(e.touches[0]);
e.stopPropagation();
};
window.ontouchend = function (e) {
if (window.onmouseup)
window.onmouseup();
e.stopPropagation();
};
window.onselectstart = function () { return false; };
if (e && e.preventDefault)
e.preventDefault();
else
window.event.returnValue = false;
},
}
}
},
TextAfter: {},
}
};
if (window.TK.Form) {
window.TK.Form.DefaultTemplates.slider = {
_: TK.Slider
};
}
"use strict";
/* Minify Order(200) */
window.TK.Switch = {
TextBefore: "",
TextAfter: "",
Data: false,
className: "toolkitSwitch",
onchange: function () { },
readOnly: false,
disabled: false,
onclick: function () {
this.Toggle();
},
Toggle: function () {
if (this.readOnly || this.disabled)
return;
this.Data = !this.Data;
if (this.onchange)
this.onchange();
this.Init();
},
Init: function () {
if (this.DataSettings) {
if (this.DataSettings.TextBefore !== undefined)
this.TextBefore = this.DataSettings.TextBefore;
if (this.DataSettings.TextAfter !== undefined)
this.TextAfter = this.DataSettings.TextAfter;
}
this.className = this.className.replace(/toolkitSwitchActive/g, "").replace(/toolkitSwitchInactive/g, "").replace(/toolkitSwitchDisabled/g, "").replace(/toolkitSwitchReadOnly/g, "") + " "
+ (this.disabled ? "toolkitSwitchDisabled" : "")
+ " " + (this.readOnly ? "toolkitSwitchReadOnly" : "")
+ " " + (this.Data ? "toolkitSwitchActive" : "toolkitSwitchInactive");
this.Elements.TextBefore.innerText = this.TextBefore;
this.Elements.TextBefore.style.display = this.TextBefore ? "" : "none";
this.Elements.TextAfter.innerText = this.TextAfter;
this.Elements.TextAfter.style.display = this.TextAfter ? "" : "none";
},
GetValue: function () {
return this.Data;
},
Elements: {
TextBefore: {},
SwitchContainer: {
Elements: {
Indicator: {
_: "div"
}
}
},
TextAfter: {},
}
};
if (window.TK.Form) {
window.TK.Form.DefaultTemplates.switch = {
_: TK.Switch
};
}