diff --git a/about.json b/about.json index 08d6da1..eb1acce 100644 --- a/about.json +++ b/about.json @@ -9,6 +9,7 @@ "minimum_discourse_version": null, "maximum_discourse_version": null, "assets": { + "jsuites": "assets/jsuites.js", "jspreadsheet": "assets/jspreadsheet.js" }, "modifiers": { diff --git a/assets/jspreadsheet.js b/assets/jspreadsheet.js index 9802e04..01b2e38 100644 --- a/assets/jspreadsheet.js +++ b/assets/jspreadsheet.js @@ -1,13314 +1,3 @@ -/** - * (c) jSuites Javascript Web Components - * - * Website: https://jsuites.net - * Description: Create amazing web based applications. - * - * MIT License - * - */ -(function (global, factory) { - typeof exports === "object" && typeof module !== "undefined" - ? (module.exports = factory()) - : typeof define === "function" && define.amd - ? define(factory) - : (global.jSuites = factory()); -})(this, function () { - "use strict"; - - var jSuites = {}; - - var Version = "4.14.3"; - - var Events = function () { - document.jsuitesComponents = []; - - var find = function (DOMElement, component) { - if ( - DOMElement[component.type] && - DOMElement[component.type] == component - ) { - return true; - } - if (DOMElement.component && DOMElement.component == component) { - return true; - } - if (DOMElement.parentNode) { - return find(DOMElement.parentNode, component); - } - return false; - }; - - var isOpened = function (e) { - if (document.jsuitesComponents && document.jsuitesComponents.length > 0) { - for (var i = 0; i < document.jsuitesComponents.length; i++) { - if ( - document.jsuitesComponents[i] && - !find(e, document.jsuitesComponents[i]) - ) { - document.jsuitesComponents[i].close(); - } - } - } - }; - - // Width of the border - var cornerSize = 15; - - // Current element - var element = null; - - // Controllers - var editorAction = false; - - // Event state - var state = { - x: null, - y: null, - }; - - // Tooltip element - var tooltip = document.createElement("div"); - tooltip.classList.add("jtooltip"); - - // Events - var mouseDown = function (e) { - // Check if this is the floating - var item = jSuites.findElement(e.target, "jpanel"); - // Jfloating found - if (item && !item.classList.contains("readonly")) { - // Add focus to the chart container - item.focus(); - // Keep the tracking information - var rect = e.target.getBoundingClientRect(); - editorAction = { - e: item, - x: e.clientX, - y: e.clientY, - w: rect.width, - h: rect.height, - d: item.style.cursor, - resizing: item.style.cursor ? true : false, - actioned: false, - }; - - // Make sure width and height styling is OK - if (!item.style.width) { - item.style.width = rect.width + "px"; - } - - if (!item.style.height) { - item.style.height = rect.height + "px"; - } - - // Remove any selection from the page - var s = window.getSelection(); - if (s.rangeCount) { - for (var i = 0; i < s.rangeCount; i++) { - s.removeRange(s.getRangeAt(i)); - } - } - - e.preventDefault(); - e.stopPropagation(); - } else { - // No floating action found - editorAction = false; - } - - // Verify current components tracking - if (e.changedTouches && e.changedTouches[0]) { - var x = e.changedTouches[0].clientX; - var y = e.changedTouches[0].clientY; - } else { - var x = e.clientX; - var y = e.clientY; - } - - // Which component I am clicking - var path = e.path || (e.composedPath && e.composedPath()); - - // If path available get the first element in the chain - if (path) { - element = path[0]; - } else { - // Try to guess using the coordinates - if (e.target && e.target.shadowRoot) { - var d = e.target.shadowRoot; - } else { - var d = document; - } - // Get the first target element - element = d.elementFromPoint(x, y); - } - - isOpened(element); - }; - - var mouseUp = function (e) { - if (editorAction && editorAction.e) { - if (typeof editorAction.e.refresh == "function" && state.actioned) { - editorAction.e.refresh(); - } - editorAction.e.style.cursor = ""; - } - - // Reset - state = { - x: null, - y: null, - }; - - editorAction = false; - }; - - var mouseMove = function (e) { - if (editorAction) { - var x = e.clientX || e.pageX; - var y = e.clientY || e.pageY; - - // Action on going - if (!editorAction.resizing) { - if (state.x == null && state.y == null) { - state.x = x; - state.y = y; - } - - var dx = x - state.x; - var dy = y - state.y; - var top = editorAction.e.offsetTop + dy; - var left = editorAction.e.offsetLeft + dx; - - // Update position - editorAction.e.style.top = top + "px"; - editorAction.e.style.left = left + "px"; - editorAction.e.style.cursor = "move"; - - state.x = x; - state.y = y; - - // Update element - if (typeof editorAction.e.refresh == "function") { - state.actioned = true; - editorAction.e.refresh("position", top, left); - } - } else { - var width = null; - var height = null; - - if ( - editorAction.d == "e-resize" || - editorAction.d == "ne-resize" || - editorAction.d == "se-resize" - ) { - // Update width - width = editorAction.w + (x - editorAction.x); - editorAction.e.style.width = width + "px"; - - // Update Height - if (e.shiftKey) { - var newHeight = - (x - editorAction.x) * (editorAction.h / editorAction.w); - height = editorAction.h + newHeight; - editorAction.e.style.height = height + "px"; - } else { - var newHeight = false; - } - } - - if (!newHeight) { - if ( - editorAction.d == "s-resize" || - editorAction.d == "se-resize" || - editorAction.d == "sw-resize" - ) { - height = editorAction.h + (y - editorAction.y); - editorAction.e.style.height = height + "px"; - } - } - - // Update element - if (typeof editorAction.e.refresh == "function") { - state.actioned = true; - editorAction.e.refresh("dimensions", width, height); - } - } - } else { - // Resizing action - var item = jSuites.findElement(e.target, "jpanel"); - // Found eligible component - if (item) { - if (item.getAttribute("tabindex")) { - var rect = item.getBoundingClientRect(); - if (e.clientY - rect.top < cornerSize) { - if (rect.width - (e.clientX - rect.left) < cornerSize) { - item.style.cursor = "ne-resize"; - } else if (e.clientX - rect.left < cornerSize) { - item.style.cursor = "nw-resize"; - } else { - item.style.cursor = "n-resize"; - } - } else if (rect.height - (e.clientY - rect.top) < cornerSize) { - if (rect.width - (e.clientX - rect.left) < cornerSize) { - item.style.cursor = "se-resize"; - } else if (e.clientX - rect.left < cornerSize) { - item.style.cursor = "sw-resize"; - } else { - item.style.cursor = "s-resize"; - } - } else if (rect.width - (e.clientX - rect.left) < cornerSize) { - item.style.cursor = "e-resize"; - } else if (e.clientX - rect.left < cornerSize) { - item.style.cursor = "w-resize"; - } else { - item.style.cursor = ""; - } - } - } - } - }; - - var mouseOver = function (e) { - var message = e.target.getAttribute("data-tooltip"); - if (message) { - // Instructions - tooltip.innerText = message; - - // Position - if (e.changedTouches && e.changedTouches[0]) { - var x = e.changedTouches[0].clientX; - var y = e.changedTouches[0].clientY; - } else { - var x = e.clientX; - var y = e.clientY; - } - - tooltip.style.top = y + "px"; - tooltip.style.left = x + "px"; - document.body.appendChild(tooltip); - } else if (tooltip.innerText) { - tooltip.innerText = ""; - document.body.removeChild(tooltip); - } - }; - - var dblClick = function (e) { - var item = jSuites.findElement(e.target, "jpanel"); - if (item && typeof item.dblclick == "function") { - // Create edition - item.dblclick(e); - } - }; - - var contextMenu = function (e) { - var item = document.activeElement; - if (item && typeof item.contextmenu == "function") { - // Create edition - item.contextmenu(e); - - e.preventDefault(); - e.stopImmediatePropagation(); - } else { - // Search for possible context menus - item = jSuites.findElement(e.target, function (o) { - return o.tagName && o.getAttribute("aria-contextmenu-id"); - }); - - if (item) { - var o = document.querySelector("#" + item); - if (!o) { - console.error("JSUITES: contextmenu id not found: " + item); - } else { - o.contextmenu.open(e); - e.preventDefault(); - e.stopImmediatePropagation(); - } - } - } - }; - - var keyDown = function (e) { - var item = document.activeElement; - if (item) { - if (e.key == "Delete" && typeof item.delete == "function") { - item.delete(); - e.preventDefault(); - e.stopImmediatePropagation(); - } - } - - if (document.jsuitesComponents && document.jsuitesComponents.length) { - if ( - (item = - document.jsuitesComponents[document.jsuitesComponents.length - 1]) - ) { - if (e.key == "Escape" && typeof item.close == "function") { - item.close(); - e.preventDefault(); - e.stopImmediatePropagation(); - } - } - } - }; - - document.addEventListener("mouseup", mouseUp); - document.addEventListener("mousedown", mouseDown); - document.addEventListener("mousemove", mouseMove); - document.addEventListener("mouseover", mouseOver); - document.addEventListener("dblclick", dblClick); - document.addEventListener("keydown", keyDown); - document.addEventListener("contextmenu", contextMenu); - }; - - /** - * Global jsuites event - */ - if (typeof document !== "undefined" && !document.jsuitesComponents) { - Events(); - } - - jSuites.version = Version; - - jSuites.setExtensions = function (o) { - if (typeof o == "object") { - var k = Object.keys(o); - for (var i = 0; i < k.length; i++) { - jSuites[k[i]] = o[k[i]]; - } - } - }; - - jSuites.tracking = function (component, state) { - if (state == true) { - document.jsuitesComponents = document.jsuitesComponents.filter(function ( - v - ) { - return v !== null; - }); - - // Start after all events - setTimeout(function () { - document.jsuitesComponents.push(component); - }, 0); - } else { - var index = document.jsuitesComponents.indexOf(component); - if (index >= 0) { - document.jsuitesComponents.splice(index, 1); - } - } - }; - - /** - * Get or set a property from a JSON from a string. - */ - jSuites.path = function (str, val) { - str = str.split("."); - if (str.length) { - var o = this; - var p = null; - while (str.length > 1) { - // Get the property - p = str.shift(); - // Check if the property exists - if (o.hasOwnProperty(p)) { - o = o[p]; - } else { - // Property does not exists - if (val === undefined) { - return undefined; - } else { - // Create the property - o[p] = {}; - // Next property - o = o[p]; - } - } - } - // Get the property - p = str.shift(); - // Set or get the value - if (val !== undefined) { - o[p] = val; - // Success - return true; - } else { - // Return the value - if (o) { - return o[p]; - } - } - } - // Something went wrong - return false; - }; - - // Update dictionary - jSuites.setDictionary = function (d) { - if (!document.dictionary) { - document.dictionary = {}; - } - // Replace the key into the dictionary and append the new ones - var k = Object.keys(d); - for (var i = 0; i < k.length; i++) { - document.dictionary[k[i]] = d[k[i]]; - } - - // Translations - var t = null; - for (var i = 0; i < jSuites.calendar.weekdays.length; i++) { - t = jSuites.translate(jSuites.calendar.weekdays[i]); - if (jSuites.calendar.weekdays[i]) { - jSuites.calendar.weekdays[i] = t; - jSuites.calendar.weekdaysShort[i] = t.substr(0, 3); - } - } - for (var i = 0; i < jSuites.calendar.months.length; i++) { - t = jSuites.translate(jSuites.calendar.months[i]); - if (t) { - jSuites.calendar.months[i] = t; - jSuites.calendar.monthsShort[i] = t.substr(0, 3); - } - } - }; - - // Translate - jSuites.translate = function (t) { - if (document.dictionary) { - return document.dictionary[t] || t; - } else { - return t; - } - }; - - jSuites.ajax = function (options, complete) { - if (Array.isArray(options)) { - // Create multiple request controller - var multiple = { - instance: [], - complete: complete, - }; - - if (options.length > 0) { - for (var i = 0; i < options.length; i++) { - options[i].multiple = multiple; - multiple.instance.push(jSuites.ajax(options[i])); - } - } - - return multiple; - } - - if (!options.data) { - options.data = {}; - } - - if (options.type) { - options.method = options.type; - } - - // Default method - if (!options.method) { - options.method = "GET"; - } - - // Default type - if (!options.dataType) { - options.dataType = "json"; - } - - if (options.data) { - // Parse object to variables format - var parseData = function (value, key) { - var vars = []; - if (value) { - var keys = Object.keys(value); - if (keys.length) { - for (var i = 0; i < keys.length; i++) { - if (key) { - var k = key + "[" + keys[i] + "]"; - } else { - var k = keys[i]; - } - - if (value[k] instanceof FileList) { - vars[k] = value[keys[i]]; - } else if ( - value[keys[i]] === null || - value[keys[i]] === undefined - ) { - vars[k] = ""; - } else if (typeof value[keys[i]] == "object") { - var r = parseData(value[keys[i]], k); - var o = Object.keys(r); - for (var j = 0; j < o.length; j++) { - vars[o[j]] = r[o[j]]; - } - } else { - vars[k] = value[keys[i]]; - } - } - } - } - - return vars; - }; - - var d = parseData(options.data); - var k = Object.keys(d); - - // Data form - if (options.method == "GET") { - if (k.length) { - var data = []; - for (var i = 0; i < k.length; i++) { - data.push(k[i] + "=" + encodeURIComponent(d[k[i]])); - } - - if (options.url.indexOf("?") < 0) { - options.url += "?"; - } - options.url += data.join("&"); - } - } else { - var data = new FormData(); - for (var i = 0; i < k.length; i++) { - if (d[k[i]] instanceof FileList) { - if (d[k[i]].length) { - for (var j = 0; j < d[k[i]].length; j++) { - data.append(k[i], d[k[i]][j], d[k[i]][j].name); - } - } - } else { - data.append(k[i], d[k[i]]); - } - } - } - } - - var httpRequest = new XMLHttpRequest(); - httpRequest.open(options.method, options.url, true); - httpRequest.setRequestHeader("X-Requested-With", "XMLHttpRequest"); - - // Content type - if (options.contentType) { - httpRequest.setRequestHeader("Content-Type", options.contentType); - } - - // Headers - if (options.method == "POST") { - httpRequest.setRequestHeader("Accept", "application/json"); - } else { - if (options.dataType == "blob") { - httpRequest.responseType = "blob"; - } else { - if (!options.contentType) { - if (options.dataType == "json") { - httpRequest.setRequestHeader("Content-Type", "text/json"); - } else if (options.dataType == "html") { - httpRequest.setRequestHeader("Content-Type", "text/html"); - } - } - } - } - - // No cache - if (options.cache != true) { - httpRequest.setRequestHeader("pragma", "no-cache"); - httpRequest.setRequestHeader("cache-control", "no-cache"); - } - - // Authentication - if (options.withCredentials == true) { - httpRequest.withCredentials = true; - } - - // Before send - if (typeof options.beforeSend == "function") { - options.beforeSend(httpRequest); - } - - // Before send - if (typeof jSuites.ajax.beforeSend == "function") { - jSuites.ajax.beforeSend(httpRequest); - } - - if (document.ajax && typeof document.ajax.beforeSend == "function") { - document.ajax.beforeSend(httpRequest); - } - - httpRequest.onload = function () { - if (httpRequest.status === 200) { - if (options.dataType == "json") { - try { - var result = JSON.parse(httpRequest.responseText); - - if (options.success && typeof options.success == "function") { - options.success(result); - } - } catch (err) { - if (options.error && typeof options.error == "function") { - options.error(err, result); - } - } - } else { - if (options.dataType == "blob") { - var result = httpRequest.response; - } else { - var result = httpRequest.responseText; - } - - if (options.success && typeof options.success == "function") { - options.success(result); - } - } - } else { - if (options.error && typeof options.error == "function") { - options.error(httpRequest.responseText, httpRequest.status); - } - } - - // Global queue - if (jSuites.ajax.queue && jSuites.ajax.queue.length > 0) { - jSuites.ajax.send(jSuites.ajax.queue.shift()); - } - - // Global complete method - if (jSuites.ajax.requests && jSuites.ajax.requests.length) { - // Get index of this request in the container - var index = jSuites.ajax.requests.indexOf(httpRequest); - // Remove from the ajax requests container - jSuites.ajax.requests.splice(index, 1); - // Deprected: Last one? - if (!jSuites.ajax.requests.length) { - // Object event - if (options.complete && typeof options.complete == "function") { - options.complete(result); - } - } - // Group requests - if (options.group) { - if ( - jSuites.ajax.oncomplete && - typeof jSuites.ajax.oncomplete[options.group] == "function" - ) { - if (!jSuites.ajax.pending(options.group)) { - jSuites.ajax.oncomplete[options.group](); - jSuites.ajax.oncomplete[options.group] = null; - } - } - } - // Multiple requests controller - if (options.multiple && options.multiple.instance) { - // Get index of this request in the container - var index = options.multiple.instance.indexOf(httpRequest); - // Remove from the ajax requests container - options.multiple.instance.splice(index, 1); - // If this is the last one call method complete - if (!options.multiple.instance.length) { - if ( - options.multiple.complete && - typeof options.multiple.complete == "function" - ) { - options.multiple.complete(result); - } - } - } - } - }; - - // Keep the options - httpRequest.options = options; - // Data - httpRequest.data = data; - - // Queue - if (options.queue == true && jSuites.ajax.requests.length > 0) { - jSuites.ajax.queue.push(httpRequest); - } else { - jSuites.ajax.send(httpRequest); - } - - return httpRequest; - }; - - jSuites.ajax.send = function (httpRequest) { - if (httpRequest.data) { - if (Array.isArray(httpRequest.data)) { - httpRequest.send(httpRequest.data.join("&")); - } else { - httpRequest.send(httpRequest.data); - } - } else { - httpRequest.send(); - } - - jSuites.ajax.requests.push(httpRequest); - }; - - jSuites.ajax.exists = function (url, __callback) { - var http = new XMLHttpRequest(); - http.open("HEAD", url, false); - http.send(); - if (http.status) { - __callback(http.status); - } - }; - - jSuites.ajax.pending = function (group) { - var n = 0; - var o = jSuites.ajax.requests; - if (o && o.length) { - for (var i = 0; i < o.length; i++) { - if (!group || group == o[i].options.group) { - n++; - } - } - } - return n; - }; - - jSuites.ajax.oncomplete = {}; - jSuites.ajax.requests = []; - jSuites.ajax.queue = []; - - jSuites.alert = function (message) { - if (jSuites.getWindowWidth() < 800 && jSuites.dialog) { - jSuites.dialog.open({ - title: "Alert", - message: message, - }); - } else { - alert(message); - } - }; - - jSuites.animation = {}; - - jSuites.animation.slideLeft = function (element, direction, done) { - if (direction == true) { - element.classList.add("slide-left-in"); - setTimeout(function () { - element.classList.remove("slide-left-in"); - if (typeof done == "function") { - done(); - } - }, 400); - } else { - element.classList.add("slide-left-out"); - setTimeout(function () { - element.classList.remove("slide-left-out"); - if (typeof done == "function") { - done(); - } - }, 400); - } - }; - - jSuites.animation.slideRight = function (element, direction, done) { - if (direction == true) { - element.classList.add("slide-right-in"); - setTimeout(function () { - element.classList.remove("slide-right-in"); - if (typeof done == "function") { - done(); - } - }, 400); - } else { - element.classList.add("slide-right-out"); - setTimeout(function () { - element.classList.remove("slide-right-out"); - if (typeof done == "function") { - done(); - } - }, 400); - } - }; - - jSuites.animation.slideTop = function (element, direction, done) { - if (direction == true) { - element.classList.add("slide-top-in"); - setTimeout(function () { - element.classList.remove("slide-top-in"); - if (typeof done == "function") { - done(); - } - }, 400); - } else { - element.classList.add("slide-top-out"); - setTimeout(function () { - element.classList.remove("slide-top-out"); - if (typeof done == "function") { - done(); - } - }, 400); - } - }; - - jSuites.animation.slideBottom = function (element, direction, done) { - if (direction == true) { - element.classList.add("slide-bottom-in"); - setTimeout(function () { - element.classList.remove("slide-bottom-in"); - if (typeof done == "function") { - done(); - } - }, 400); - } else { - element.classList.add("slide-bottom-out"); - setTimeout(function () { - element.classList.remove("slide-bottom-out"); - if (typeof done == "function") { - done(); - } - }, 100); - } - }; - - jSuites.animation.fadeIn = function (element, done) { - element.style.display = ""; - element.classList.add("fade-in"); - setTimeout(function () { - element.classList.remove("fade-in"); - if (typeof done == "function") { - done(); - } - }, 2000); - }; - - jSuites.animation.fadeOut = function (element, done) { - element.classList.add("fade-out"); - setTimeout(function () { - element.style.display = "none"; - element.classList.remove("fade-out"); - if (typeof done == "function") { - done(); - } - }, 1000); - }; - - jSuites.calendar = function (el, options) { - // Already created, update options - if (el.calendar) { - return el.calendar.setOptions(options, true); - } - - // New instance - var obj = { type: "calendar" }; - obj.options = {}; - - // Date - obj.date = null; - - /** - * Update options - */ - obj.setOptions = function (options, reset) { - // Default configuration - var defaults = { - // Render type: [ default | year-month-picker ] - type: "default", - // Restrictions - validRange: null, - // Starting weekday - 0 for sunday, 6 for saturday - startingDay: null, - // Date format - format: "DD/MM/YYYY", - // Allow keyboard date entry - readonly: true, - // Today is default - today: false, - // Show timepicker - time: false, - // Show the reset button - resetButton: true, - // Placeholder - placeholder: "", - // Translations can be done here - months: jSuites.calendar.monthsShort, - monthsFull: jSuites.calendar.months, - weekdays: jSuites.calendar.weekdays, - textDone: jSuites.translate("Done"), - textReset: jSuites.translate("Reset"), - textUpdate: jSuites.translate("Update"), - // Value - value: null, - // Fullscreen (this is automatic set for screensize < 800) - fullscreen: false, - // Create the calendar closed as default - opened: false, - // Events - onopen: null, - onclose: null, - onchange: null, - onupdate: null, - // Internal mode controller - mode: null, - position: null, - // Data type - dataType: null, - }; - - // Loop through our object - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - if (typeof obj.options[property] == "undefined" || reset === true) { - obj.options[property] = defaults[property]; - } - } - } - - // Reset button - if (obj.options.resetButton == false) { - calendarReset.style.display = "none"; - } else { - calendarReset.style.display = ""; - } - - // Readonly - if (obj.options.readonly) { - el.setAttribute("readonly", "readonly"); - } else { - el.removeAttribute("readonly"); - } - - // Placeholder - if (obj.options.placeholder) { - el.setAttribute("placeholder", obj.options.placeholder); - } else { - el.removeAttribute("placeholder"); - } - - if (jSuites.isNumeric(obj.options.value) && obj.options.value > 0) { - obj.options.value = jSuites.calendar.numToDate(obj.options.value); - // Data type numberic - obj.options.dataType = "numeric"; - } - - // Texts - calendarReset.innerHTML = obj.options.textReset; - calendarConfirm.innerHTML = obj.options.textDone; - calendarControlsUpdateButton.innerHTML = obj.options.textUpdate; - - // Define mask - el.setAttribute("data-mask", obj.options.format.toLowerCase()); - - // Value - if (!obj.options.value && obj.options.today) { - var value = jSuites.calendar.now(); - } else { - var value = obj.options.value; - } - - // Set internal date - if (value) { - // Force the update - obj.options.value = null; - // New value - obj.setValue(value); - } - - return obj; - }; - - /** - * Open the calendar - */ - obj.open = function (value) { - if (!calendar.classList.contains("jcalendar-focus")) { - if (!calendar.classList.contains("jcalendar-inline")) { - // Current - jSuites.calendar.current = obj; - // Start tracking - jSuites.tracking(obj, true); - // Create the days - obj.getDays(); - // Render months - if (obj.options.type == "year-month-picker") { - obj.getMonths(); - } - // Get time - if (obj.options.time) { - calendarSelectHour.value = obj.date[3]; - calendarSelectMin.value = obj.date[4]; - } - - // Show calendar - calendar.classList.add("jcalendar-focus"); - - // Get the position of the corner helper - if (jSuites.getWindowWidth() < 800 || obj.options.fullscreen) { - calendar.classList.add("jcalendar-fullsize"); - // Animation - jSuites.animation.slideBottom(calendarContent, 1); - } else { - calendar.classList.remove("jcalendar-fullsize"); - - var rect = el.getBoundingClientRect(); - var rectContent = calendarContent.getBoundingClientRect(); - - if (obj.options.position) { - calendarContainer.style.position = "fixed"; - if (window.innerHeight < rect.bottom + rectContent.height) { - calendarContainer.style.top = - rect.top - (rectContent.height + 2) + "px"; - } else { - calendarContainer.style.top = rect.top + rect.height + 2 + "px"; - } - calendarContainer.style.left = rect.left + "px"; - } else { - if (window.innerHeight < rect.bottom + rectContent.height) { - var d = -1 * (rect.height + rectContent.height + 2); - if (d + rect.top < 0) { - d = -1 * (rect.top + rect.height); - } - calendarContainer.style.top = d + "px"; - } else { - calendarContainer.style.top = 2 + "px"; - } - - if (window.innerWidth < rect.left + rectContent.width) { - var d = - window.innerWidth - (rect.left + rectContent.width + 20); - calendarContainer.style.left = d + "px"; - } else { - calendarContainer.style.left = "0px"; - } - } - } - - // Events - if (typeof obj.options.onopen == "function") { - obj.options.onopen(el); - } - } - } - }; - - obj.close = function (ignoreEvents, update) { - if (calendar.classList.contains("jcalendar-focus")) { - if (update !== false) { - var element = calendar.querySelector(".jcalendar-selected"); - - if (typeof update == "string") { - var value = update; - } else if ( - !element || - element.classList.contains("jcalendar-disabled") - ) { - var value = obj.options.value; - } else { - var value = obj.getValue(); - } - - obj.setValue(value); - } - - // Events - if (!ignoreEvents && typeof obj.options.onclose == "function") { - obj.options.onclose(el); - } - // Hide - calendar.classList.remove("jcalendar-focus"); - // Stop tracking - jSuites.tracking(obj, false); - // Current - jSuites.calendar.current = null; - } - - return obj.options.value; - }; - - obj.prev = function () { - // Check if the visualization is the days picker or years picker - if (obj.options.mode == "years") { - obj.date[0] = obj.date[0] - 12; - - // Update picker table of days - obj.getYears(); - } else if (obj.options.mode == "months") { - obj.date[0] = parseInt(obj.date[0]) - 1; - // Update picker table of months - obj.getMonths(); - } else { - // Go to the previous month - if (obj.date[1] < 2) { - obj.date[0] = obj.date[0] - 1; - obj.date[1] = 12; - } else { - obj.date[1] = obj.date[1] - 1; - } - - // Update picker table of days - obj.getDays(); - } - }; - - obj.next = function () { - // Check if the visualization is the days picker or years picker - if (obj.options.mode == "years") { - obj.date[0] = parseInt(obj.date[0]) + 12; - - // Update picker table of days - obj.getYears(); - } else if (obj.options.mode == "months") { - obj.date[0] = parseInt(obj.date[0]) + 1; - // Update picker table of months - obj.getMonths(); - } else { - // Go to the previous month - if (obj.date[1] > 11) { - obj.date[0] = parseInt(obj.date[0]) + 1; - obj.date[1] = 1; - } else { - obj.date[1] = parseInt(obj.date[1]) + 1; - } - - // Update picker table of days - obj.getDays(); - } - }; - - /** - * Set today - */ - obj.setToday = function () { - // Today - var value = new Date().toISOString().substr(0, 10); - // Change value - obj.setValue(value); - // Value - return value; - }; - - obj.setValue = function (val) { - if (!val) { - val = "" + val; - } - // Values - var newValue = val; - var oldValue = obj.options.value; - - if (oldValue != newValue) { - // Set label - if (!newValue) { - obj.date = null; - var val = ""; - } else { - var value = obj.setLabel(newValue, obj.options); - var date = newValue.split(" "); - if (!date[1]) { - date[1] = "00:00:00"; - } - var time = date[1].split(":"); - var date = date[0].split("-"); - var y = parseInt(date[0]); - var m = parseInt(date[1]); - var d = parseInt(date[2]); - var h = parseInt(time[0]); - var i = parseInt(time[1]); - obj.date = [y, m, d, h, i, 0]; - var val = obj.setLabel(newValue, obj.options); - } - - // New value - obj.options.value = newValue; - - if (typeof obj.options.onchange == "function") { - obj.options.onchange(el, newValue, oldValue); - } - - // Lemonade JS - if (el.value != val) { - el.value = val; - if (typeof el.oninput == "function") { - el.oninput({ - type: "input", - target: el, - value: el.value, - }); - } - } - } - - obj.getDays(); - }; - - obj.getValue = function () { - if (obj.date) { - if (obj.options.time) { - return ( - jSuites.two(obj.date[0]) + - "-" + - jSuites.two(obj.date[1]) + - "-" + - jSuites.two(obj.date[2]) + - " " + - jSuites.two(obj.date[3]) + - ":" + - jSuites.two(obj.date[4]) + - ":" + - jSuites.two(0) - ); - } else { - return ( - jSuites.two(obj.date[0]) + - "-" + - jSuites.two(obj.date[1]) + - "-" + - jSuites.two(obj.date[2]) + - " " + - jSuites.two(0) + - ":" + - jSuites.two(0) + - ":" + - jSuites.two(0) - ); - } - } else { - return ""; - } - }; - - /** - * Calendar - */ - obj.update = function (element, v) { - if (element.classList.contains("jcalendar-disabled")) { - // Do nothing - } else { - var elements = calendar.querySelector(".jcalendar-selected"); - if (elements) { - elements.classList.remove("jcalendar-selected"); - } - element.classList.add("jcalendar-selected"); - - if (element.classList.contains("jcalendar-set-month")) { - obj.date[1] = v; - obj.date[2] = 1; // first day of the month - } else { - obj.date[2] = element.innerText; - } - - if (!obj.options.time) { - obj.close(); - } else { - obj.date[3] = calendarSelectHour.value; - obj.date[4] = calendarSelectMin.value; - } - } - - // Update - updateActions(); - }; - - /** - * Set to blank - */ - obj.reset = function () { - // Close calendar - obj.setValue(""); - obj.date = null; - obj.close(false, false); - }; - - /** - * Get calendar days - */ - obj.getDays = function () { - // Mode - obj.options.mode = "days"; - - // Setting current values in case of NULLs - var date = new Date(); - - // Current selection - var year = - obj.date && jSuites.isNumeric(obj.date[0]) - ? obj.date[0] - : parseInt(date.getFullYear()); - var month = - obj.date && jSuites.isNumeric(obj.date[1]) - ? obj.date[1] - : parseInt(date.getMonth()) + 1; - var day = - obj.date && jSuites.isNumeric(obj.date[2]) - ? obj.date[2] - : parseInt(date.getDate()); - var hour = - obj.date && jSuites.isNumeric(obj.date[3]) - ? obj.date[3] - : parseInt(date.getHours()); - var min = - obj.date && jSuites.isNumeric(obj.date[4]) - ? obj.date[4] - : parseInt(date.getMinutes()); - - // Selection container - obj.date = [year, month, day, hour, min, 0]; - - // Update title - calendarLabelYear.innerHTML = year; - calendarLabelMonth.innerHTML = obj.options.months[month - 1]; - - // Current month and Year - var isCurrentMonthAndYear = - date.getMonth() == month - 1 && date.getFullYear() == year - ? true - : false; - var currentDay = date.getDate(); - - // Number of days in the month - var date = new Date(year, month, 0, 0, 0); - var numberOfDays = date.getDate(); - - // First day - var date = new Date(year, month - 1, 0, 0, 0); - var firstDay = date.getDay() + 1; - - // Index value - var index = obj.options.startingDay || 0; - - // First of day relative to the starting calendar weekday - firstDay = firstDay - index; - - // Reset table - calendarBody.innerHTML = ""; - - // Weekdays Row - var row = document.createElement("tr"); - row.setAttribute("align", "center"); - calendarBody.appendChild(row); - - // Create weekdays row - for (var i = 0; i < 7; i++) { - var cell = document.createElement("td"); - cell.classList.add("jcalendar-weekday"); - cell.innerHTML = obj.options.weekdays[index].substr(0, 1); - row.appendChild(cell); - // Next week day - index++; - // Restart index - if (index > 6) { - index = 0; - } - } - - // Index of days - var index = 0; - var d = 0; - - // Calendar table - for (var j = 0; j < 6; j++) { - // Reset cells container - var row = document.createElement("tr"); - row.setAttribute("align", "center"); - // Data control - var emptyRow = true; - // Create cells - for (var i = 0; i < 7; i++) { - // Create cell - var cell = document.createElement("td"); - cell.classList.add("jcalendar-set-day"); - - if (index >= firstDay && index < firstDay + numberOfDays) { - // Day cell - d++; - cell.innerHTML = d; - - // Selected - if (d == day) { - cell.classList.add("jcalendar-selected"); - } - - // Current selection day is today - if (isCurrentMonthAndYear && currentDay == d) { - cell.style.fontWeight = "bold"; - } - - // Current selection day - var current = jSuites.calendar.now( - new Date(year, month - 1, d), - true - ); - - // Available ranges - if (obj.options.validRange) { - if ( - !obj.options.validRange[0] || - current >= obj.options.validRange[0] - ) { - var test1 = true; - } else { - var test1 = false; - } - - if ( - !obj.options.validRange[1] || - current <= obj.options.validRange[1] - ) { - var test2 = true; - } else { - var test2 = false; - } - - if (!(test1 && test2)) { - cell.classList.add("jcalendar-disabled"); - } - } - - // Control - emptyRow = false; - } - // Day cell - row.appendChild(cell); - // Index - index++; - } - - // Add cell to the calendar body - if (emptyRow == false) { - calendarBody.appendChild(row); - } - } - - // Show time controls - if (obj.options.time) { - calendarControlsTime.style.display = ""; - } else { - calendarControlsTime.style.display = "none"; - } - - // Update - updateActions(); - }; - - obj.getMonths = function () { - // Mode - obj.options.mode = "months"; - - // Loading month labels - var months = obj.options.months; - - // Value - var value = obj.options.value; - - // Current date - var date = new Date(); - var currentYear = parseInt(date.getFullYear()); - var currentMonth = parseInt(date.getMonth()) + 1; - var selectedYear = - obj.date && jSuites.isNumeric(obj.date[0]) ? obj.date[0] : currentYear; - var selectedMonth = - obj.date && jSuites.isNumeric(obj.date[1]) ? obj.date[1] : currentMonth; - - // Update title - calendarLabelYear.innerHTML = obj.date[0]; - calendarLabelMonth.innerHTML = months[selectedMonth - 1]; - - // Table - var table = document.createElement("table"); - table.setAttribute("width", "100%"); - - // Row - var row = null; - - // Calendar table - for (var i = 0; i < 12; i++) { - if (!(i % 4)) { - // Reset cells container - var row = document.createElement("tr"); - row.setAttribute("align", "center"); - table.appendChild(row); - } - - // Create cell - var cell = document.createElement("td"); - cell.classList.add("jcalendar-set-month"); - cell.setAttribute("data-value", i + 1); - cell.innerText = months[i]; - - if (obj.options.validRange) { - var current = selectedYear + "-" + jSuites.two(i + 1); - if ( - !obj.options.validRange[0] || - current >= obj.options.validRange[0].substr(0, 7) - ) { - var test1 = true; - } else { - var test1 = false; - } - - if ( - !obj.options.validRange[1] || - current <= obj.options.validRange[1].substr(0, 7) - ) { - var test2 = true; - } else { - var test2 = false; - } - - if (!(test1 && test2)) { - cell.classList.add("jcalendar-disabled"); - } - } - - if (i + 1 == selectedMonth) { - cell.classList.add("jcalendar-selected"); - } - - if (currentYear == selectedYear && i + 1 == currentMonth) { - cell.style.fontWeight = "bold"; - } - - row.appendChild(cell); - } - - calendarBody.innerHTML = ''; - calendarBody.children[0].children[0].appendChild(table); - - // Update - updateActions(); - }; - - obj.getYears = function () { - // Mode - obj.options.mode = "years"; - - // Current date - var date = new Date(); - var currentYear = date.getFullYear(); - var selectedYear = - obj.date && jSuites.isNumeric(obj.date[0]) - ? obj.date[0] - : parseInt(date.getFullYear()); - - // Array of years - var y = []; - for (var i = 0; i < 25; i++) { - y[i] = parseInt(obj.date[0]) + (i - 12); - } - - // Assembling the year tables - var table = document.createElement("table"); - table.setAttribute("width", "100%"); - - for (var i = 0; i < 25; i++) { - if (!(i % 5)) { - // Reset cells container - var row = document.createElement("tr"); - row.setAttribute("align", "center"); - table.appendChild(row); - } - - // Create cell - var cell = document.createElement("td"); - cell.classList.add("jcalendar-set-year"); - cell.innerText = y[i]; - - if (selectedYear == y[i]) { - cell.classList.add("jcalendar-selected"); - } - - if (currentYear == y[i]) { - cell.style.fontWeight = "bold"; - } - - row.appendChild(cell); - } - - calendarBody.innerHTML = ''; - calendarBody.firstChild.firstChild.appendChild(table); - - // Update - updateActions(); - }; - - obj.setLabel = function (value, mixed) { - return jSuites.calendar.getDateString(value, mixed); - }; - - obj.fromFormatted = function (value, format) { - return jSuites.calendar.extractDateFromString(value, format); - }; - - var mouseUpControls = function (e) { - var element = jSuites.findElement(e.target, "jcalendar-container"); - if (element) { - var action = e.target.className; - - // Object id - if (action == "jcalendar-prev") { - obj.prev(); - } else if (action == "jcalendar-next") { - obj.next(); - } else if (action == "jcalendar-month") { - obj.getMonths(); - } else if (action == "jcalendar-year") { - obj.getYears(); - } else if (action == "jcalendar-set-year") { - obj.date[0] = e.target.innerText; - if (obj.options.type == "year-month-picker") { - obj.getMonths(); - } else { - obj.getDays(); - } - } else if (e.target.classList.contains("jcalendar-set-month")) { - var month = parseInt(e.target.getAttribute("data-value")); - if (obj.options.type == "year-month-picker") { - obj.update(e.target, month); - } else { - obj.date[1] = month; - obj.getDays(); - } - } else if ( - action == "jcalendar-confirm" || - action == "jcalendar-update" || - action == "jcalendar-close" - ) { - obj.close(); - } else if (action == "jcalendar-backdrop") { - obj.close(false, false); - } else if (action == "jcalendar-reset") { - obj.reset(); - } else if ( - e.target.classList.contains("jcalendar-set-day") && - e.target.innerText - ) { - obj.update(e.target); - } - } else { - obj.close(); - } - }; - - var keyUpControls = function (e) { - if (e.target.value && e.target.value.length > 3) { - var test = jSuites.calendar.extractDateFromString( - e.target.value, - obj.options.format - ); - if (test) { - obj.setValue(test); - } - } - }; - - // Update actions button - var updateActions = function () { - var currentDay = calendar.querySelector(".jcalendar-selected"); - - if (currentDay && currentDay.classList.contains("jcalendar-disabled")) { - calendarControlsUpdateButton.setAttribute("disabled", "disabled"); - calendarSelectHour.setAttribute("disabled", "disabled"); - calendarSelectMin.setAttribute("disabled", "disabled"); - } else { - calendarControlsUpdateButton.removeAttribute("disabled"); - calendarSelectHour.removeAttribute("disabled"); - calendarSelectMin.removeAttribute("disabled"); - } - - // Event - if (typeof obj.options.onupdate == "function") { - obj.options.onupdate(el, obj.getValue()); - } - }; - - var calendar = null; - var calendarReset = null; - var calendarConfirm = null; - var calendarContainer = null; - var calendarContent = null; - var calendarLabelYear = null; - var calendarLabelMonth = null; - var calendarTable = null; - var calendarBody = null; - - var calendarControls = null; - var calendarControlsTime = null; - var calendarControlsUpdate = null; - var calendarControlsUpdateButton = null; - var calendarSelectHour = null; - var calendarSelectMin = null; - - var init = function () { - // Get value from initial element if that is an input - if (el.tagName == "INPUT" && el.value) { - options.value = el.value; - } - - // Calendar DOM elements - calendarReset = document.createElement("div"); - calendarReset.className = "jcalendar-reset"; - - calendarConfirm = document.createElement("div"); - calendarConfirm.className = "jcalendar-confirm"; - - calendarControls = document.createElement("div"); - calendarControls.className = "jcalendar-controls"; - calendarControls.style.borderBottom = "1px solid #ddd"; - calendarControls.appendChild(calendarReset); - calendarControls.appendChild(calendarConfirm); - - calendarContainer = document.createElement("div"); - calendarContainer.className = "jcalendar-container"; - - calendarContent = document.createElement("div"); - calendarContent.className = "jcalendar-content"; - calendarContainer.appendChild(calendarContent); - - // Main element - if (el.tagName == "DIV") { - calendar = el; - calendar.classList.add("jcalendar-inline"); - } else { - // Add controls to the screen - calendarContent.appendChild(calendarControls); - - calendar = document.createElement("div"); - calendar.className = "jcalendar"; - } - calendar.classList.add("jcalendar-container"); - calendar.appendChild(calendarContainer); - - // Table container - var calendarTableContainer = document.createElement("div"); - calendarTableContainer.className = "jcalendar-table"; - calendarContent.appendChild(calendarTableContainer); - - // Previous button - var calendarHeaderPrev = document.createElement("td"); - calendarHeaderPrev.setAttribute("colspan", "2"); - calendarHeaderPrev.className = "jcalendar-prev"; - - // Header with year and month - calendarLabelYear = document.createElement("span"); - calendarLabelYear.className = "jcalendar-year"; - calendarLabelMonth = document.createElement("span"); - calendarLabelMonth.className = "jcalendar-month"; - - var calendarHeaderTitle = document.createElement("td"); - calendarHeaderTitle.className = "jcalendar-header"; - calendarHeaderTitle.setAttribute("colspan", "3"); - calendarHeaderTitle.appendChild(calendarLabelMonth); - calendarHeaderTitle.appendChild(calendarLabelYear); - - var calendarHeaderNext = document.createElement("td"); - calendarHeaderNext.setAttribute("colspan", "2"); - calendarHeaderNext.className = "jcalendar-next"; - - var calendarHeader = document.createElement("thead"); - var calendarHeaderRow = document.createElement("tr"); - calendarHeaderRow.appendChild(calendarHeaderPrev); - calendarHeaderRow.appendChild(calendarHeaderTitle); - calendarHeaderRow.appendChild(calendarHeaderNext); - calendarHeader.appendChild(calendarHeaderRow); - - calendarTable = document.createElement("table"); - calendarBody = document.createElement("tbody"); - calendarTable.setAttribute("cellpadding", "0"); - calendarTable.setAttribute("cellspacing", "0"); - calendarTable.appendChild(calendarHeader); - calendarTable.appendChild(calendarBody); - calendarTableContainer.appendChild(calendarTable); - - calendarSelectHour = document.createElement("select"); - calendarSelectHour.className = "jcalendar-select"; - calendarSelectHour.onchange = function () { - obj.date[3] = this.value; - - // Event - if (typeof obj.options.onupdate == "function") { - obj.options.onupdate(el, obj.getValue()); - } - }; - - for (var i = 0; i < 24; i++) { - var element = document.createElement("option"); - element.value = i; - element.innerHTML = jSuites.two(i); - calendarSelectHour.appendChild(element); - } - - calendarSelectMin = document.createElement("select"); - calendarSelectMin.className = "jcalendar-select"; - calendarSelectMin.onchange = function () { - obj.date[4] = this.value; - - // Event - if (typeof obj.options.onupdate == "function") { - obj.options.onupdate(el, obj.getValue()); - } - }; - - for (var i = 0; i < 60; i++) { - var element = document.createElement("option"); - element.value = i; - element.innerHTML = jSuites.two(i); - calendarSelectMin.appendChild(element); - } - - // Footer controls - var calendarControlsFooter = document.createElement("div"); - calendarControlsFooter.className = "jcalendar-controls"; - - calendarControlsTime = document.createElement("div"); - calendarControlsTime.className = "jcalendar-time"; - calendarControlsTime.style.maxWidth = "140px"; - calendarControlsTime.appendChild(calendarSelectHour); - calendarControlsTime.appendChild(calendarSelectMin); - - calendarControlsUpdateButton = document.createElement("button"); - calendarControlsUpdateButton.setAttribute("type", "button"); - calendarControlsUpdateButton.className = "jcalendar-update"; - - calendarControlsUpdate = document.createElement("div"); - calendarControlsUpdate.style.flexGrow = "10"; - calendarControlsUpdate.appendChild(calendarControlsUpdateButton); - calendarControlsFooter.appendChild(calendarControlsTime); - - // Only show the update button for input elements - if (el.tagName == "INPUT") { - calendarControlsFooter.appendChild(calendarControlsUpdate); - } - - calendarContent.appendChild(calendarControlsFooter); - - var calendarBackdrop = document.createElement("div"); - calendarBackdrop.className = "jcalendar-backdrop"; - calendar.appendChild(calendarBackdrop); - - // Handle events - el.addEventListener("keyup", keyUpControls); - - // Add global events - calendar.addEventListener("swipeleft", function (e) { - jSuites.animation.slideLeft(calendarTable, 0, function () { - obj.next(); - jSuites.animation.slideRight(calendarTable, 1); - }); - e.preventDefault(); - e.stopPropagation(); - }); - - calendar.addEventListener("swiperight", function (e) { - jSuites.animation.slideRight(calendarTable, 0, function () { - obj.prev(); - jSuites.animation.slideLeft(calendarTable, 1); - }); - e.preventDefault(); - e.stopPropagation(); - }); - - el.onmouseup = function () { - obj.open(); - }; - - if ("ontouchend" in document.documentElement === true) { - calendar.addEventListener("touchend", mouseUpControls); - } else { - calendar.addEventListener("mouseup", mouseUpControls); - } - - // Global controls - if (!jSuites.calendar.hasEvents) { - // Execute only one time - jSuites.calendar.hasEvents = true; - // Enter and Esc - document.addEventListener("keydown", jSuites.calendar.keydown); - } - - // Set configuration - obj.setOptions(options); - - // Append element to the DOM - if (el.tagName == "INPUT") { - el.parentNode.insertBefore(calendar, el.nextSibling); - // Add properties - el.setAttribute("autocomplete", "off"); - // Element - el.classList.add("jcalendar-input"); - // Value - el.value = obj.setLabel(obj.getValue(), obj.options); - } else { - // Get days - obj.getDays(); - // Hour - if (obj.options.time) { - calendarSelectHour.value = obj.date[3]; - calendarSelectMin.value = obj.date[4]; - } - } - - // Default opened - if (obj.options.opened == true) { - obj.open(); - } - - // Change method - el.change = obj.setValue; - - // Global generic value handler - el.val = function (val) { - if (val === undefined) { - return obj.getValue(); - } else { - obj.setValue(val); - } - }; - - // Keep object available from the node - el.calendar = calendar.calendar = obj; - }; - - init(); - - return obj; - }; - - jSuites.calendar.keydown = function (e) { - var calendar = null; - if ((calendar = jSuites.calendar.current)) { - if (e.which == 13) { - // ENTER - calendar.close(false, true); - } else if (e.which == 27) { - // ESC - calendar.close(false, false); - } - } - }; - - jSuites.calendar.prettify = function (d, texts) { - if (!texts) { - var texts = { - justNow: "Just now", - xMinutesAgo: "{0}m ago", - xHoursAgo: "{0}h ago", - xDaysAgo: "{0}d ago", - xWeeksAgo: "{0}w ago", - xMonthsAgo: "{0} mon ago", - xYearsAgo: "{0}y ago", - }; - } - - var d1 = new Date(); - var d2 = new Date(d); - var total = parseInt((d1 - d2) / 1000 / 60); - - String.prototype.format = function (o) { - return this.replace("{0}", o); - }; - - if (total == 0) { - var text = texts.justNow; - } else if (total < 90) { - var text = texts.xMinutesAgo.format(total); - } else if (total < 1440) { - // One day - var text = texts.xHoursAgo.format(Math.round(total / 60)); - } else if (total < 20160) { - // 14 days - var text = texts.xDaysAgo.format(Math.round(total / 1440)); - } else if (total < 43200) { - // 30 days - var text = texts.xWeeksAgo.format(Math.round(total / 10080)); - } else if (total < 1036800) { - // 24 months - var text = texts.xMonthsAgo.format(Math.round(total / 43200)); - } else { - // 24 months+ - var text = texts.xYearsAgo.format(Math.round(total / 525600)); - } - - return text; - }; - - jSuites.calendar.prettifyAll = function () { - var elements = document.querySelectorAll(".prettydate"); - for (var i = 0; i < elements.length; i++) { - if (elements[i].getAttribute("data-date")) { - elements[i].innerHTML = jSuites.calendar.prettify( - elements[i].getAttribute("data-date") - ); - } else { - if (elements[i].innerHTML) { - elements[i].setAttribute("title", elements[i].innerHTML); - elements[i].setAttribute("data-date", elements[i].innerHTML); - elements[i].innerHTML = jSuites.calendar.prettify( - elements[i].innerHTML - ); - } - } - } - }; - - jSuites.calendar.now = function (date, dateOnly) { - if (Array.isArray(date)) { - var y = date[0]; - var m = date[1]; - var d = date[2]; - var h = date[3]; - var i = date[4]; - var s = date[5]; - } else { - if (!date) { - var date = new Date(); - } - var y = date.getFullYear(); - var m = date.getMonth() + 1; - var d = date.getDate(); - var h = date.getHours(); - var i = date.getMinutes(); - var s = date.getSeconds(); - } - - if (dateOnly == true) { - return jSuites.two(y) + "-" + jSuites.two(m) + "-" + jSuites.two(d); - } else { - return ( - jSuites.two(y) + - "-" + - jSuites.two(m) + - "-" + - jSuites.two(d) + - " " + - jSuites.two(h) + - ":" + - jSuites.two(i) + - ":" + - jSuites.two(s) - ); - } - }; - - jSuites.calendar.toArray = function (value) { - var date = value.split(value.indexOf("T") !== -1 ? "T" : " "); - var time = date[1]; - var date = date[0].split("-"); - var y = parseInt(date[0]); - var m = parseInt(date[1]); - var d = parseInt(date[2]); - - if (time) { - var time = time.split(":"); - var h = parseInt(time[0]); - var i = parseInt(time[1]); - } else { - var h = 0; - var i = 0; - } - return [y, m, d, h, i, 0]; - }; - - // Helper to extract date from a string - jSuites.calendar.extractDateFromString = function (date, format) { - if (date > 0 && Number(date) == date) { - var d = new Date(Math.round((date - 25569) * 86400 * 1000)); - return ( - d.getFullYear() + - "-" + - jSuites.two(d.getMonth()) + - "-" + - jSuites.two(d.getDate()) + - " 00:00:00" - ); - } - - var o = jSuites.mask(date, { mask: format }, true); - if (o.date[0] && o.date[1]) { - if (!o.date[2]) { - o.date[2] = 1; - } - - return ( - o.date[0] + - "-" + - jSuites.two(o.date[1]) + - "-" + - jSuites.two(o.date[2]) + - " " + - jSuites.two(o.date[3]) + - ":" + - jSuites.two(o.date[4]) + - ":" + - jSuites.two(o.date[5]) - ); - } - return ""; - }; - - var excelInitialTime = Date.UTC(1900, 0, 0); - var excelLeapYearBug = Date.UTC(1900, 1, 29); - var millisecondsPerDay = 86400000; - - /** - * Date to number - */ - jSuites.calendar.dateToNum = function (jsDate) { - if (typeof jsDate === "string") { - jsDate = new Date(jsDate + " GMT+0"); - } - var jsDateInMilliseconds = jsDate.getTime(); - - if (jsDateInMilliseconds >= excelLeapYearBug) { - jsDateInMilliseconds += millisecondsPerDay; - } - - jsDateInMilliseconds -= excelInitialTime; - - return jsDateInMilliseconds / millisecondsPerDay; - }; - - /** - * Number to date - */ - // !IMPORTANT! - // Excel incorrectly considers 1900 to be a leap year - jSuites.calendar.numToDate = function (excelSerialNumber) { - var jsDateInMilliseconds = - excelInitialTime + excelSerialNumber * millisecondsPerDay; - - if (jsDateInMilliseconds >= excelLeapYearBug) { - jsDateInMilliseconds -= millisecondsPerDay; - } - - const d = new Date(jsDateInMilliseconds); - - var date = [ - d.getUTCFullYear(), - d.getUTCMonth() + 1, - d.getUTCDate(), - d.getUTCHours(), - d.getUTCMinutes(), - d.getUTCSeconds(), - ]; - - return jSuites.calendar.now(date); - }; - - // Helper to convert date into string - jSuites.calendar.getDateString = function (value, options) { - if (!options) { - var options = {}; - } - - // Labels - if (options && typeof options == "object") { - var format = options.format; - } else { - var format = options; - } - - if (!format) { - format = "YYYY-MM-DD"; - } - - // Convert to number of hours - if (typeof value == "number" && format.indexOf("[h]") >= 0) { - var result = parseFloat(24 * Number(value)); - if (format.indexOf("mm") >= 0) { - var h = ("" + result).split("."); - if (h[1]) { - var d = 60 * parseFloat("0." + h[1]); - d = parseFloat(d.toFixed(2)); - } else { - var d = 0; - } - result = parseInt(h[0]) + ":" + jSuites.two(d); - } - return result; - } - - // Date instance - if (value instanceof Date) { - value = jSuites.calendar.now(value); - } else if (value && jSuites.isNumeric(value)) { - value = jSuites.calendar.numToDate(value); - } - - // Tokens - var tokens = [ - "DAY", - "WD", - "DDDD", - "DDD", - "DD", - "D", - "Q", - "HH24", - "HH12", - "HH", - "H", - "AM/PM", - "MI", - "SS", - "MS", - "YYYY", - "YYY", - "YY", - "Y", - "MONTH", - "MON", - "MMMMM", - "MMMM", - "MMM", - "MM", - "M", - ".", - ]; - - // Expression to extract all tokens from the string - var e = new RegExp(tokens.join("|"), "gi"); - // Extract - var t = format.match(e); - - // Compatibility with excel - for (var i = 0; i < t.length; i++) { - if (t[i].toUpperCase() == "MM") { - // Not a month, correct to minutes - if (t[i - 1] && t[i - 1].toUpperCase().indexOf("H") >= 0) { - t[i] = "mi"; - } else if (t[i - 2] && t[i - 2].toUpperCase().indexOf("H") >= 0) { - t[i] = "mi"; - } else if (t[i + 1] && t[i + 1].toUpperCase().indexOf("S") >= 0) { - t[i] = "mi"; - } else if (t[i + 2] && t[i + 2].toUpperCase().indexOf("S") >= 0) { - t[i] = "mi"; - } - } - } - - // Object - var o = { - tokens: t, - }; - - // Value - if (value) { - var d = "" + value; - var splitStr = d.indexOf("T") !== -1 ? "T" : " "; - d = d.split(splitStr); - - var h = 0; - var m = 0; - var s = 0; - - if (d[1]) { - h = d[1].split(":"); - m = h[1] ? h[1] : 0; - s = h[2] ? h[2] : 0; - h = h[0] ? h[0] : 0; - } - - d = d[0].split("-"); - - if ( - d[0] && - d[1] && - d[2] && - d[0] > 0 && - d[1] > 0 && - d[1] < 13 && - d[2] > 0 && - d[2] < 32 - ) { - // Data - o.data = [d[0], d[1], d[2], h, m, s]; - - // Value - o.value = []; - - // Calendar instance - var calendar = new Date( - o.data[0], - o.data[1] - 1, - o.data[2], - o.data[3], - o.data[4], - o.data[5] - ); - - // Get method - var get = function (i) { - // Token - var t = this.tokens[i]; - // Case token - var s = t.toUpperCase(); - var v = null; - - if (s === "YYYY") { - v = this.data[0]; - } else if (s === "YYY") { - v = this.data[0].substring(1, 4); - } else if (s === "YY") { - v = this.data[0].substring(2, 4); - } else if (s === "Y") { - v = this.data[0].substring(3, 4); - } else if (t === "MON") { - v = jSuites.calendar.months[calendar.getMonth()] - .substr(0, 3) - .toUpperCase(); - } else if (t === "mon") { - v = jSuites.calendar.months[calendar.getMonth()] - .substr(0, 3) - .toLowerCase(); - } else if (t === "MONTH") { - v = jSuites.calendar.months[calendar.getMonth()].toUpperCase(); - } else if (t === "month") { - v = jSuites.calendar.months[calendar.getMonth()].toLowerCase(); - } else if (s === "MMMMM") { - v = jSuites.calendar.months[calendar.getMonth()].substr(0, 1); - } else if (s === "MMMM" || t === "Month") { - v = jSuites.calendar.months[calendar.getMonth()]; - } else if (s === "MMM" || t == "Mon") { - v = jSuites.calendar.months[calendar.getMonth()].substr(0, 3); - } else if (s === "MM") { - v = jSuites.two(this.data[1]); - } else if (s === "M") { - v = calendar.getMonth() + 1; - } else if (t === "DAY") { - v = jSuites.calendar.weekdays[calendar.getDay()].toUpperCase(); - } else if (t === "day") { - v = jSuites.calendar.weekdays[calendar.getDay()].toLowerCase(); - } else if (s === "DDDD" || t == "Day") { - v = jSuites.calendar.weekdays[calendar.getDay()]; - } else if (s === "DDD") { - v = jSuites.calendar.weekdays[calendar.getDay()].substr(0, 3); - } else if (s === "DD") { - v = jSuites.two(this.data[2]); - } else if (s === "D") { - v = this.data[2]; - } else if (s === "Q") { - v = Math.floor((calendar.getMonth() + 3) / 3); - } else if (s === "HH24" || s === "HH") { - v = jSuites.two(this.data[3]); - } else if (s === "HH12") { - if (this.data[3] > 12) { - v = jSuites.two(this.data[3] - 12); - } else { - v = jSuites.two(this.data[3]); - } - } else if (s === "H") { - v = this.data[3]; - } else if (s === "MI") { - v = jSuites.two(this.data[4]); - } else if (s === "SS") { - v = jSuites.two(this.data[5]); - } else if (s === "MS") { - v = calendar.getMilliseconds(); - } else if (s === "AM/PM") { - if (this.data[3] >= 12) { - v = "PM"; - } else { - v = "AM"; - } - } else if (s === "WD") { - v = jSuites.calendar.weekdays[calendar.getDay()]; - } - - if (v === null) { - this.value[i] = this.tokens[i]; - } else { - this.value[i] = v; - } - }; - - for (var i = 0; i < o.tokens.length; i++) { - get.call(o, i); - } - // Put pieces together - value = o.value.join(""); - } else { - value = ""; - } - } - - return value; - }; - - // Jsuites calendar labels - jSuites.calendar.weekdays = [ - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", - ]; - jSuites.calendar.months = [ - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", - ]; - jSuites.calendar.weekdaysShort = [ - "Sun", - "Mon", - "Tue", - "Wed", - "Thu", - "Fri", - "Sat", - ]; - jSuites.calendar.monthsShort = [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ]; - - jSuites.color = function (el, options) { - // Already created, update options - if (el.color) { - return el.color.setOptions(options, true); - } - - // New instance - var obj = { type: "color" }; - obj.options = {}; - - var container = null; - var backdrop = null; - var content = null; - var resetButton = null; - var closeButton = null; - var tabs = null; - var jsuitesTabs = null; - - /** - * Update options - */ - obj.setOptions = function (options, reset) { - /** - * @typedef {Object} defaults - * @property {(string|Array)} value - Initial value of the compontent - * @property {string} placeholder - The default instruction text on the element - * @property {requestCallback} onchange - Method to be execute after any changes on the element - * @property {requestCallback} onclose - Method to be execute when the element is closed - * @property {string} doneLabel - Label for button done - * @property {string} resetLabel - Label for button reset - * @property {string} resetValue - Value for button reset - * @property {Bool} showResetButton - Active or note for button reset - default false - */ - var defaults = { - placeholder: "", - value: null, - onopen: null, - onclose: null, - onchange: null, - closeOnChange: true, - palette: null, - position: null, - doneLabel: "Done", - resetLabel: "Reset", - fullscreen: false, - opened: false, - }; - - if (!options) { - options = {}; - } - - if (options && !options.palette) { - // Default pallete - options.palette = jSuites.palette(); - } - - // Loop through our object - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - if (typeof obj.options[property] == "undefined" || reset === true) { - obj.options[property] = defaults[property]; - } - } - } - - // Update the text of the controls, if they have already been created - if (resetButton) { - resetButton.innerHTML = obj.options.resetLabel; - } - if (closeButton) { - closeButton.innerHTML = obj.options.doneLabel; - } - - // Update the pallete - if (obj.options.palette && jsuitesTabs) { - jsuitesTabs.updateContent(0, table()); - } - - // Value - if (typeof obj.options.value === "string") { - el.value = obj.options.value; - if (el.tagName === "INPUT") { - el.style.color = el.value; - el.style.backgroundColor = el.value; - } - } - - // Placeholder - if (obj.options.placeholder) { - el.setAttribute("placeholder", obj.options.placeholder); - } else { - if (el.getAttribute("placeholder")) { - el.removeAttribute("placeholder"); - } - } - - return obj; - }; - - obj.select = function (color) { - // Remove current selected mark - var selected = container.querySelector(".jcolor-selected"); - if (selected) { - selected.classList.remove("jcolor-selected"); - } - - // Mark cell as selected - if (obj.values[color]) { - obj.values[color].classList.add("jcolor-selected"); - } - - obj.options.value = color; - }; - - /** - * Open color pallete - */ - obj.open = function () { - if (!container.classList.contains("jcolor-focus")) { - // Start tracking - jSuites.tracking(obj, true); - - // Show color picker - container.classList.add("jcolor-focus"); - - // Select current color - if (obj.options.value) { - obj.select(obj.options.value); - } - - // Reset margin - content.style.marginTop = ""; - content.style.marginLeft = ""; - - var rectContent = content.getBoundingClientRect(); - var availableWidth = jSuites.getWindowWidth(); - var availableHeight = jSuites.getWindowHeight(); - - if (availableWidth < 800 || obj.options.fullscreen == true) { - content.classList.add("jcolor-fullscreen"); - jSuites.animation.slideBottom(content, 1); - backdrop.style.display = "block"; - } else { - if (content.classList.contains("jcolor-fullscreen")) { - content.classList.remove("jcolor-fullscreen"); - backdrop.style.display = ""; - } - - if (obj.options.position) { - content.style.position = "fixed"; - } else { - content.style.position = ""; - } - - if (rectContent.left + rectContent.width > availableWidth) { - content.style.marginLeft = - -1 * - (rectContent.left + rectContent.width - (availableWidth - 20)) + - "px"; - } - if (rectContent.top + rectContent.height > availableHeight) { - content.style.marginTop = - -1 * - (rectContent.top + - rectContent.height - - (availableHeight - 20)) + - "px"; - } - } - - if (typeof obj.options.onopen == "function") { - obj.options.onopen(el); - } - - jsuitesTabs.setBorder(jsuitesTabs.getActive()); - - // Update sliders - if (obj.options.value) { - var rgb = HexToRgb(obj.options.value); - - rgbInputs.forEach(function (rgbInput, index) { - rgbInput.value = rgb[index]; - rgbInput.dispatchEvent(new Event("input")); - }); - } - } - }; - - /** - * Close color pallete - */ - obj.close = function (ignoreEvents) { - if (container.classList.contains("jcolor-focus")) { - // Remove focus - container.classList.remove("jcolor-focus"); - // Make sure backdrop is hidden - backdrop.style.display = ""; - // Call related events - if (!ignoreEvents && typeof obj.options.onclose == "function") { - obj.options.onclose(el); - } - // Stop the object - jSuites.tracking(obj, false); - } - - return obj.options.value; - }; - - /** - * Set value - */ - obj.setValue = function (color) { - if (!color) { - color = ""; - } - - if (color != obj.options.value) { - obj.options.value = color; - slidersResult = color; - - // Remove current selecded mark - obj.select(color); - - // Onchange - if (typeof obj.options.onchange == "function") { - obj.options.onchange(el, color); - } - - // Changes - if (el.value != obj.options.value) { - // Set input value - el.value = obj.options.value; - if (el.tagName === "INPUT") { - el.style.color = el.value; - el.style.backgroundColor = el.value; - } - - // Element onchange native - if (typeof el.oninput == "function") { - el.oninput({ - type: "input", - target: el, - value: el.value, - }); - } - } - - if (obj.options.closeOnChange == true) { - obj.close(); - } - } - }; - - /** - * Get value - */ - obj.getValue = function () { - return obj.options.value; - }; - - var backdropClickControl = false; - - // Converts a number in decimal to hexadecimal - var decToHex = function (num) { - var hex = num.toString(16); - return hex.length === 1 ? "0" + hex : hex; - }; - - // Converts a color in rgb to hexadecimal - var rgbToHex = function (r, g, b) { - return "#" + decToHex(r) + decToHex(g) + decToHex(b); - }; - - // Converts a number in hexadecimal to decimal - var hexToDec = function (hex) { - return parseInt("0x" + hex); - }; - - // Converts a color in hexadecimal to rgb - var HexToRgb = function (hex) { - return [ - hexToDec(hex.substr(1, 2)), - hexToDec(hex.substr(3, 2)), - hexToDec(hex.substr(5, 2)), - ]; - }; - - var table = function () { - // Content of the first tab - var tableContainer = document.createElement("div"); - tableContainer.className = "jcolor-grid"; - - // Cells - obj.values = []; - - // Table pallete - var t = document.createElement("table"); - t.setAttribute("cellpadding", "7"); - t.setAttribute("cellspacing", "0"); - - for (var j = 0; j < obj.options.palette.length; j++) { - var tr = document.createElement("tr"); - for (var i = 0; i < obj.options.palette[j].length; i++) { - var td = document.createElement("td"); - var color = obj.options.palette[j][i]; - if (color.length < 7 && color.substr(0, 1) !== "#") { - color = "#" + color; - } - td.style.backgroundColor = color; - td.setAttribute("data-value", color); - td.innerHTML = ""; - tr.appendChild(td); - - // Selected color - if (obj.options.value == color) { - td.classList.add("jcolor-selected"); - } - - // Possible values - obj.values[color] = td; - } - t.appendChild(tr); - } - - // Append to the table - tableContainer.appendChild(t); - - return tableContainer; - }; - - // Canvas where the image will be rendered - var canvas = document.createElement("canvas"); - canvas.width = 200; - canvas.height = 160; - var context = canvas.getContext("2d"); - - var resizeCanvas = function () { - // Specifications necessary to correctly obtain colors later in certain positions - var m = tabs.firstChild.getBoundingClientRect(); - canvas.width = m.width - 14; - gradient(); - }; - - var gradient = function () { - var g = context.createLinearGradient(0, 0, canvas.width, 0); - // Create color gradient - g.addColorStop(0, "rgb(255,0,0)"); - g.addColorStop(0.15, "rgb(255,0,255)"); - g.addColorStop(0.33, "rgb(0,0,255)"); - g.addColorStop(0.49, "rgb(0,255,255)"); - g.addColorStop(0.67, "rgb(0,255,0)"); - g.addColorStop(0.84, "rgb(255,255,0)"); - g.addColorStop(1, "rgb(255,0,0)"); - context.fillStyle = g; - context.fillRect(0, 0, canvas.width, canvas.height); - g = context.createLinearGradient(0, 0, 0, canvas.height); - g.addColorStop(0, "rgba(255,255,255,1)"); - g.addColorStop(0.5, "rgba(255,255,255,0)"); - g.addColorStop(0.5, "rgba(0,0,0,0)"); - g.addColorStop(1, "rgba(0,0,0,1)"); - context.fillStyle = g; - context.fillRect(0, 0, canvas.width, canvas.height); - }; - - var hsl = function () { - var element = document.createElement("div"); - element.className = "jcolor-hsl"; - - var point = document.createElement("div"); - point.className = "jcolor-point"; - - var div = document.createElement("div"); - div.appendChild(canvas); - div.appendChild(point); - element.appendChild(div); - - // Moves the marquee point to the specified position - var update = function (buttons, x, y) { - if (buttons === 1) { - var rect = element.getBoundingClientRect(); - var left = x - rect.left; - var top = y - rect.top; - if (left < 0) { - left = 0; - } - if (top < 0) { - top = 0; - } - if (left > rect.width) { - left = rect.width; - } - if (top > rect.height) { - top = rect.height; - } - point.style.left = left + "px"; - point.style.top = top + "px"; - var pixel = context.getImageData(left, top, 1, 1).data; - slidersResult = rgbToHex(pixel[0], pixel[1], pixel[2]); - } - }; - - // Applies the point's motion function to the div that contains it - element.addEventListener("mousedown", function (e) { - update(e.buttons, e.clientX, e.clientY); - }); - - element.addEventListener("mousemove", function (e) { - update(e.buttons, e.clientX, e.clientY); - }); - - element.addEventListener("touchmove", function (e) { - update(1, e.changedTouches[0].clientX, e.changedTouches[0].clientY); - }); - - return element; - }; - - var slidersResult = ""; - - var rgbInputs = []; - - var changeInputColors = function () { - if (slidersResult !== "") { - for (var j = 0; j < rgbInputs.length; j++) { - var currentColor = HexToRgb(slidersResult); - - currentColor[j] = 0; - - var newGradient = "linear-gradient(90deg, rgb("; - newGradient += currentColor.join(", "); - newGradient += "), rgb("; - - currentColor[j] = 255; - - newGradient += currentColor.join(", "); - newGradient += "))"; - - rgbInputs[j].style.backgroundImage = newGradient; - } - } - }; - - var sliders = function () { - // Content of the third tab - var slidersElement = document.createElement("div"); - slidersElement.className = "jcolor-sliders"; - - var slidersBody = document.createElement("div"); - - // Creates a range-type input with the specified name - var createSliderInput = function (name) { - var inputContainer = document.createElement("div"); - inputContainer.className = "jcolor-sliders-input-container"; - - var label = document.createElement("label"); - label.innerText = name; - - var subContainer = document.createElement("div"); - subContainer.className = "jcolor-sliders-input-subcontainer"; - - var input = document.createElement("input"); - input.type = "range"; - input.min = 0; - input.max = 255; - input.value = 0; - - inputContainer.appendChild(label); - subContainer.appendChild(input); - - var value = document.createElement("div"); - value.innerText = input.value; - - input.addEventListener("input", function () { - value.innerText = input.value; - }); - - subContainer.appendChild(value); - inputContainer.appendChild(subContainer); - - slidersBody.appendChild(inputContainer); - - return input; - }; - - // Creates red, green and blue inputs - rgbInputs = [ - createSliderInput("Red"), - createSliderInput("Green"), - createSliderInput("Blue"), - ]; - - slidersElement.appendChild(slidersBody); - - // Element that prints the current color - var slidersResultColor = document.createElement("div"); - slidersResultColor.className = "jcolor-sliders-final-color"; - - var resultElement = document.createElement("div"); - resultElement.style.visibility = "hidden"; - resultElement.innerText = "a"; - slidersResultColor.appendChild(resultElement); - - // Update the element that prints the current color - var updateResult = function () { - var resultColor = rgbToHex( - parseInt(rgbInputs[0].value), - parseInt(rgbInputs[1].value), - parseInt(rgbInputs[2].value) - ); - - resultElement.innerText = resultColor; - resultElement.style.color = resultColor; - resultElement.style.removeProperty("visibility"); - - slidersResult = resultColor; - }; - - // Apply the update function to color inputs - rgbInputs.forEach(function (rgbInput) { - rgbInput.addEventListener("input", function () { - updateResult(); - changeInputColors(); - }); - }); - - slidersElement.appendChild(slidersResultColor); - - return slidersElement; - }; - - var init = function () { - // Initial options - obj.setOptions(options); - - // Add a proper input tag when the element is an input - if (el.tagName == "INPUT") { - el.classList.add("jcolor-input"); - el.readOnly = true; - } - - // Table container - container = document.createElement("div"); - container.className = "jcolor"; - - // Table container - backdrop = document.createElement("div"); - backdrop.className = "jcolor-backdrop"; - container.appendChild(backdrop); - - // Content - content = document.createElement("div"); - content.className = "jcolor-content"; - - // Controls - var controls = document.createElement("div"); - controls.className = "jcolor-controls"; - content.appendChild(controls); - - // Reset button - resetButton = document.createElement("div"); - resetButton.className = "jcolor-reset"; - resetButton.innerHTML = obj.options.resetLabel; - controls.appendChild(resetButton); - - // Close button - closeButton = document.createElement("div"); - closeButton.className = "jcolor-close"; - closeButton.innerHTML = obj.options.doneLabel; - controls.appendChild(closeButton); - - // Element that will be used to create the tabs - tabs = document.createElement("div"); - content.appendChild(tabs); - - // Starts the jSuites tabs component - jsuitesTabs = jSuites.tabs(tabs, { - animation: true, - data: [ - { - title: "Grid", - contentElement: table(), - }, - { - title: "Spectrum", - contentElement: hsl(), - }, - { - title: "Sliders", - contentElement: sliders(), - }, - ], - onchange: function (element, instance, index) { - if (index === 1) { - resizeCanvas(); - } else { - var color = slidersResult !== "" ? slidersResult : obj.getValue(); - - if (index === 2 && color) { - var rgb = HexToRgb(color); - - rgbInputs.forEach(function (rgbInput, index) { - rgbInput.value = rgb[index]; - rgbInput.dispatchEvent(new Event("input")); - }); - } - } - }, - palette: "modern", - }); - - container.appendChild(content); - - // Insert picker after the element - if (el.tagName == "INPUT") { - el.parentNode.insertBefore(container, el.nextSibling); - } else { - el.appendChild(container); - } - - container.addEventListener("click", function (e) { - if (e.target.tagName == "TD") { - var value = e.target.getAttribute("data-value"); - if (value) { - obj.setValue(value); - } - } else if (e.target.classList.contains("jcolor-reset")) { - obj.setValue(""); - obj.close(); - } else if (e.target.classList.contains("jcolor-close")) { - if (jsuitesTabs.getActive() > 0) { - obj.setValue(slidersResult); - } - obj.close(); - } else if (e.target.classList.contains("jcolor-backdrop")) { - obj.close(); - } else { - obj.open(); - } - }); - - /** - * If element is focus open the picker - */ - el.addEventListener("mouseup", function (e) { - obj.open(); - }); - - // If the picker is open on the spectrum tab, it changes the canvas size when the window size is changed - window.addEventListener("resize", function () { - if ( - container.classList.contains("jcolor-focus") && - jsuitesTabs.getActive() == 1 - ) { - resizeCanvas(); - } - }); - - // Default opened - if (obj.options.opened == true) { - obj.open(); - } - - // Change - el.change = obj.setValue; - - // Global generic value handler - el.val = function (val) { - if (val === undefined) { - return obj.getValue(); - } else { - obj.setValue(val); - } - }; - - // Keep object available from the node - el.color = obj; - - // Container shortcut - container.color = obj; - }; - - obj.toHex = function (rgb) { - var hex = function (x) { - return ("0" + parseInt(x).toString(16)).slice(-2); - }; - if (/^#[0-9A-F]{6}$/i.test(rgb)) { - return rgb; - } else { - rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); - return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]); - } - }; - - init(); - - return obj; - }; - - jSuites.contextmenu = function (el, options) { - // New instance - var obj = { type: "contextmenu" }; - obj.options = {}; - - // Default configuration - var defaults = { - items: null, - onclick: null, - }; - - // Loop through our object - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - obj.options[property] = defaults[property]; - } - } - - // Class definition - el.classList.add("jcontextmenu"); - - /** - * Open contextmenu - */ - obj.open = function (e, items) { - if (items) { - // Update content - obj.options.items = items; - // Create items - obj.create(items); - } - - // Close current contextmenu - if (jSuites.contextmenu.current) { - jSuites.contextmenu.current.close(); - } - - // Add to the opened components monitor - jSuites.tracking(obj, true); - - // Show context menu - el.classList.add("jcontextmenu-focus"); - - // Current - jSuites.contextmenu.current = obj; - - // Coordinates - if ( - (obj.options.items && obj.options.items.length > 0) || - el.children.length - ) { - if (e.target) { - if (e.changedTouches && e.changedTouches[0]) { - x = e.changedTouches[0].clientX; - y = e.changedTouches[0].clientY; - } else { - var x = e.clientX; - var y = e.clientY; - } - } else { - var x = e.x; - var y = e.y; - } - - var rect = el.getBoundingClientRect(); - - if (window.innerHeight < y + rect.height) { - var h = y - rect.height; - if (h < 0) { - h = 0; - } - el.style.top = h + "px"; - } else { - el.style.top = y + "px"; - } - - if (window.innerWidth < x + rect.width) { - if (x - rect.width > 0) { - el.style.left = x - rect.width + "px"; - } else { - el.style.left = "10px"; - } - } else { - el.style.left = x + "px"; - } - } - }; - - obj.isOpened = function () { - return el.classList.contains("jcontextmenu-focus") ? true : false; - }; - - /** - * Close menu - */ - obj.close = function () { - if (el.classList.contains("jcontextmenu-focus")) { - el.classList.remove("jcontextmenu-focus"); - } - jSuites.tracking(obj, false); - }; - - /** - * Create items based on the declared objectd - * @param {object} items - List of object - */ - obj.create = function (items) { - // Update content - el.innerHTML = ""; - - // Add header contextmenu - var itemHeader = createHeader(); - el.appendChild(itemHeader); - - // Append items - for (var i = 0; i < items.length; i++) { - var itemContainer = createItemElement(items[i]); - el.appendChild(itemContainer); - } - }; - - /** - * createHeader for context menu - * @private - * @returns {HTMLElement} - */ - function createHeader() { - var header = document.createElement("div"); - header.classList.add("header"); - header.addEventListener("click", function (e) { - e.preventDefault(); - e.stopPropagation(); - }); - var title = document.createElement("a"); - title.classList.add("title"); - title.innerHTML = jSuites.translate("Menu"); - - header.appendChild(title); - - var closeButton = document.createElement("a"); - closeButton.classList.add("close"); - closeButton.innerHTML = jSuites.translate("close"); - closeButton.addEventListener("click", function (e) { - obj.close(); - }); - - header.appendChild(closeButton); - - return header; - } - - /** - * Private function for create a new Item element - * @param {type} item - * @returns {jsuitesL#15.jSuites.contextmenu.createItemElement.itemContainer} - */ - function createItemElement(item) { - if (item.type && (item.type == "line" || item.type == "divisor")) { - var itemContainer = document.createElement("hr"); - } else { - var itemContainer = document.createElement("div"); - var itemText = document.createElement("a"); - itemText.innerHTML = item.title; - - if (item.tooltip) { - itemContainer.setAttribute("title", item.tooltip); - } - - if (item.icon) { - itemContainer.setAttribute("data-icon", item.icon); - } - - if (item.id) { - itemContainer.id = item.id; - } - - if (item.disabled) { - itemContainer.className = "jcontextmenu-disabled"; - } else if (item.onclick) { - itemContainer.method = item.onclick; - itemContainer.addEventListener("mousedown", function (e) { - e.preventDefault(); - }); - itemContainer.addEventListener("mouseup", function (e) { - // Execute method - this.method(this, e); - }); - } - itemContainer.appendChild(itemText); - - if (item.submenu) { - var itemIconSubmenu = document.createElement("span"); - itemIconSubmenu.innerHTML = "►"; - itemContainer.appendChild(itemIconSubmenu); - itemContainer.classList.add("jcontexthassubmenu"); - var el_submenu = document.createElement("div"); - // Class definition - el_submenu.classList.add("jcontextmenu"); - // Focusable - el_submenu.setAttribute("tabindex", "900"); - - // Append items - var submenu = item.submenu; - for (var i = 0; i < submenu.length; i++) { - var itemContainerSubMenu = createItemElement(submenu[i]); - el_submenu.appendChild(itemContainerSubMenu); - } - - itemContainer.appendChild(el_submenu); - } else if (item.shortcut) { - var itemShortCut = document.createElement("span"); - itemShortCut.innerHTML = item.shortcut; - itemContainer.appendChild(itemShortCut); - } - } - return itemContainer; - } - - if (typeof obj.options.onclick == "function") { - el.addEventListener("click", function (e) { - obj.options.onclick(obj, e); - }); - } - - // Create items - if (obj.options.items) { - obj.create(obj.options.items); - } - - window.addEventListener("mousewheel", function () { - obj.close(); - }); - - el.contextmenu = obj; - - return obj; - }; - - jSuites.dropdown = function (el, options) { - // Already created, update options - if (el.dropdown) { - return el.dropdown.setOptions(options, true); - } - - // New instance - var obj = { type: "dropdown" }; - obj.options = {}; - - // Success - var success = function (data, val) { - // Set data - if (data && data.length) { - // Sort - if (obj.options.sortResults !== false) { - if (typeof obj.options.sortResults == "function") { - data.sort(obj.options.sortResults); - } else { - data.sort(sortData); - } - } - - obj.setData(data); - } - - // Onload method - if (typeof obj.options.onload == "function") { - obj.options.onload(el, obj, data, val); - } - - // Set value - if (val) { - applyValue(val); - } - - // Component value - if (val === undefined || val === null) { - obj.options.value = ""; - } - el.value = obj.options.value; - - // Open dropdown - if (obj.options.opened == true) { - obj.open(); - } - }; - - // Default sort - var sortData = function (itemA, itemB) { - var testA, testB; - if (typeof itemA == "string") { - testA = itemA; - } else { - if (itemA.text) { - testA = itemA.text; - } else if (itemA.name) { - testA = itemA.name; - } - } - - if (typeof itemB == "string") { - testB = itemB; - } else { - if (itemB.text) { - testB = itemB.text; - } else if (itemB.name) { - testB = itemB.name; - } - } - - if (typeof testA == "string" || typeof testB == "string") { - if (typeof testA != "string") { - testA = "" + testA; - } - if (typeof testB != "string") { - testB = "" + testB; - } - return testA.localeCompare(testB); - } else { - return testA - testB; - } - }; - - /** - * Reset the options for the dropdown - */ - var resetValue = function () { - // Reset value container - obj.value = {}; - // Remove selected - for (var i = 0; i < obj.items.length; i++) { - if (obj.items[i].selected == true) { - if (obj.items[i].element) { - obj.items[i].element.classList.remove("jdropdown-selected"); - } - obj.items[i].selected = null; - } - } - // Reset options - obj.options.value = ""; - }; - - /** - * Apply values to the dropdown - */ - var applyValue = function (values) { - // Reset the current values - resetValue(); - - // Read values - if (values !== null) { - if (!values) { - if (typeof obj.value[""] !== "undefined") { - obj.value[""] = ""; - } - } else { - if (!Array.isArray(values)) { - values = ("" + values).split(";"); - } - for (var i = 0; i < values.length; i++) { - obj.value[values[i]] = ""; - } - } - } - - // Update the DOM - for (var i = 0; i < obj.items.length; i++) { - if (typeof obj.value[Value(i)] !== "undefined") { - if (obj.items[i].element) { - obj.items[i].element.classList.add("jdropdown-selected"); - } - obj.items[i].selected = true; - - // Keep label - obj.value[Value(i)] = Text(i); - } - } - - // Global value - obj.options.value = Object.keys(obj.value).join(";"); - - // Update labels - obj.header.value = obj.getText(); - }; - - // Get the value of one item - var Value = function (k, v) { - // Legacy purposes - if (!obj.options.format) { - var property = "value"; - } else { - var property = "id"; - } - - if (obj.items[k]) { - if (v !== undefined) { - return (obj.items[k].data[property] = v); - } else { - return obj.items[k].data[property]; - } - } - - return ""; - }; - - // Get the label of one item - var Text = function (k, v) { - // Legacy purposes - if (!obj.options.format) { - var property = "text"; - } else { - var property = "name"; - } - - if (obj.items[k]) { - if (v !== undefined) { - return (obj.items[k].data[property] = v); - } else { - return obj.items[k].data[property]; - } - } - - return ""; - }; - - var getValue = function () { - return Object.keys(obj.value); - }; - - var getText = function () { - var data = []; - var k = Object.keys(obj.value); - for (var i = 0; i < k.length; i++) { - data.push(obj.value[k[i]]); - } - return data; - }; - - obj.setOptions = function (options, reset) { - if (!options) { - options = {}; - } - - // Default configuration - var defaults = { - url: null, - data: [], - format: 0, - multiple: false, - autocomplete: false, - remoteSearch: false, - lazyLoading: false, - type: null, - width: null, - maxWidth: null, - opened: false, - value: null, - placeholder: "", - newOptions: false, - position: false, - onchange: null, - onload: null, - onopen: null, - onclose: null, - onfocus: null, - onblur: null, - oninsert: null, - onbeforeinsert: null, - sortResults: false, - autofocus: false, - }; - - // Loop through our object - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - if (typeof obj.options[property] == "undefined" || reset === true) { - obj.options[property] = defaults[property]; - } - } - } - - // Force autocomplete search - if ( - obj.options.remoteSearch == true || - obj.options.type === "searchbar" - ) { - obj.options.autocomplete = true; - } - - // New options - if (obj.options.newOptions == true) { - obj.header.classList.add("jdropdown-add"); - } else { - obj.header.classList.remove("jdropdown-add"); - } - - // Autocomplete - if (obj.options.autocomplete == true) { - obj.header.removeAttribute("readonly"); - } else { - obj.header.setAttribute("readonly", "readonly"); - } - - // Place holder - if (obj.options.placeholder) { - obj.header.setAttribute("placeholder", obj.options.placeholder); - } else { - obj.header.removeAttribute("placeholder"); - } - - // Remove specific dropdown typing to add again - el.classList.remove("jdropdown-searchbar"); - el.classList.remove("jdropdown-picker"); - el.classList.remove("jdropdown-list"); - - if (obj.options.type == "searchbar") { - el.classList.add("jdropdown-searchbar"); - } else if (obj.options.type == "list") { - el.classList.add("jdropdown-list"); - } else if (obj.options.type == "picker") { - el.classList.add("jdropdown-picker"); - } else { - if (jSuites.getWindowWidth() < 800) { - if (obj.options.autocomplete) { - el.classList.add("jdropdown-searchbar"); - obj.options.type = "searchbar"; - } else { - el.classList.add("jdropdown-picker"); - obj.options.type = "picker"; - } - } else { - if (obj.options.width) { - el.style.width = obj.options.width; - el.style.minWidth = obj.options.width; - } else { - el.style.removeProperty("width"); - el.style.removeProperty("min-width"); - } - - el.classList.add("jdropdown-default"); - obj.options.type = "default"; - } - } - - // Close button - if (obj.options.type == "searchbar") { - containerHeader.appendChild(closeButton); - } else { - container.insertBefore(closeButton, container.firstChild); - } - - // Load the content - if (obj.options.url && !options.data) { - jSuites.ajax({ - url: obj.options.url, - method: "GET", - dataType: "json", - success: function (data) { - if (data) { - success(data, obj.options.value); - } - }, - }); - } else { - success(obj.options.data, obj.options.value); - } - - // Return the instance - return obj; - }; - - // Helpers - var containerHeader = null; - var container = null; - var content = null; - var closeButton = null; - var resetButton = null; - var backdrop = null; - - var keyTimer = null; - - /** - * Init dropdown - */ - var init = function () { - // Do not accept null - if (!options) { - options = {}; - } - - // If the element is a SELECT tag, create a configuration object - if (el.tagName == "SELECT") { - var ret = jSuites.dropdown.extractFromDom(el, options); - el = ret.el; - options = ret.options; - } - - // Place holder - if (!options.placeholder && el.getAttribute("placeholder")) { - options.placeholder = el.getAttribute("placeholder"); - } - - // Value container - obj.value = {}; - // Containers - obj.items = []; - obj.groups = []; - // Search options - obj.search = ""; - obj.results = null; - - // Create dropdown - el.classList.add("jdropdown"); - - // Header container - containerHeader = document.createElement("div"); - containerHeader.className = "jdropdown-container-header"; - - // Header - obj.header = document.createElement("input"); - obj.header.className = "jdropdown-header"; - obj.header.type = "text"; - obj.header.setAttribute("autocomplete", "off"); - obj.header.onfocus = function () { - if (typeof obj.options.onfocus == "function") { - obj.options.onfocus(el); - } - }; - - obj.header.onblur = function () { - if (typeof obj.options.onblur == "function") { - obj.options.onblur(el); - } - }; - - obj.header.onkeyup = function (e) { - if (obj.options.autocomplete == true && !keyTimer) { - if (obj.search != obj.header.value.trim()) { - keyTimer = setTimeout(function () { - obj.find(obj.header.value.trim()); - keyTimer = null; - }, 400); - } - - if (!el.classList.contains("jdropdown-focus")) { - obj.open(); - } - } else { - if (!obj.options.autocomplete) { - obj.next(e.key); - } - } - }; - - // Global controls - if (!jSuites.dropdown.hasEvents) { - // Execute only one time - jSuites.dropdown.hasEvents = true; - // Enter and Esc - document.addEventListener("keydown", jSuites.dropdown.keydown); - } - - // Container - container = document.createElement("div"); - container.className = "jdropdown-container"; - - // Dropdown content - content = document.createElement("div"); - content.className = "jdropdown-content"; - - // Close button - closeButton = document.createElement("div"); - closeButton.className = "jdropdown-close"; - closeButton.innerHTML = "Done"; - - // Reset button - resetButton = document.createElement("div"); - resetButton.className = "jdropdown-reset"; - resetButton.innerHTML = "x"; - resetButton.onclick = function () { - obj.reset(); - obj.close(); - }; - - // Create backdrop - backdrop = document.createElement("div"); - backdrop.className = "jdropdown-backdrop"; - - // Append elements - containerHeader.appendChild(obj.header); - - container.appendChild(content); - el.appendChild(containerHeader); - el.appendChild(container); - el.appendChild(backdrop); - - // Set the otiptions - obj.setOptions(options); - - if ("ontouchsend" in document.documentElement === true) { - el.addEventListener("touchsend", jSuites.dropdown.mouseup); - } else { - el.addEventListener("mouseup", jSuites.dropdown.mouseup); - } - - // Lazyloading - if (obj.options.lazyLoading == true) { - jSuites.lazyLoading(content, { - loadUp: obj.loadUp, - loadDown: obj.loadDown, - }); - } - - content.onwheel = function (e) { - e.stopPropagation(); - }; - - // Change method - el.change = obj.setValue; - - // Global generic value handler - el.val = function (val) { - if (val === undefined) { - return obj.getValue(obj.options.multiple ? true : false); - } else { - obj.setValue(val); - } - }; - - // Keep object available from the node - el.dropdown = obj; - }; - - /** - * Get the current remote source of data URL - */ - obj.getUrl = function () { - return obj.options.url; - }; - - /** - * Set the new data from a remote source - * @param {string} url - url from the remote source - * @param {function} callback - callback when the data is loaded - */ - obj.setUrl = function (url, callback) { - obj.options.url = url; - - jSuites.ajax({ - url: obj.options.url, - method: "GET", - dataType: "json", - success: function (data) { - obj.setData(data); - // Callback - if (typeof callback == "function") { - callback(obj); - } - }, - }); - }; - - /** - * Set ID for one item - */ - obj.setId = function (item, v) { - // Legacy purposes - if (!obj.options.format) { - var property = "value"; - } else { - var property = "id"; - } - - if (typeof item == "object") { - item[property] = v; - } else { - obj.items[item].data[property] = v; - } - }; - - /** - * Add a new item - * @param {string} title - title of the new item - * @param {string} id - value/id of the new item - */ - obj.add = function (title, id) { - if (!title) { - var current = obj.options.autocomplete == true ? obj.header.value : ""; - var title = prompt(jSuites.translate("Add A New Option"), current); - if (!title) { - return false; - } - } - - // Id - if (!id) { - id = jSuites.guid(); - } - - // Create new item - if (!obj.options.format) { - var item = { - value: id, - text: title, - }; - } else { - var item = { - id: id, - name: title, - }; - } - - // Callback - if (typeof obj.options.onbeforeinsert == "function") { - var ret = obj.options.onbeforeinsert(obj, item); - if (ret === false) { - return false; - } else if (ret) { - item = ret; - } - } - - // Add item to the main list - obj.options.data.push(item); - - // Create DOM - var newItem = obj.createItem(item); - - // Append DOM to the list - content.appendChild(newItem.element); - - // Callback - if (typeof obj.options.oninsert == "function") { - obj.options.oninsert(obj, item, newItem); - } - - // Show content - if (content.style.display == "none") { - content.style.display = ""; - } - - // Search? - if (obj.results) { - obj.results.push(newItem); - } - - return item; - }; - - /** - * Create a new item - */ - obj.createItem = function (data, group, groupName) { - // Keep the correct source of data - if (!obj.options.format) { - if (!data.value && data.id !== undefined) { - data.value = data.id; - //delete data.id; - } - if (!data.text && data.name !== undefined) { - data.text = data.name; - //delete data.name; - } - } else { - if (!data.id && data.value !== undefined) { - data.id = data.value; - //delete data.value; - } - if (!data.name && data.text !== undefined) { - data.name = data.text; - //delete data.text; - } - } - - // Create item - var item = {}; - item.element = document.createElement("div"); - item.element.className = "jdropdown-item"; - item.element.indexValue = obj.items.length; - item.data = data; - - // Groupd DOM - if (group) { - item.group = group; - } - - // Id - if (data.id) { - item.element.setAttribute("id", data.id); - } - - // Disabled - if (data.disabled == true) { - item.element.setAttribute("data-disabled", true); - } - - // Tooltip - if (data.tooltip) { - item.element.setAttribute("title", data.tooltip); - } - - // Image - if (data.image) { - var image = document.createElement("img"); - image.className = "jdropdown-image"; - image.src = data.image; - if (!data.title) { - image.classList.add("jdropdown-image-small"); - } - item.element.appendChild(image); - } else if (data.icon) { - var icon = document.createElement("span"); - icon.className = "jdropdown-icon material-icons"; - icon.innerText = data.icon; - if (!data.title) { - icon.classList.add("jdropdown-icon-small"); - } - if (data.color) { - icon.style.color = data.color; - } - item.element.appendChild(icon); - } else if (data.color) { - var color = document.createElement("div"); - color.className = "jdropdown-color"; - color.style.backgroundColor = data.color; - item.element.appendChild(color); - } - - // Set content - if (!obj.options.format) { - var text = data.text; - } else { - var text = data.name; - } - - var node = document.createElement("div"); - node.className = "jdropdown-description"; - node.innerHTML = text || " "; - - // Title - if (data.title) { - var title = document.createElement("div"); - title.className = "jdropdown-title"; - title.innerText = data.title; - node.appendChild(title); - } - - // Set content - if (!obj.options.format) { - var val = data.value; - } else { - var val = data.id; - } - - // Value - if (obj.value[val]) { - item.element.classList.add("jdropdown-selected"); - item.selected = true; - } - - // Keep DOM accessible - obj.items.push(item); - - // Add node to item - item.element.appendChild(node); - - return item; - }; - - obj.appendData = function (data) { - // Create elements - if (data.length) { - // Helpers - var items = []; - var groups = []; - - // Prepare data - for (var i = 0; i < data.length; i++) { - // Process groups - if (data[i].group) { - if (!groups[data[i].group]) { - groups[data[i].group] = []; - } - groups[data[i].group].push(i); - } else { - items.push(i); - } - } - - // Number of items counter - var counter = 0; - - // Groups - var groupNames = Object.keys(groups); - - // Append groups in case exists - if (groupNames.length > 0) { - for (var i = 0; i < groupNames.length; i++) { - // Group container - var group = document.createElement("div"); - group.className = "jdropdown-group"; - // Group name - var groupName = document.createElement("div"); - groupName.className = "jdropdown-group-name"; - groupName.innerHTML = groupNames[i]; - // Group arrow - var groupArrow = document.createElement("i"); - groupArrow.className = - "jdropdown-group-arrow jdropdown-group-arrow-down"; - groupName.appendChild(groupArrow); - // Group items - var groupContent = document.createElement("div"); - groupContent.className = "jdropdown-group-items"; - for (var j = 0; j < groups[groupNames[i]].length; j++) { - var item = obj.createItem( - data[groups[groupNames[i]][j]], - group, - groupNames[i] - ); - - if (obj.options.lazyLoading == false || counter < 200) { - groupContent.appendChild(item.element); - counter++; - } - } - // Group itens - group.appendChild(groupName); - group.appendChild(groupContent); - // Keep group DOM - obj.groups.push(group); - // Only add to the screen if children on the group - if (groupContent.children.length > 0) { - // Add DOM to the content - content.appendChild(group); - } - } - } - - if (items.length) { - for (var i = 0; i < items.length; i++) { - var item = obj.createItem(data[items[i]]); - if (obj.options.lazyLoading == false || counter < 200) { - content.appendChild(item.element); - counter++; - } - } - } - } - }; - - obj.setData = function (data) { - // Reset current value - resetValue(); - - // Make sure the content container is blank - content.innerHTML = ""; - - // Reset - obj.header.value = ""; - - // Reset items and values - obj.items = []; - - // Prepare data - if (data && data.length) { - for (var i = 0; i < data.length; i++) { - // Compatibility - if (typeof data[i] != "object") { - // Correct format - if (!obj.options.format) { - data[i] = { - value: data[i], - text: data[i], - }; - } else { - data[i] = { - id: data[i], - name: data[i], - }; - } - } - } - - // Append data - obj.appendData(data); - - // Update data - obj.options.data = data; - } else { - // Update data - obj.options.data = []; - } - - obj.close(); - }; - - obj.getData = function () { - return obj.options.data; - }; - - /** - * Get position of the item - */ - obj.getPosition = function (val) { - for (var i = 0; i < obj.items.length; i++) { - if (Value(i) == val) { - return i; - } - } - return false; - }; - - /** - * Get dropdown current text - */ - obj.getText = function (asArray) { - // Get value - var v = getText(); - // Return value - if (asArray) { - return v; - } else { - return v.join("; "); - } - }; - - /** - * Get dropdown current value - */ - obj.getValue = function (asArray) { - // Get value - var v = getValue(); - // Return value - if (asArray) { - return v; - } else { - return v.join(";"); - } - }; - - /** - * Change event - */ - var change = function (oldValue) { - // Lemonade JS - if (el.value != obj.options.value) { - el.value = obj.options.value; - if (typeof el.oninput == "function") { - el.oninput({ - type: "input", - target: el, - value: el.value, - }); - } - } - - // Events - if (typeof obj.options.onchange == "function") { - obj.options.onchange(el, obj, oldValue, obj.options.value); - } - }; - - /** - * Set value - */ - obj.setValue = function (newValue) { - // Current value - var oldValue = obj.getValue(); - // New value - if (Array.isArray(newValue)) { - newValue = newValue.join(";"); - } - - if (oldValue !== newValue) { - // Set value - applyValue(newValue); - - // Change - change(oldValue); - } - }; - - obj.resetSelected = function () { - obj.setValue(null); - }; - - obj.selectIndex = function (index, force) { - // Make sure is a number - var index = parseInt(index); - - // Only select those existing elements - if ( - obj.items && - obj.items[index] && - (force === true || obj.items[index].data.disabled !== true) - ) { - // Reset cursor to a new position - obj.setCursor(index, false); - - // Behaviour - if (!obj.options.multiple) { - // Update value - if (obj.items[index].selected) { - obj.setValue(null); - } else { - obj.setValue(Value(index)); - } - - // Close component - obj.close(); - } else { - // Old value - var oldValue = obj.options.value; - - // Toggle option - if (obj.items[index].selected) { - obj.items[index].element.classList.remove("jdropdown-selected"); - obj.items[index].selected = false; - - delete obj.value[Value(index)]; - } else { - // Select element - obj.items[index].element.classList.add("jdropdown-selected"); - obj.items[index].selected = true; - - // Set value - obj.value[Value(index)] = Text(index); - } - - // Global value - obj.options.value = Object.keys(obj.value).join(";"); - - // Update labels for multiple dropdown - if (obj.options.autocomplete == false) { - obj.header.value = getText().join("; "); - } - - // Events - change(oldValue); - } - } - }; - - obj.selectItem = function (item) { - obj.selectIndex(item.indexValue); - }; - - var exists = function (k, result) { - for (var j = 0; j < result.length; j++) { - if (!obj.options.format) { - if (result[j].value == k) { - return true; - } - } else { - if (result[j].id == k) { - return true; - } - } - } - return false; - }; - - obj.find = function (str) { - if (obj.search == str.trim()) { - return false; - } - - // Search term - obj.search = str; - - // Reset index - obj.setCursor(); - - // Remove nodes from all groups - if (obj.groups.length) { - for (var i = 0; i < obj.groups.length; i++) { - obj.groups[i].lastChild.innerHTML = ""; - } - } - - // Remove all nodes - content.innerHTML = ""; - - // Remove current items in the remote search - if (obj.options.remoteSearch == true) { - // Reset results - obj.results = null; - // URL - var url = - obj.options.url + - (obj.options.url.indexOf("?") > 0 ? "&" : "?") + - "q=" + - str; - // Remote search - jSuites.ajax({ - url: url, - method: "GET", - dataType: "json", - success: function (result) { - // Reset items - obj.items = []; - - // Add the current selected items to the results in case they are not there - var current = Object.keys(obj.value); - if (current.length) { - for (var i = 0; i < current.length; i++) { - if (!exists(current[i], result)) { - if (!obj.options.format) { - result.unshift({ - value: current[i], - text: obj.value[current[i]], - }); - } else { - result.unshift({ - id: current[i], - name: obj.value[current[i]], - }); - } - } - } - } - // Append data - obj.appendData(result); - // Show or hide results - if (!result.length) { - content.style.display = "none"; - } else { - content.style.display = ""; - } - }, - }); - } else { - // Search terms - str = new RegExp(str, "gi"); - - // Reset search - var results = []; - - // Append options - for (var i = 0; i < obj.items.length; i++) { - // Item label - var label = Text(i); - // Item title - var title = obj.items[i].data.title || ""; - // Group name - var groupName = obj.items[i].data.group || ""; - // Synonym - var synonym = obj.items[i].data.synonym || ""; - if (synonym) { - synonym = synonym.join(" "); - } - - if ( - str == null || - obj.items[i].selected == true || - label.match(str) || - title.match(str) || - groupName.match(str) || - synonym.match(str) - ) { - results.push(obj.items[i]); - } - } - - if (!results.length) { - content.style.display = "none"; - - // Results - obj.results = null; - } else { - content.style.display = ""; - - // Results - obj.results = results; - - // Show 200 items at once - var number = results.length || 0; - - // Lazyloading - if (obj.options.lazyLoading == true && number > 200) { - number = 200; - } - - for (var i = 0; i < number; i++) { - if (obj.results[i].group) { - if (!obj.results[i].group.parentNode) { - content.appendChild(obj.results[i].group); - } - obj.results[i].group.lastChild.appendChild( - obj.results[i].element - ); - } else { - content.appendChild(obj.results[i].element); - } - } - } - } - - // Auto focus - if (obj.options.autofocus == true) { - obj.first(); - } - }; - - obj.open = function () { - // Focus - if (!el.classList.contains("jdropdown-focus")) { - // Current dropdown - jSuites.dropdown.current = obj; - - // Start tracking - jSuites.tracking(obj, true); - - // Add focus - el.classList.add("jdropdown-focus"); - - // Animation - if (jSuites.getWindowWidth() < 800) { - if (obj.options.type == null || obj.options.type == "picker") { - jSuites.animation.slideBottom(container, 1); - } - } - - // Filter - if (obj.options.autocomplete == true) { - obj.header.value = obj.search; - obj.header.focus(); - } - - // Set cursor for the first or first selected element - var k = getValue(); - if (k[0]) { - var cursor = obj.getPosition(k[0]); - if (cursor !== false) { - obj.setCursor(cursor); - } - } - - // Container Size - if (!obj.options.type || obj.options.type == "default") { - var rect = el.getBoundingClientRect(); - var rectContainer = container.getBoundingClientRect(); - - if (obj.options.position) { - container.style.position = "fixed"; - if (window.innerHeight < rect.bottom + rectContainer.height) { - container.style.top = ""; - container.style.bottom = window.innerHeight - rect.top + 1 + "px"; - } else { - container.style.top = rect.bottom + "px"; - container.style.bottom = ""; - } - container.style.left = rect.left + "px"; - } else { - if (window.innerHeight < rect.bottom + rectContainer.height) { - container.style.top = ""; - container.style.bottom = rect.height + 1 + "px"; - } else { - container.style.top = ""; - container.style.bottom = ""; - } - } - - container.style.minWidth = rect.width + "px"; - - if (obj.options.maxWidth) { - container.style.maxWidth = obj.options.maxWidth; - } - - if (!obj.items.length && obj.options.autocomplete == true) { - content.style.display = "none"; - } else { - content.style.display = ""; - } - } - } - - // Events - if (typeof obj.options.onopen == "function") { - obj.options.onopen(el); - } - }; - - obj.close = function (ignoreEvents) { - if (el.classList.contains("jdropdown-focus")) { - // Update labels - obj.header.value = obj.getText(); - // Remove cursor - obj.setCursor(); - // Events - if (!ignoreEvents && typeof obj.options.onclose == "function") { - obj.options.onclose(el); - } - // Blur - if (obj.header.blur) { - obj.header.blur(); - } - // Remove focus - el.classList.remove("jdropdown-focus"); - // Start tracking - jSuites.tracking(obj, false); - // Current dropdown - jSuites.dropdown.current = null; - } - - return obj.getValue(); - }; - - /** - * Set cursor - */ - obj.setCursor = function (index, setPosition) { - // Remove current cursor - if (obj.currentIndex != null) { - // Remove visual cursor - if (obj.items && obj.items[obj.currentIndex]) { - obj.items[obj.currentIndex].element.classList.remove( - "jdropdown-cursor" - ); - } - } - - if (index == undefined) { - obj.currentIndex = null; - } else { - index = parseInt(index); - - // Cursor only for visible items - if (obj.items[index].element.parentNode) { - obj.items[index].element.classList.add("jdropdown-cursor"); - obj.currentIndex = index; - - // Update scroll to the cursor element - if (setPosition !== false && obj.items[obj.currentIndex].element) { - var container = content.scrollTop; - var element = obj.items[obj.currentIndex].element; - content.scrollTop = - element.offsetTop - element.scrollTop + element.clientTop - 95; - } - } - } - }; - - // Compatibility - obj.resetCursor = obj.setCursor; - obj.updateCursor = obj.setCursor; - - /** - * Reset cursor and selected items - */ - obj.reset = function () { - // Reset cursor - obj.setCursor(); - - // Reset selected - obj.setValue(null); - }; - - /** - * First available item - */ - obj.first = function () { - if (obj.options.lazyLoading === true) { - obj.loadFirst(); - } - - var items = content.querySelectorAll(".jdropdown-item"); - if (items.length) { - var newIndex = items[0].indexValue; - obj.setCursor(newIndex); - } - }; - - /** - * Last available item - */ - obj.last = function () { - if (obj.options.lazyLoading === true) { - obj.loadLast(); - } - - var items = content.querySelectorAll(".jdropdown-item"); - if (items.length) { - var newIndex = items[items.length - 1].indexValue; - obj.setCursor(newIndex); - } - }; - - obj.next = function (letter) { - var newIndex = null; - - if (letter) { - if (letter.length == 1) { - // Current index - var current = obj.currentIndex || -1; - // Letter - letter = letter.toLowerCase(); - - var e = null; - var l = null; - var items = content.querySelectorAll(".jdropdown-item"); - if (items.length) { - for (var i = 0; i < items.length; i++) { - if (items[i].indexValue > current) { - if ((e = obj.items[items[i].indexValue])) { - if ((l = e.element.innerText[0])) { - l = l.toLowerCase(); - if (letter == l) { - newIndex = items[i].indexValue; - break; - } - } - } - } - } - obj.setCursor(newIndex); - } - } - } else { - if (obj.currentIndex == undefined || obj.currentIndex == null) { - obj.first(); - } else { - var element = obj.items[obj.currentIndex].element; - - var next = element.nextElementSibling; - if (next) { - if (next.classList.contains("jdropdown-group")) { - next = next.lastChild.firstChild; - } - newIndex = next.indexValue; - } else { - if ( - element.parentNode.classList.contains("jdropdown-group-items") - ) { - if ((next = element.parentNode.parentNode.nextElementSibling)) { - if (next.classList.contains("jdropdown-group")) { - next = next.lastChild.firstChild; - } else if (next.classList.contains("jdropdown-item")) { - newIndex = next.indexValue; - } else { - next = null; - } - } - - if (next) { - newIndex = next.indexValue; - } - } - } - - if (newIndex !== null) { - obj.setCursor(newIndex); - } - } - } - }; - - obj.prev = function () { - var newIndex = null; - - if (obj.currentIndex === null) { - obj.first(); - } else { - var element = obj.items[obj.currentIndex].element; - - var prev = element.previousElementSibling; - if (prev) { - if (prev.classList.contains("jdropdown-group")) { - prev = prev.lastChild.lastChild; - } - newIndex = prev.indexValue; - } else { - if (element.parentNode.classList.contains("jdropdown-group-items")) { - if ((prev = element.parentNode.parentNode.previousElementSibling)) { - if (prev.classList.contains("jdropdown-group")) { - prev = prev.lastChild.lastChild; - } else if (prev.classList.contains("jdropdown-item")) { - newIndex = prev.indexValue; - } else { - prev = null; - } - } - - if (prev) { - newIndex = prev.indexValue; - } - } - } - } - - if (newIndex !== null) { - obj.setCursor(newIndex); - } - }; - - obj.loadFirst = function () { - // Search - if (obj.results) { - var results = obj.results; - } else { - var results = obj.items; - } - - // Show 200 items at once - var number = results.length || 0; - - // Lazyloading - if (obj.options.lazyLoading == true && number > 200) { - number = 200; - } - - // Reset container - content.innerHTML = ""; - - // First 200 items - for (var i = 0; i < number; i++) { - if (results[i].group) { - if (!results[i].group.parentNode) { - content.appendChild(results[i].group); - } - results[i].group.lastChild.appendChild(results[i].element); - } else { - content.appendChild(results[i].element); - } - } - - // Scroll go to the begin - content.scrollTop = 0; - }; - - obj.loadLast = function () { - // Search - if (obj.results) { - var results = obj.results; - } else { - var results = obj.items; - } - - // Show first page - var number = results.length; - - // Max 200 items - if (number > 200) { - number = number - 200; - - // Reset container - content.innerHTML = ""; - - // First 200 items - for (var i = number; i < results.length; i++) { - if (results[i].group) { - if (!results[i].group.parentNode) { - content.appendChild(results[i].group); - } - results[i].group.lastChild.appendChild(results[i].element); - } else { - content.appendChild(results[i].element); - } - } - - // Scroll go to the begin - content.scrollTop = content.scrollHeight; - } - }; - - obj.loadUp = function () { - var test = false; - - // Search - if (obj.results) { - var results = obj.results; - } else { - var results = obj.items; - } - - var items = content.querySelectorAll(".jdropdown-item"); - var fistItem = items[0].indexValue; - fistItem = obj.items[fistItem]; - var index = results.indexOf(fistItem) - 1; - - if (index > 0) { - var number = 0; - - while (index > 0 && results[index] && number < 200) { - if (results[index].group) { - if (!results[index].group.parentNode) { - content.insertBefore(results[index].group, content.firstChild); - } - results[index].group.lastChild.insertBefore( - results[index].element, - results[index].group.lastChild.firstChild - ); - } else { - content.insertBefore(results[index].element, content.firstChild); - } - - index--; - number++; - } - - // New item added - test = true; - } - - return test; - }; - - obj.loadDown = function () { - var test = false; - - // Search - if (obj.results) { - var results = obj.results; - } else { - var results = obj.items; - } - - var items = content.querySelectorAll(".jdropdown-item"); - var lastItem = items[items.length - 1].indexValue; - lastItem = obj.items[lastItem]; - var index = results.indexOf(lastItem) + 1; - - if (index < results.length) { - var number = 0; - while (index < results.length && results[index] && number < 200) { - if (results[index].group) { - if (!results[index].group.parentNode) { - content.appendChild(results[index].group); - } - results[index].group.lastChild.appendChild(results[index].element); - } else { - content.appendChild(results[index].element); - } - - index++; - number++; - } - - // New item added - test = true; - } - - return test; - }; - - init(); - - return obj; - }; - - jSuites.dropdown.keydown = function (e) { - var dropdown = null; - if ((dropdown = jSuites.dropdown.current)) { - if (e.which == 13 || e.which == 9) { - // enter or tab - if ( - dropdown.header.value && - dropdown.currentIndex == null && - dropdown.options.newOptions - ) { - // if they typed something in, but it matched nothing, and newOptions are allowed, start that flow - dropdown.add(); - } else { - // Quick Select/Filter - if ( - dropdown.currentIndex == null && - dropdown.options.autocomplete == true && - dropdown.header.value != "" - ) { - dropdown.find(dropdown.header.value); - } - dropdown.selectIndex(dropdown.currentIndex); - } - } else if (e.which == 38) { - // up arrow - if (dropdown.currentIndex == null) { - dropdown.first(); - } else if (dropdown.currentIndex > 0) { - dropdown.prev(); - } - e.preventDefault(); - } else if (e.which == 40) { - // down arrow - if (dropdown.currentIndex == null) { - dropdown.first(); - } else if (dropdown.currentIndex + 1 < dropdown.items.length) { - dropdown.next(); - } - e.preventDefault(); - } else if (e.which == 36) { - dropdown.first(); - if (!e.target.classList.contains("jdropdown-header")) { - e.preventDefault(); - } - } else if (e.which == 35) { - dropdown.last(); - if (!e.target.classList.contains("jdropdown-header")) { - e.preventDefault(); - } - } else if (e.which == 27) { - dropdown.close(); - } else if (e.which == 33) { - // page up - if (dropdown.currentIndex == null) { - dropdown.first(); - } else if (dropdown.currentIndex > 0) { - for (var i = 0; i < 7; i++) { - dropdown.prev(); - } - } - e.preventDefault(); - } else if (e.which == 34) { - // page down - if (dropdown.currentIndex == null) { - dropdown.first(); - } else if (dropdown.currentIndex + 1 < dropdown.items.length) { - for (var i = 0; i < 7; i++) { - dropdown.next(); - } - } - e.preventDefault(); - } - } - }; - - jSuites.dropdown.mouseup = function (e) { - var element = jSuites.findElement(e.target, "jdropdown"); - if (element) { - var dropdown = element.dropdown; - if (e.target.classList.contains("jdropdown-header")) { - if ( - element.classList.contains("jdropdown-focus") && - element.classList.contains("jdropdown-default") - ) { - var rect = element.getBoundingClientRect(); - - if (e.changedTouches && e.changedTouches[0]) { - var x = e.changedTouches[0].clientX; - var y = e.changedTouches[0].clientY; - } else { - var x = e.clientX; - var y = e.clientY; - } - - if (rect.width - (x - rect.left) < 30) { - if (e.target.classList.contains("jdropdown-add")) { - dropdown.add(); - } else { - dropdown.close(); - } - } else { - if (dropdown.options.autocomplete == false) { - dropdown.close(); - } - } - } else { - dropdown.open(); - } - } else if (e.target.classList.contains("jdropdown-group-name")) { - var items = e.target.nextSibling.children; - if (e.target.nextSibling.style.display != "none") { - for (var i = 0; i < items.length; i++) { - if (items[i].style.display != "none") { - dropdown.selectItem(items[i]); - } - } - } - } else if (e.target.classList.contains("jdropdown-group-arrow")) { - if (e.target.classList.contains("jdropdown-group-arrow-down")) { - e.target.classList.remove("jdropdown-group-arrow-down"); - e.target.classList.add("jdropdown-group-arrow-up"); - e.target.parentNode.nextSibling.style.display = "none"; - } else { - e.target.classList.remove("jdropdown-group-arrow-up"); - e.target.classList.add("jdropdown-group-arrow-down"); - e.target.parentNode.nextSibling.style.display = ""; - } - } else if (e.target.classList.contains("jdropdown-item")) { - dropdown.selectItem(e.target); - } else if (e.target.classList.contains("jdropdown-image")) { - dropdown.selectItem(e.target.parentNode); - } else if (e.target.classList.contains("jdropdown-description")) { - dropdown.selectItem(e.target.parentNode); - } else if (e.target.classList.contains("jdropdown-title")) { - dropdown.selectItem(e.target.parentNode.parentNode); - } else if ( - e.target.classList.contains("jdropdown-close") || - e.target.classList.contains("jdropdown-backdrop") - ) { - dropdown.close(); - } - } - }; - - jSuites.dropdown.extractFromDom = function (el, options) { - // Keep reference - var select = el; - if (!options) { - options = {}; - } - // Prepare configuration - if ( - el.getAttribute("multiple") && - (!options || options.multiple == undefined) - ) { - options.multiple = true; - } - if ( - el.getAttribute("placeholder") && - (!options || options.placeholder == undefined) - ) { - options.placeholder = el.getAttribute("placeholder"); - } - if ( - el.getAttribute("data-autocomplete") && - (!options || options.autocomplete == undefined) - ) { - options.autocomplete = true; - } - if (!options || options.width == undefined) { - options.width = el.offsetWidth; - } - if (el.value && (!options || options.value == undefined)) { - options.value = el.value; - } - if (!options || options.data == undefined) { - options.data = []; - for (var j = 0; j < el.children.length; j++) { - if (el.children[j].tagName == "OPTGROUP") { - for (var i = 0; i < el.children[j].children.length; i++) { - options.data.push({ - value: el.children[j].children[i].value, - text: el.children[j].children[i].innerHTML, - group: el.children[j].getAttribute("label"), - }); - } - } else { - options.data.push({ - value: el.children[j].value, - text: el.children[j].innerHTML, - }); - } - } - } - if (!options || options.onchange == undefined) { - options.onchange = function (a, b, c, d) { - if (options.multiple == true) { - if (obj.items[b].classList.contains("jdropdown-selected")) { - select.options[b].setAttribute("selected", "selected"); - } else { - select.options[b].removeAttribute("selected"); - } - } else { - select.value = d; - } - }; - } - // Create DIV - var div = document.createElement("div"); - el.parentNode.insertBefore(div, el); - el.style.display = "none"; - el = div; - - return { el: el, options: options }; - }; - - jSuites.editor = function (el, options) { - // New instance - var obj = { type: "editor" }; - obj.options = {}; - - // Default configuration - var defaults = { - // Initial HTML content - value: null, - // Initial snippet - snippet: null, - // Add toolbar - toolbar: null, - // Website parser is to read websites and images from cross domain - remoteParser: null, - // Placeholder - placeholder: null, - // Parse URL - parseURL: false, - filterPaste: true, - // Accept drop files - dropZone: false, - dropAsSnippet: false, - acceptImages: false, - acceptFiles: false, - maxFileSize: 5000000, - allowImageResize: true, - // Style - border: true, - padding: true, - maxHeight: null, - height: null, - focus: false, - // Events - onclick: null, - onfocus: null, - onblur: null, - onload: null, - onkeyup: null, - onkeydown: null, - onchange: null, - userSearch: null, - }; - - // Loop through our object - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - obj.options[property] = defaults[property]; - } - } - - // Private controllers - var imageResize = 0; - var editorTimer = null; - var editorAction = null; - var files = []; - - // Make sure element is empty - el.innerHTML = ""; - - // Keep the reference for the container - obj.el = el; - - if (typeof obj.options.onclick == "function") { - el.onclick = function (e) { - obj.options.onclick(el, obj, e); - }; - } - - // Prepare container - el.classList.add("jeditor-container"); - - // Padding - if (obj.options.padding == true) { - el.classList.add("jeditor-padding"); - } - - // Border - if (obj.options.border == false) { - el.style.border = "0px"; - } - - // Snippet - var snippet = document.createElement("div"); - snippet.className = "jsnippet"; - snippet.setAttribute("contenteditable", false); - - // Toolbar - var toolbar = document.createElement("div"); - toolbar.className = "jeditor-toolbar"; - - // Create editor - var editor = document.createElement("div"); - editor.setAttribute("contenteditable", true); - editor.setAttribute("spellcheck", false); - editor.className = "jeditor"; - - // Placeholder - if (obj.options.placeholder) { - editor.setAttribute("data-placeholder", obj.options.placeholder); - } - - // Max height - if (obj.options.maxHeight || obj.options.height) { - editor.style.overflowY = "auto"; - - if (obj.options.maxHeight) { - editor.style.maxHeight = obj.options.maxHeight; - } - if (obj.options.height) { - editor.style.height = obj.options.height; - } - } - - // Set editor initial value - if (obj.options.value) { - var value = obj.options.value; - } else { - var value = el.innerHTML ? el.innerHTML : ""; - } - - if (!value) { - var value = ""; - } - - /** - * Onchange event controllers - */ - var change = function (e) { - if (typeof obj.options.onchange == "function") { - obj.options.onchange(el, obj, e); - } - - // Update value - obj.options.value = obj.getData(); - - // Lemonade JS - if (el.value != obj.options.value) { - el.value = obj.options.value; - if (typeof el.oninput == "function") { - el.oninput({ - type: "input", - target: el, - value: el.value, - }); - } - } - }; - - // Create node - var createUserSearchNode = function () { - // Get coordinates from caret - var sel = window.getSelection - ? window.getSelection() - : document.selection; - var range = sel.getRangeAt(0); - range.deleteContents(); - // Append text node - var input = document.createElement("a"); - input.innerText = "@"; - input.searchable = true; - range.insertNode(input); - var node = range.getBoundingClientRect(); - range.collapse(false); - // Position - userSearch.style.position = "fixed"; - userSearch.style.top = node.top + node.height + 10 + "px"; - userSearch.style.left = node.left + 2 + "px"; - }; - - /** - * Extract images from a HTML string - */ - var extractImageFromHtml = function (html) { - // Create temp element - var div = document.createElement("div"); - div.innerHTML = html; - - // Extract images - var img = div.querySelectorAll("img"); - - if (img.length) { - for (var i = 0; i < img.length; i++) { - obj.addImage(img[i].src); - } - } - }; - - /** - * Insert node at caret - */ - var insertNodeAtCaret = function (newNode) { - var sel, range; - - if (window.getSelection) { - sel = window.getSelection(); - if (sel.rangeCount) { - range = sel.getRangeAt(0); - var selectedText = range.toString(); - range.deleteContents(); - range.insertNode(newNode); - // move the cursor after element - range.setStartAfter(newNode); - range.setEndAfter(newNode); - sel.removeAllRanges(); - sel.addRange(range); - } - } - }; - - var updateTotalImages = function () { - var o = null; - if ((o = snippet.children[0])) { - // Make sure is a grid - if (!o.classList.contains("jslider-grid")) { - o.classList.add("jslider-grid"); - } - // Quantify of images - var number = o.children.length; - // Set the configuration of the grid - o.setAttribute("data-number", number > 4 ? 4 : number); - // Total of images inside the grid - if (number > 4) { - o.setAttribute("data-total", number - 4); - } else { - o.removeAttribute("data-total"); - } - } - }; - - /** - * Append image to the snippet - */ - var appendImage = function (image) { - if (!snippet.innerHTML) { - appendElement({}); - } - snippet.children[0].appendChild(image); - updateTotalImages(); - }; - - /** - * Append snippet - * @Param object data - */ - var appendElement = function (data) { - // Reset snippet - snippet.innerHTML = ""; - - // Attributes - var a = ["image", "title", "description", "host", "url"]; - - for (var i = 0; i < a.length; i++) { - var div = document.createElement("div"); - div.className = "jsnippet-" + a[i]; - div.setAttribute("data-k", a[i]); - snippet.appendChild(div); - if (data[a[i]]) { - if (a[i] == "image") { - if (!Array.isArray(data.image)) { - data.image = [data.image]; - } - for (var j = 0; j < data.image.length; j++) { - var img = document.createElement("img"); - img.src = data.image[j]; - div.appendChild(img); - } - } else { - div.innerHTML = data[a[i]]; - } - } - } - - editor.appendChild(document.createElement("br")); - editor.appendChild(snippet); - }; - - var verifyEditor = function () { - clearTimeout(editorTimer); - editorTimer = setTimeout(function () { - var snippet = editor.querySelector(".jsnippet"); - if (!snippet) { - var html = editor.innerHTML.replace(/\n/g, " "); - var container = document.createElement("div"); - container.innerHTML = html; - var text = container.innerText; - var url = jSuites.editor.detectUrl(text); - - if (url) { - if ( - url[0].substr(-3) == "jpg" || - url[0].substr(-3) == "png" || - url[0].substr(-3) == "gif" - ) { - obj.addImage(url[0], true); - } else { - var id = jSuites.editor.youtubeParser(url[0]); - obj.parseWebsite(url[0], id); - } - } - } - }, 1000); - }; - - obj.parseContent = function () { - verifyEditor(); - }; - - obj.parseWebsite = function (url, youtubeId) { - if (!obj.options.remoteParser) { - console.log("The remoteParser is not defined"); - } else { - // Youtube definitions - if (youtubeId) { - var url = "https://www.youtube.com/watch?v=" + youtubeId; - } - - var p = { - title: "", - description: "", - image: "", - host: url.split("/")[2], - url: url, - }; - - jSuites.ajax({ - url: obj.options.remoteParser + encodeURI(url.trim()), - method: "GET", - dataType: "json", - success: function (result) { - // Get title - if (result.title) { - p.title = result.title; - } - // Description - if (result.description) { - p.description = result.description; - } - // Host - if (result.host) { - p.host = result.host; - } - // Url - if (result.url) { - p.url = result.url; - } - // Append snippet - appendElement(p); - // Add image - if (result.image) { - obj.addImage(result.image, true); - } else if (result["og:image"]) { - obj.addImage(result["og:image"], true); - } - }, - }); - } - }; - - /** - * Set editor value - */ - obj.setData = function (o) { - if (typeof o == "object") { - editor.innerHTML = o.content; - } else { - editor.innerHTML = o; - } - - if (obj.options.focus) { - jSuites.editor.setCursor(editor, true); - } - - // Reset files container - files = []; - }; - - obj.getFiles = function () { - var f = editor.querySelectorAll(".jfile"); - var d = []; - for (var i = 0; i < f.length; i++) { - if (files[f[i].src]) { - d.push(files[f[i].src]); - } - } - return d; - }; - - obj.getText = function () { - return editor.innerText; - }; - - /** - * Get editor data - */ - obj.getData = function (json) { - if (!json) { - var data = editor.innerHTML; - } else { - var data = { - content: "", - }; - - // Get snippet - if (snippet.innerHTML) { - var index = 0; - data.snippet = {}; - for (var i = 0; i < snippet.children.length; i++) { - // Get key from element - var key = snippet.children[i].getAttribute("data-k"); - if (key) { - if (key == "image") { - if (!data.snippet.image) { - data.snippet.image = []; - } - // Get all images - for (var j = 0; j < snippet.children[i].children.length; j++) { - data.snippet.image.push( - snippet.children[i].children[j].getAttribute("src") - ); - } - } else { - data.snippet[key] = snippet.children[i].innerHTML; - } - } - } - } - - // Get files - var f = Object.keys(files); - if (f.length) { - data.files = []; - for (var i = 0; i < f.length; i++) { - data.files.push(files[f[i]]); - } - } - - // Users - if (userSearch) { - // Get tag users - var tagged = editor.querySelectorAll("a[data-user]"); - if (tagged.length) { - data.users = []; - for (var i = 0; i < tagged.length; i++) { - var userId = tagged[i].getAttribute("data-user"); - if (userId) { - data.users.push(userId); - } - } - data.users = data.users.join(","); - } - } - - // Get content - var d = document.createElement("div"); - d.innerHTML = editor.innerHTML; - var s = d.querySelector(".jsnippet"); - if (s) { - s.remove(); - } - - var text = d.innerHTML; - text = text.replace(/
/g, "\n"); - text = text.replace(/<\/div>/g, "\n"); - text = text.replace(/<(?:.|\n)*?>/gm, ""); - data.content = text.trim(); - } - - return data; - }; - - // Reset - obj.reset = function () { - editor.innerHTML = ""; - snippet.innerHTML = ""; - files = []; - }; - - obj.addPdf = function (data) { - if (data.result.substr(0, 4) != "data") { - console.error("Invalid source"); - } else { - var canvas = document.createElement("canvas"); - canvas.width = 60; - canvas.height = 60; - - var img = new Image(); - var ctx = canvas.getContext("2d"); - ctx.drawImage(img, 0, 0, canvas.width, canvas.height); - - canvas.toBlob(function (blob) { - var newImage = document.createElement("img"); - newImage.src = window.URL.createObjectURL(blob); - newImage.title = data.name; - newImage.className = "jfile pdf"; - - files[newImage.src] = { - file: newImage.src, - extension: "pdf", - content: data.result, - }; - - insertNodeAtCaret(newImage); - }); - } - }; - - obj.addImage = function (src, asSnippet) { - if (!src) { - src = ""; - } - - if (src.substr(0, 4) != "data" && !obj.options.remoteParser) { - console.error("remoteParser not defined in your initialization"); - } else { - // This is to process cross domain images - if (src.substr(0, 4) == "data") { - var extension = src.split(";"); - extension = extension[0].split("/"); - extension = extension[1]; - } else { - var extension = src.substr(src.lastIndexOf(".") + 1); - // Work for cross browsers - src = obj.options.remoteParser + src; - } - - var img = new Image(); - - img.onload = function onload() { - var canvas = document.createElement("canvas"); - canvas.width = img.width; - canvas.height = img.height; - - var ctx = canvas.getContext("2d"); - ctx.drawImage(img, 0, 0, canvas.width, canvas.height); - - canvas.toBlob(function (blob) { - var newImage = document.createElement("img"); - newImage.src = window.URL.createObjectURL(blob); - newImage.classList.add("jfile"); - newImage.setAttribute("tabindex", "900"); - files[newImage.src] = { - file: newImage.src, - extension: extension, - content: canvas.toDataURL(), - }; - - if (obj.options.dropAsSnippet || asSnippet) { - appendImage(newImage); - // Just to understand the attachment is part of a snippet - files[newImage.src].snippet = true; - } else { - insertNodeAtCaret(newImage); - } - - change(); - }); - }; - - img.src = src; - } - }; - - obj.addFile = function (files) { - var reader = []; - - for (var i = 0; i < files.length; i++) { - if (files[i].size > obj.options.maxFileSize) { - alert("The file is too big"); - } else { - // Only PDF or Images - var type = files[i].type.split("/"); - - if (type[0] == "image") { - type = 1; - } else if (type[1] == "pdf") { - type = 2; - } else { - type = 0; - } - - if (type) { - // Create file - reader[i] = new FileReader(); - reader[i].index = i; - reader[i].type = type; - reader[i].name = files[i].name; - reader[i].date = files[i].lastModified; - reader[i].size = files[i].size; - reader[i].addEventListener( - "load", - function (data) { - // Get result - if (data.target.type == 2) { - if (obj.options.acceptFiles == true) { - obj.addPdf(data.target); - } - } else { - obj.addImage(data.target.result); - } - }, - false - ); - - reader[i].readAsDataURL(files[i]); - } else { - alert("The extension is not allowed"); - } - } - } - }; - - // Destroy - obj.destroy = function () { - editor.removeEventListener("mouseup", editorMouseUp); - editor.removeEventListener("mousedown", editorMouseDown); - editor.removeEventListener("mousemove", editorMouseMove); - editor.removeEventListener("keyup", editorKeyUp); - editor.removeEventListener("keydown", editorKeyDown); - editor.removeEventListener("dragstart", editorDragStart); - editor.removeEventListener("dragenter", editorDragEnter); - editor.removeEventListener("dragover", editorDragOver); - editor.removeEventListener("drop", editorDrop); - editor.removeEventListener("paste", editorPaste); - editor.removeEventListener("blur", editorBlur); - editor.removeEventListener("focus", editorFocus); - - el.editor = null; - el.classList.remove("jeditor-container"); - - toolbar.remove(); - snippet.remove(); - editor.remove(); - }; - - var isLetter = function (str) { - var regex = - /([\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]+)/g; - return str.match(regex) ? 1 : 0; - }; - - // Event handlers - var editorMouseUp = function (e) { - if (editorAction && editorAction.e) { - editorAction.e.classList.remove("resizing"); - } - - editorAction = false; - }; - - var editorMouseDown = function (e) { - var close = function (snippet) { - var rect = snippet.getBoundingClientRect(); - if ( - rect.width - (e.clientX - rect.left) < 40 && - e.clientY - rect.top < 40 - ) { - snippet.innerHTML = ""; - snippet.remove(); - } - }; - - if (e.target.tagName == "IMG") { - if (e.target.style.cursor) { - var rect = e.target.getBoundingClientRect(); - editorAction = { - e: e.target, - x: e.clientX, - y: e.clientY, - w: rect.width, - h: rect.height, - d: e.target.style.cursor, - }; - - if (!e.target.width) { - e.target.width = rect.width + "px"; - } - - if (!e.target.height) { - e.target.height = rect.height + "px"; - } - - var s = window.getSelection(); - if (s.rangeCount) { - for (var i = 0; i < s.rangeCount; i++) { - s.removeRange(s.getRangeAt(i)); - } - } - - e.target.classList.add("resizing"); - } else { - editorAction = true; - } - } else { - if (e.target.classList.contains("jsnippet")) { - close(e.target); - } else if (e.target.parentNode.classList.contains("jsnippet")) { - close(e.target.parentNode); - } - - editorAction = true; - } - }; - - var editorMouseMove = function (e) { - if ( - e.target.tagName == "IMG" && - !e.target.parentNode.classList.contains("jsnippet-image") && - obj.options.allowImageResize == true - ) { - if (e.target.getAttribute("tabindex")) { - var rect = e.target.getBoundingClientRect(); - if (e.clientY - rect.top < 5) { - if (rect.width - (e.clientX - rect.left) < 5) { - e.target.style.cursor = "ne-resize"; - } else if (e.clientX - rect.left < 5) { - e.target.style.cursor = "nw-resize"; - } else { - e.target.style.cursor = "n-resize"; - } - } else if (rect.height - (e.clientY - rect.top) < 5) { - if (rect.width - (e.clientX - rect.left) < 5) { - e.target.style.cursor = "se-resize"; - } else if (e.clientX - rect.left < 5) { - e.target.style.cursor = "sw-resize"; - } else { - e.target.style.cursor = "s-resize"; - } - } else if (rect.width - (e.clientX - rect.left) < 5) { - e.target.style.cursor = "e-resize"; - } else if (e.clientX - rect.left < 5) { - e.target.style.cursor = "w-resize"; - } else { - e.target.style.cursor = ""; - } - } - } - - // Move - if (e.which == 1 && editorAction && editorAction.d) { - if ( - editorAction.d == "e-resize" || - editorAction.d == "ne-resize" || - editorAction.d == "se-resize" - ) { - editorAction.e.width = editorAction.w + (e.clientX - editorAction.x); - - if (e.shiftKey) { - var newHeight = - (e.clientX - editorAction.x) * (editorAction.h / editorAction.w); - editorAction.e.height = editorAction.h + newHeight; - } else { - var newHeight = null; - } - } - - if (!newHeight) { - if ( - editorAction.d == "s-resize" || - editorAction.d == "se-resize" || - editorAction.d == "sw-resize" - ) { - if (!e.shiftKey) { - editorAction.e.height = - editorAction.h + (e.clientY - editorAction.y); - } - } - } - } - }; - - var editorKeyUp = function (e) { - if (!editor.innerHTML) { - editor.innerHTML = "

"; - } - - if (userSearch) { - var t = jSuites.getNode(); - if (t) { - if (t.searchable === true) { - if (t.innerText && t.innerText.substr(0, 1) == "@") { - userSearchInstance(t.innerText.substr(1)); - } - } else if (t.searchable === false) { - if (t.innerText !== t.getAttribute("data-label")) { - t.searchable = true; - t.removeAttribute("href"); - } - } - } - } - - if (typeof obj.options.onkeyup == "function") { - obj.options.onkeyup(el, obj, e); - } - }; - - var editorKeyDown = function (e) { - // Check for URL - if (obj.options.parseURL == true) { - verifyEditor(); - } - - if (userSearch) { - if (e.key == "@") { - createUserSearchNode(editor); - e.preventDefault(); - } else { - if (userSearchInstance.isOpened()) { - userSearchInstance.keydown(e); - } - } - } - - if (typeof obj.options.onkeydown == "function") { - obj.options.onkeydown(el, obj, e); - } - - if (e.key == "Delete") { - if ( - e.target.tagName == "IMG" && - e.target.parentNode.classList.contains("jsnippet-image") - ) { - e.target.remove(); - updateTotalImages(); - } - } - }; - - // Elements to be removed - var remove = [ - HTMLUnknownElement, - HTMLAudioElement, - HTMLEmbedElement, - HTMLIFrameElement, - HTMLTextAreaElement, - HTMLInputElement, - HTMLScriptElement, - ]; - - // Valid properties - var validProperty = [ - "width", - "height", - "align", - "border", - "src", - "tabindex", - ]; - - // Valid CSS attributes - var validStyle = [ - "color", - "font-weight", - "font-size", - "background", - "background-color", - "margin", - ]; - - var parse = function (element) { - // Remove attributes - if (element.attributes && element.attributes.length) { - var image = null; - var style = null; - // Process style attribute - var elementStyle = element.getAttribute("style"); - if (elementStyle) { - style = []; - var t = elementStyle.split(";"); - for (var j = 0; j < t.length; j++) { - var v = t[j].trim().split(":"); - if (validStyle.indexOf(v[0].trim()) >= 0) { - var k = v.shift(); - var v = v.join(":"); - style.push(k + ":" + v); - } - } - } - // Process image - if (element.tagName.toUpperCase() == "IMG") { - if (!obj.options.acceptImages || !element.src) { - element.parentNode.removeChild(element); - } else { - // Check if is data - element.setAttribute("tabindex", "900"); - // Check attributes for persistance - obj.addImage(element.src); - } - } - // Remove attributes - var attr = []; - var numAttributes = element.attributes.length - 1; - if (numAttributes > 0) { - for (var i = numAttributes; i >= 0; i--) { - attr.push(element.attributes[i].name); - } - attr.forEach(function (v) { - if (validProperty.indexOf(v) == -1) { - element.removeAttribute(v); - } - }); - } - element.style = ""; - // Add valid style - if (style && style.length) { - element.setAttribute("style", style.join(";")); - } - } - // Parse children - if (element.children.length) { - for (var i = 0; i < element.children.length; i++) { - parse(element.children[i]); - } - } - - if (remove.indexOf(element.constructor) >= 0) { - element.remove(); - } - }; - - var filter = function (data) { - if (data) { - data = data.replace(new RegExp("", "gsi"), ""); - } - var parser = new DOMParser(); - var d = parser.parseFromString(data, "text/html"); - parse(d); - var span = document.createElement("span"); - span.innerHTML = d.firstChild.innerHTML; - return span; - }; - - var editorPaste = function (e) { - if (obj.options.filterPaste == true) { - if (e.clipboardData || e.originalEvent.clipboardData) { - var html = (e.originalEvent || e).clipboardData.getData("text/html"); - var text = (e.originalEvent || e).clipboardData.getData("text/plain"); - var file = (e.originalEvent || e).clipboardData.files; - } else if (window.clipboardData) { - var html = window.clipboardData.getData("Html"); - var text = window.clipboardData.getData("Text"); - var file = window.clipboardData.files; - } - - if (file.length) { - // Paste a image from the clipboard - obj.addFile(file); - } else { - if (!html) { - html = text.split("\r\n"); - if (!e.target.innerText) { - html.map(function (v) { - var d = document.createElement("div"); - d.innerText = v; - editor.appendChild(d); - }); - } else { - html = html.map(function (v) { - return "
" + v + "
"; - }); - document.execCommand("insertHtml", false, html.join("")); - } - } else { - var d = filter(html); - // Paste to the editor - //insertNodeAtCaret(d); - document.execCommand("insertHtml", false, d.innerHTML); - } - } - - e.preventDefault(); - } - }; - - var editorDragStart = function (e) { - if (editorAction && editorAction.e) { - e.preventDefault(); - } - }; - - var editorDragEnter = function (e) { - if (editorAction || obj.options.dropZone == false) { - // Do nothing - } else { - el.classList.add("jeditor-dragging"); - e.preventDefault(); - } - }; - - var editorDragOver = function (e) { - if (editorAction || obj.options.dropZone == false) { - // Do nothing - } else { - if (editorTimer) { - clearTimeout(editorTimer); - } - - editorTimer = setTimeout(function () { - el.classList.remove("jeditor-dragging"); - }, 100); - e.preventDefault(); - } - }; - - var editorDrop = function (e) { - if (editorAction || obj.options.dropZone == false) { - // Do nothing - } else { - // Position caret on the drop - var range = null; - if (document.caretRangeFromPoint) { - range = document.caretRangeFromPoint(e.clientX, e.clientY); - } else if (e.rangeParent) { - range = document.createRange(); - range.setStart(e.rangeParent, e.rangeOffset); - } - var sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange(range); - sel.anchorNode.parentNode.focus(); - - var html = (e.originalEvent || e).dataTransfer.getData("text/html"); - var text = (e.originalEvent || e).dataTransfer.getData("text/plain"); - var file = (e.originalEvent || e).dataTransfer.files; - - if (file.length) { - obj.addFile(file); - } else if (text) { - extractImageFromHtml(html); - } - - el.classList.remove("jeditor-dragging"); - e.preventDefault(); - } - }; - - var editorBlur = function (e) { - if (userSearch && userSearchInstance.isOpened()) { - userSearchInstance.close(); - } - - // Blur - if (typeof obj.options.onblur == "function") { - obj.options.onblur(el, obj, e); - } - - change(e); - }; - - var editorFocus = function (e) { - // Focus - if (typeof obj.options.onfocus == "function") { - obj.options.onfocus(el, obj, e); - } - }; - - editor.addEventListener("mouseup", editorMouseUp); - editor.addEventListener("mousedown", editorMouseDown); - editor.addEventListener("mousemove", editorMouseMove); - editor.addEventListener("keyup", editorKeyUp); - editor.addEventListener("keydown", editorKeyDown); - editor.addEventListener("dragstart", editorDragStart); - editor.addEventListener("dragenter", editorDragEnter); - editor.addEventListener("dragover", editorDragOver); - editor.addEventListener("drop", editorDrop); - editor.addEventListener("paste", editorPaste); - editor.addEventListener("focus", editorFocus); - editor.addEventListener("blur", editorBlur); - - // Onload - if (typeof obj.options.onload == "function") { - obj.options.onload(el, obj, editor); - } - - // Set value to the editor - editor.innerHTML = value; - - // Append editor to the containre - el.appendChild(editor); - - // Snippet - if (obj.options.snippet) { - appendElement(obj.options.snippet); - } - - // Default toolbar - if (obj.options.toolbar == null) { - obj.options.toolbar = jSuites.editor.getDefaultToolbar(); - } - - // Add toolbar - if (obj.options.toolbar) { - // Append to the DOM - el.appendChild(toolbar); - // Create toolbar - jSuites.toolbar(toolbar, { - container: true, - responsive: true, - items: obj.options.toolbar, - }); - } - - // Add user search - var userSearch = null; - var userSearchInstance = null; - if (obj.options.userSearch) { - userSearch = document.createElement("div"); - el.appendChild(userSearch); - - // Component - userSearchInstance = jSuites.search(userSearch, { - data: obj.options.userSearch, - placeholder: jSuites.translate("Type the name a user"), - onselect: function (a, b, c, d) { - if (userSearchInstance.isOpened()) { - var t = jSuites.getNode(); - if ( - t && - t.searchable == true && - t.innerText.trim() && - t.innerText.substr(1) - ) { - t.innerText = "@" + c; - t.href = "/" + c; - t.setAttribute("data-user", d); - t.setAttribute("data-label", t.innerText); - t.searchable = false; - jSuites.focus(t); - } - } - }, - }); - } - - // Focus to the editor - if (obj.options.focus) { - jSuites.editor.setCursor( - editor, - obj.options.focus == "initial" ? true : false - ); - } - - // Change method - el.change = obj.setData; - - // Global generic value handler - el.val = function (val) { - if (val === undefined) { - // Data type - var o = el.getAttribute("data-html") === "true" ? false : true; - return obj.getData(o); - } else { - obj.setData(val); - } - }; - - el.editor = obj; - - return obj; - }; - - jSuites.editor.setCursor = function (element, first) { - element.focus(); - document.execCommand("selectAll"); - var sel = window.getSelection(); - var range = sel.getRangeAt(0); - if (first == true) { - var node = range.startContainer; - var size = 0; - } else { - var node = range.endContainer; - var size = node.length; - } - range.setStart(node, size); - range.setEnd(node, size); - sel.removeAllRanges(); - sel.addRange(range); - }; - - jSuites.editor.getDomain = function (url) { - return url - .replace("http://", "") - .replace("https://", "") - .replace("www.", "") - .split(/[/?#]/)[0] - .split(/:/g)[0]; - }; - - jSuites.editor.detectUrl = function (text) { - var expression = - /(((https?:\/\/)|(www\.))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]+)/gi; - var links = text.match(expression); - - if (links) { - if (links[0].substr(0, 3) == "www") { - links[0] = "http://" + links[0]; - } - } - - return links; - }; - - jSuites.editor.youtubeParser = function (url) { - var regExp = - /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/; - var match = url.match(regExp); - - return match && match[7].length == 11 ? match[7] : false; - }; - - jSuites.editor.getDefaultToolbar = function () { - return [ - { - content: "undo", - onclick: function () { - document.execCommand("undo"); - }, - }, - { - content: "redo", - onclick: function () { - document.execCommand("redo"); - }, - }, - { - type: "divisor", - }, - { - content: "format_bold", - onclick: function (a, b, c) { - document.execCommand("bold"); - - if (document.queryCommandState("bold")) { - c.classList.add("selected"); - } else { - c.classList.remove("selected"); - } - }, - }, - { - content: "format_italic", - onclick: function (a, b, c) { - document.execCommand("italic"); - - if (document.queryCommandState("italic")) { - c.classList.add("selected"); - } else { - c.classList.remove("selected"); - } - }, - }, - { - content: "format_underline", - onclick: function (a, b, c) { - document.execCommand("underline"); - - if (document.queryCommandState("underline")) { - c.classList.add("selected"); - } else { - c.classList.remove("selected"); - } - }, - }, - { - type: "divisor", - }, - { - content: "format_list_bulleted", - onclick: function (a, b, c) { - document.execCommand("insertUnorderedList"); - - if (document.queryCommandState("insertUnorderedList")) { - c.classList.add("selected"); - } else { - c.classList.remove("selected"); - } - }, - }, - { - content: "format_list_numbered", - onclick: function (a, b, c) { - document.execCommand("insertOrderedList"); - - if (document.queryCommandState("insertOrderedList")) { - c.classList.add("selected"); - } else { - c.classList.remove("selected"); - } - }, - }, - { - content: "format_indent_increase", - onclick: function (a, b, c) { - document.execCommand("indent", true, null); - - if (document.queryCommandState("indent")) { - c.classList.add("selected"); - } else { - c.classList.remove("selected"); - } - }, - }, - { - content: "format_indent_decrease", - onclick: function () { - document.execCommand("outdent"); - - if (document.queryCommandState("outdent")) { - this.classList.add("selected"); - } else { - this.classList.remove("selected"); - } - }, - } /*, - { - icon: ['format_align_left', 'format_align_right', 'format_align_center'], - onclick: function() { - document.execCommand('justifyCenter'); - - if (document.queryCommandState("justifyCenter")) { - this.classList.add('selected'); - } else { - this.classList.remove('selected'); - } - } - } - { - type:'select', - items: ['Verdana','Arial','Courier New'], - onchange: function() { - } - }, - { - type:'select', - items: ['10px','12px','14px','16px','18px','20px','22px'], - onchange: function() { - } - }, - { - icon:'format_align_left', - onclick: function() { - document.execCommand('JustifyLeft'); - - if (document.queryCommandState("JustifyLeft")) { - this.classList.add('selected'); - } else { - this.classList.remove('selected'); - } - } - }, - { - icon:'format_align_center', - onclick: function() { - document.execCommand('justifyCenter'); - - if (document.queryCommandState("justifyCenter")) { - this.classList.add('selected'); - } else { - this.classList.remove('selected'); - } - } - }, - { - icon:'format_align_right', - onclick: function() { - document.execCommand('justifyRight'); - - if (document.queryCommandState("justifyRight")) { - this.classList.add('selected'); - } else { - this.classList.remove('selected'); - } - } - }, - { - icon:'format_align_justify', - onclick: function() { - document.execCommand('justifyFull'); - - if (document.queryCommandState("justifyFull")) { - this.classList.add('selected'); - } else { - this.classList.remove('selected'); - } - } - }, - { - icon:'format_list_bulleted', - onclick: function() { - document.execCommand('insertUnorderedList'); - - if (document.queryCommandState("insertUnorderedList")) { - this.classList.add('selected'); - } else { - this.classList.remove('selected'); - } - } - }*/, - ]; - }; - - jSuites.form = function (el, options) { - var obj = {}; - obj.options = {}; - - // Default configuration - var defaults = { - url: null, - message: "Are you sure? There are unsaved information in your form", - ignore: false, - currentHash: null, - submitButton: null, - validations: null, - onbeforeload: null, - onload: null, - onbeforesave: null, - onsave: null, - onbeforeremove: null, - onremove: null, - onerror: function (el, message) { - jSuites.alert(message); - }, - }; - - // Loop through our object - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - obj.options[property] = defaults[property]; - } - } - - // Validations - if (!obj.options.validations) { - obj.options.validations = {}; - } - - // Submit Button - if (!obj.options.submitButton) { - obj.options.submitButton = el.querySelector("input[type=submit]"); - } - - if (obj.options.submitButton && obj.options.url) { - obj.options.submitButton.onclick = function () { - obj.save(); - }; - } - - if (!obj.options.validations.email) { - obj.options.validations.email = jSuites.validations.email; - } - - if (!obj.options.validations.length) { - obj.options.validations.length = jSuites.validations.length; - } - - if (!obj.options.validations.required) { - obj.options.validations.required = jSuites.validations.required; - } - - obj.setUrl = function (url) { - obj.options.url = url; - }; - - obj.load = function () { - jSuites.ajax({ - url: obj.options.url, - method: "GET", - dataType: "json", - queue: true, - success: function (data) { - // Overwrite values from the backend - if (typeof obj.options.onbeforeload == "function") { - var ret = obj.options.onbeforeload(el, data); - if (ret) { - data = ret; - } - } - // Apply values to the form - jSuites.form.setElements(el, data); - // Onload methods - if (typeof obj.options.onload == "function") { - obj.options.onload(el, data); - } - }, - }); - }; - - obj.save = function () { - var test = obj.validate(); - - if (test) { - obj.options.onerror(el, test); - } else { - var data = jSuites.form.getElements(el, true); - - if (typeof obj.options.onbeforesave == "function") { - var data = obj.options.onbeforesave(el, data); - - if (data === false) { - return; - } - } - - jSuites.ajax({ - url: obj.options.url, - method: "POST", - dataType: "json", - data: data, - success: function (result) { - if (typeof obj.options.onsave == "function") { - obj.options.onsave(el, data, result); - } - }, - }); - } - }; - - obj.remove = function () { - if (typeof obj.options.onbeforeremove == "function") { - var ret = obj.options.onbeforeremove(el, obj); - if (ret === false) { - return false; - } - } - - jSuites.ajax({ - url: obj.options.url, - method: "DELETE", - dataType: "json", - success: function (result) { - if (typeof obj.options.onremove == "function") { - obj.options.onremove(el, obj, result); - } - - obj.reset(); - }, - }); - }; - - var addError = function (element) { - // Add error in the element - element.classList.add("error"); - // Submit button - if (obj.options.submitButton) { - obj.options.submitButton.setAttribute("disabled", true); - } - // Return error message - var error = - element.getAttribute("data-error") || "There is an error in the form"; - element.setAttribute("title", error); - return error; - }; - - var delError = function (element) { - var error = false; - // Remove class from this element - element.classList.remove("error"); - element.removeAttribute("title"); - // Get elements in the form - var elements = el.querySelectorAll("input, select, textarea, div[name]"); - // Run all elements - for (var i = 0; i < elements.length; i++) { - if (elements[i].getAttribute("data-validation")) { - if (elements[i].classList.contains("error")) { - error = true; - } - } - } - - if (obj.options.submitButton) { - if (error) { - obj.options.submitButton.setAttribute("disabled", true); - } else { - obj.options.submitButton.removeAttribute("disabled"); - } - } - }; - - obj.validateElement = function (element) { - // Test results - var test = false; - // Value - var value = jSuites.form.getValue(element); - // Validation - var validation = element.getAttribute("data-validation"); - // Parse - if ( - typeof obj.options.validations[validation] == "function" && - !obj.options.validations[validation](value, element) - ) { - // Not passed in the test - test = addError(element); - } else { - if (element.classList.contains("error")) { - delError(element); - } - } - - return test; - }; - - obj.reset = function () { - // Get elements in the form - var name = null; - var elements = el.querySelectorAll("input, select, textarea, div[name]"); - // Run all elements - for (var i = 0; i < elements.length; i++) { - if ((name = elements[i].getAttribute("name"))) { - if (elements[i].type == "checkbox" || elements[i].type == "radio") { - elements[i].checked = false; - } else { - if (typeof elements[i].val == "function") { - elements[i].val(""); - } else { - elements[i].value = ""; - } - } - } - } - }; - - // Run form validation - obj.validate = function () { - var test = []; - // Get elements in the form - var elements = el.querySelectorAll("input, select, textarea, div[name]"); - // Run all elements - for (var i = 0; i < elements.length; i++) { - // Required - if (elements[i].getAttribute("data-validation")) { - var res = obj.validateElement(elements[i]); - if (res) { - test.push(res); - } - } - } - if (test.length > 0) { - return test.join("
"); - } else { - return false; - } - }; - - // Check the form - obj.getError = function () { - // Validation - return obj.validation() ? true : false; - }; - - // Return the form hash - obj.setHash = function () { - return obj.getHash(jSuites.form.getElements(el)); - }; - - // Get the form hash - obj.getHash = function (str) { - var hash = 0, - i, - chr; - - if (str.length === 0) { - return hash; - } else { - for (i = 0; i < str.length; i++) { - chr = str.charCodeAt(i); - hash = (hash << 5) - hash + chr; - hash |= 0; - } - } - - return hash; - }; - - // Is there any change in the form since start tracking? - obj.isChanged = function () { - var hash = obj.setHash(); - return obj.options.currentHash != hash; - }; - - // Restart tracking - obj.resetTracker = function () { - obj.options.currentHash = obj.setHash(); - obj.options.ignore = false; - }; - - // Ignore flag - obj.setIgnore = function (ignoreFlag) { - obj.options.ignore = ignoreFlag ? true : false; - }; - - // Start tracking in one second - setTimeout(function () { - obj.options.currentHash = obj.setHash(); - }, 1000); - - // Validations - el.addEventListener("keyup", function (e) { - if (e.target.getAttribute("data-validation")) { - obj.validateElement(e.target); - } - }); - - // Alert - if (!jSuites.form.hasEvents) { - window.addEventListener("beforeunload", function (e) { - if (obj.isChanged() && obj.options.ignore == false) { - var confirmationMessage = obj.options.message - ? obj.options.message - : "o/"; - - if (confirmationMessage) { - if (typeof e == "undefined") { - e = window.event; - } - - if (e) { - e.returnValue = confirmationMessage; - } - - return confirmationMessage; - } else { - return void 0; - } - } - }); - - jSuites.form.hasEvents = true; - } - - el.form = obj; - - return obj; - }; - - // Get value from one element - jSuites.form.getValue = function (element) { - var value = null; - if (element.type == "checkbox") { - if (element.checked == true) { - value = element.value || true; - } - } else if (element.type == "radio") { - if (element.checked == true) { - value = element.value; - } - } else if (element.type == "file") { - value = element.files; - } else if (element.tagName == "select" && element.multiple == true) { - value = []; - var options = element.querySelectorAll("options[selected]"); - for (var j = 0; j < options.length; j++) { - value.push(options[j].value); - } - } else if (typeof element.val == "function") { - value = element.val(); - } else { - value = element.value || ""; - } - - return value; - }; - - // Get form elements - jSuites.form.getElements = function (el, asArray) { - var data = {}; - var name = null; - var elements = el.querySelectorAll("input, select, textarea, div[name]"); - - for (var i = 0; i < elements.length; i++) { - if ((name = elements[i].getAttribute("name"))) { - data[name] = jSuites.form.getValue(elements[i]) || ""; - } - } - - return asArray == true ? data : JSON.stringify(data); - }; - - //Get form elements - jSuites.form.setElements = function (el, data) { - var name = null; - var value = null; - var elements = el.querySelectorAll("input, select, textarea, div[name]"); - for (var i = 0; i < elements.length; i++) { - // Attributes - var type = elements[i].getAttribute("type"); - if ((name = elements[i].getAttribute("name"))) { - // Transform variable names in pathname - name = name.replace(new RegExp(/\[(.*?)\]/gi), ".$1"); - value = null; - // Seach for the data in the path - if (name.match(/\./)) { - var tmp = jSuites.path.call(data, name) || ""; - if (typeof tmp !== "undefined") { - value = tmp; - } - } else { - if (typeof data[name] !== "undefined") { - value = data[name]; - } - } - // Set the values - if (value !== null) { - if (type == "checkbox" || type == "radio") { - elements[i].checked = value ? true : false; - } else if (type == "file") { - // Do nothing - } else { - if (typeof elements[i].val == "function") { - elements[i].val(value); - } else { - elements[i].value = value; - } - } - } - } - } - }; - - // Legacy - jSuites.tracker = jSuites.form; - - jSuites.focus = function (el) { - if (el.innerText.length) { - var range = document.createRange(); - var sel = window.getSelection(); - var node = el.childNodes[el.childNodes.length - 1]; - range.setStart(node, node.length); - range.collapse(true); - sel.removeAllRanges(); - sel.addRange(range); - el.scrollLeft = el.scrollWidth; - } - }; - - jSuites.isNumeric = function (num) { - if (typeof num === "string") { - num = num.trim(); - } - return !isNaN(num) && num !== null && num !== ""; - }; - - jSuites.guid = function () { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( - /[xy]/g, - function (c) { - var r = (Math.random() * 16) | 0, - v = c == "x" ? r : (r & 0x3) | 0x8; - return v.toString(16); - } - ); - }; - - jSuites.getNode = function () { - var node = document.getSelection().anchorNode; - if (node) { - return node.nodeType == 3 ? node.parentNode : node; - } else { - return null; - } - }; - /** - * Generate hash from a string - */ - jSuites.hash = function (str) { - var hash = 0, - i, - chr; - - if (str.length === 0) { - return hash; - } else { - for (i = 0; i < str.length; i++) { - chr = str.charCodeAt(i); - if (chr > 32) { - hash = (hash << 5) - hash + chr; - hash |= 0; - } - } - } - return hash; - }; - - /** - * Generate a random color - */ - jSuites.randomColor = function (h) { - var lum = -0.25; - var hex = String( - "#" + Math.random().toString(16).slice(2, 8).toUpperCase() - ).replace(/[^0-9a-f]/gi, ""); - if (hex.length < 6) { - hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; - } - var rgb = [], - c, - i; - for (i = 0; i < 3; i++) { - c = parseInt(hex.substr(i * 2, 2), 16); - c = Math.round(Math.min(Math.max(0, c + c * lum), 255)).toString(16); - rgb.push(("00" + c).substr(c.length)); - } - - // Return hex - if (h == true) { - return ( - "#" + - jSuites.two(rgb[0].toString(16)) + - jSuites.two(rgb[1].toString(16)) + - jSuites.two(rgb[2].toString(16)) - ); - } - - return rgb; - }; - - jSuites.getWindowWidth = function () { - var w = window, - d = document, - e = d.documentElement, - g = d.getElementsByTagName("body")[0], - x = w.innerWidth || e.clientWidth || g.clientWidth; - return x; - }; - - jSuites.getWindowHeight = function () { - var w = window, - d = document, - e = d.documentElement, - g = d.getElementsByTagName("body")[0], - y = w.innerHeight || e.clientHeight || g.clientHeight; - return y; - }; - - jSuites.getPosition = function (e) { - if (e.changedTouches && e.changedTouches[0]) { - var x = e.changedTouches[0].pageX; - var y = e.changedTouches[0].pageY; - } else { - var x = window.Event - ? e.pageX - : e.clientX + - (document.documentElement.scrollLeft - ? document.documentElement.scrollLeft - : document.body.scrollLeft); - var y = window.Event - ? e.pageY - : e.clientY + - (document.documentElement.scrollTop - ? document.documentElement.scrollTop - : document.body.scrollTop); - } - - return [x, y]; - }; - - jSuites.click = function (el) { - if (el.click) { - el.click(); - } else { - var evt = new MouseEvent("click", { - bubbles: true, - cancelable: true, - view: window, - }); - el.dispatchEvent(evt); - } - }; - - jSuites.findElement = function (element, condition) { - var foundElement = false; - - function path(element) { - if (element && !foundElement) { - if (typeof condition == "function") { - foundElement = condition(element); - } else if (typeof condition == "string") { - if (element.classList && element.classList.contains(condition)) { - foundElement = element; - } - } - } - - if (element.parentNode && !foundElement) { - path(element.parentNode); - } - } - - path(element); - - return foundElement; - }; - - // Two digits - jSuites.two = function (value) { - value = "" + value; - if (value.length == 1) { - value = "0" + value; - } - return value; - }; - - jSuites.sha512 = function (str) { - function int64(msint_32, lsint_32) { - this.highOrder = msint_32; - this.lowOrder = lsint_32; - } - - var H = [ - new int64(0x6a09e667, 0xf3bcc908), - new int64(0xbb67ae85, 0x84caa73b), - new int64(0x3c6ef372, 0xfe94f82b), - new int64(0xa54ff53a, 0x5f1d36f1), - new int64(0x510e527f, 0xade682d1), - new int64(0x9b05688c, 0x2b3e6c1f), - new int64(0x1f83d9ab, 0xfb41bd6b), - new int64(0x5be0cd19, 0x137e2179), - ]; - - var K = [ - new int64(0x428a2f98, 0xd728ae22), - new int64(0x71374491, 0x23ef65cd), - new int64(0xb5c0fbcf, 0xec4d3b2f), - new int64(0xe9b5dba5, 0x8189dbbc), - new int64(0x3956c25b, 0xf348b538), - new int64(0x59f111f1, 0xb605d019), - new int64(0x923f82a4, 0xaf194f9b), - new int64(0xab1c5ed5, 0xda6d8118), - new int64(0xd807aa98, 0xa3030242), - new int64(0x12835b01, 0x45706fbe), - new int64(0x243185be, 0x4ee4b28c), - new int64(0x550c7dc3, 0xd5ffb4e2), - new int64(0x72be5d74, 0xf27b896f), - new int64(0x80deb1fe, 0x3b1696b1), - new int64(0x9bdc06a7, 0x25c71235), - new int64(0xc19bf174, 0xcf692694), - new int64(0xe49b69c1, 0x9ef14ad2), - new int64(0xefbe4786, 0x384f25e3), - new int64(0x0fc19dc6, 0x8b8cd5b5), - new int64(0x240ca1cc, 0x77ac9c65), - new int64(0x2de92c6f, 0x592b0275), - new int64(0x4a7484aa, 0x6ea6e483), - new int64(0x5cb0a9dc, 0xbd41fbd4), - new int64(0x76f988da, 0x831153b5), - new int64(0x983e5152, 0xee66dfab), - new int64(0xa831c66d, 0x2db43210), - new int64(0xb00327c8, 0x98fb213f), - new int64(0xbf597fc7, 0xbeef0ee4), - new int64(0xc6e00bf3, 0x3da88fc2), - new int64(0xd5a79147, 0x930aa725), - new int64(0x06ca6351, 0xe003826f), - new int64(0x14292967, 0x0a0e6e70), - new int64(0x27b70a85, 0x46d22ffc), - new int64(0x2e1b2138, 0x5c26c926), - new int64(0x4d2c6dfc, 0x5ac42aed), - new int64(0x53380d13, 0x9d95b3df), - new int64(0x650a7354, 0x8baf63de), - new int64(0x766a0abb, 0x3c77b2a8), - new int64(0x81c2c92e, 0x47edaee6), - new int64(0x92722c85, 0x1482353b), - new int64(0xa2bfe8a1, 0x4cf10364), - new int64(0xa81a664b, 0xbc423001), - new int64(0xc24b8b70, 0xd0f89791), - new int64(0xc76c51a3, 0x0654be30), - new int64(0xd192e819, 0xd6ef5218), - new int64(0xd6990624, 0x5565a910), - new int64(0xf40e3585, 0x5771202a), - new int64(0x106aa070, 0x32bbd1b8), - new int64(0x19a4c116, 0xb8d2d0c8), - new int64(0x1e376c08, 0x5141ab53), - new int64(0x2748774c, 0xdf8eeb99), - new int64(0x34b0bcb5, 0xe19b48a8), - new int64(0x391c0cb3, 0xc5c95a63), - new int64(0x4ed8aa4a, 0xe3418acb), - new int64(0x5b9cca4f, 0x7763e373), - new int64(0x682e6ff3, 0xd6b2b8a3), - new int64(0x748f82ee, 0x5defb2fc), - new int64(0x78a5636f, 0x43172f60), - new int64(0x84c87814, 0xa1f0ab72), - new int64(0x8cc70208, 0x1a6439ec), - new int64(0x90befffa, 0x23631e28), - new int64(0xa4506ceb, 0xde82bde9), - new int64(0xbef9a3f7, 0xb2c67915), - new int64(0xc67178f2, 0xe372532b), - new int64(0xca273ece, 0xea26619c), - new int64(0xd186b8c7, 0x21c0c207), - new int64(0xeada7dd6, 0xcde0eb1e), - new int64(0xf57d4f7f, 0xee6ed178), - new int64(0x06f067aa, 0x72176fba), - new int64(0x0a637dc5, 0xa2c898a6), - new int64(0x113f9804, 0xbef90dae), - new int64(0x1b710b35, 0x131c471b), - new int64(0x28db77f5, 0x23047d84), - new int64(0x32caab7b, 0x40c72493), - new int64(0x3c9ebe0a, 0x15c9bebc), - new int64(0x431d67c4, 0x9c100d4c), - new int64(0x4cc5d4be, 0xcb3e42b6), - new int64(0x597f299c, 0xfc657e2a), - new int64(0x5fcb6fab, 0x3ad6faec), - new int64(0x6c44198c, 0x4a475817), - ]; - - var W = new Array(64); - var a, b, c, d, e, f, g, h, i, j; - var T1, T2; - var charsize = 8; - - function utf8_encode(str) { - return unescape(encodeURIComponent(str)); - } - - function str2binb(str) { - var bin = []; - var mask = (1 << charsize) - 1; - var len = str.length * charsize; - - for (var i = 0; i < len; i += charsize) { - bin[i >> 5] |= - (str.charCodeAt(i / charsize) & mask) << (32 - charsize - (i % 32)); - } - - return bin; - } - - function binb2hex(binarray) { - var hex_tab = "0123456789abcdef"; - var str = ""; - var length = binarray.length * 4; - var srcByte; - - for (var i = 0; i < length; i += 1) { - srcByte = binarray[i >> 2] >> ((3 - (i % 4)) * 8); - str += - hex_tab.charAt((srcByte >> 4) & 0xf) + hex_tab.charAt(srcByte & 0xf); - } - - return str; - } - - function safe_add_2(x, y) { - var lsw, msw, lowOrder, highOrder; - - lsw = (x.lowOrder & 0xffff) + (y.lowOrder & 0xffff); - msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16); - lowOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); - - lsw = (x.highOrder & 0xffff) + (y.highOrder & 0xffff) + (msw >>> 16); - msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16); - highOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); - - return new int64(highOrder, lowOrder); - } - - function safe_add_4(a, b, c, d) { - var lsw, msw, lowOrder, highOrder; - - lsw = - (a.lowOrder & 0xffff) + - (b.lowOrder & 0xffff) + - (c.lowOrder & 0xffff) + - (d.lowOrder & 0xffff); - msw = - (a.lowOrder >>> 16) + - (b.lowOrder >>> 16) + - (c.lowOrder >>> 16) + - (d.lowOrder >>> 16) + - (lsw >>> 16); - lowOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); - - lsw = - (a.highOrder & 0xffff) + - (b.highOrder & 0xffff) + - (c.highOrder & 0xffff) + - (d.highOrder & 0xffff) + - (msw >>> 16); - msw = - (a.highOrder >>> 16) + - (b.highOrder >>> 16) + - (c.highOrder >>> 16) + - (d.highOrder >>> 16) + - (lsw >>> 16); - highOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); - - return new int64(highOrder, lowOrder); - } - - function safe_add_5(a, b, c, d, e) { - var lsw, msw, lowOrder, highOrder; - - lsw = - (a.lowOrder & 0xffff) + - (b.lowOrder & 0xffff) + - (c.lowOrder & 0xffff) + - (d.lowOrder & 0xffff) + - (e.lowOrder & 0xffff); - msw = - (a.lowOrder >>> 16) + - (b.lowOrder >>> 16) + - (c.lowOrder >>> 16) + - (d.lowOrder >>> 16) + - (e.lowOrder >>> 16) + - (lsw >>> 16); - lowOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); - - lsw = - (a.highOrder & 0xffff) + - (b.highOrder & 0xffff) + - (c.highOrder & 0xffff) + - (d.highOrder & 0xffff) + - (e.highOrder & 0xffff) + - (msw >>> 16); - msw = - (a.highOrder >>> 16) + - (b.highOrder >>> 16) + - (c.highOrder >>> 16) + - (d.highOrder >>> 16) + - (e.highOrder >>> 16) + - (lsw >>> 16); - highOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); - - return new int64(highOrder, lowOrder); - } - - function maj(x, y, z) { - return new int64( - (x.highOrder & y.highOrder) ^ - (x.highOrder & z.highOrder) ^ - (y.highOrder & z.highOrder), - (x.lowOrder & y.lowOrder) ^ - (x.lowOrder & z.lowOrder) ^ - (y.lowOrder & z.lowOrder) - ); - } - - function ch(x, y, z) { - return new int64( - (x.highOrder & y.highOrder) ^ (~x.highOrder & z.highOrder), - (x.lowOrder & y.lowOrder) ^ (~x.lowOrder & z.lowOrder) - ); - } - - function rotr(x, n) { - if (n <= 32) { - return new int64( - (x.highOrder >>> n) | (x.lowOrder << (32 - n)), - (x.lowOrder >>> n) | (x.highOrder << (32 - n)) - ); - } else { - return new int64( - (x.lowOrder >>> n) | (x.highOrder << (32 - n)), - (x.highOrder >>> n) | (x.lowOrder << (32 - n)) - ); - } - } - - function sigma0(x) { - var rotr28 = rotr(x, 28); - var rotr34 = rotr(x, 34); - var rotr39 = rotr(x, 39); - - return new int64( - rotr28.highOrder ^ rotr34.highOrder ^ rotr39.highOrder, - rotr28.lowOrder ^ rotr34.lowOrder ^ rotr39.lowOrder - ); - } - - function sigma1(x) { - var rotr14 = rotr(x, 14); - var rotr18 = rotr(x, 18); - var rotr41 = rotr(x, 41); - - return new int64( - rotr14.highOrder ^ rotr18.highOrder ^ rotr41.highOrder, - rotr14.lowOrder ^ rotr18.lowOrder ^ rotr41.lowOrder - ); - } - - function gamma0(x) { - var rotr1 = rotr(x, 1), - rotr8 = rotr(x, 8), - shr7 = shr(x, 7); - - return new int64( - rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder, - rotr1.lowOrder ^ rotr8.lowOrder ^ shr7.lowOrder - ); - } - - function gamma1(x) { - var rotr19 = rotr(x, 19); - var rotr61 = rotr(x, 61); - var shr6 = shr(x, 6); - - return new int64( - rotr19.highOrder ^ rotr61.highOrder ^ shr6.highOrder, - rotr19.lowOrder ^ rotr61.lowOrder ^ shr6.lowOrder - ); - } - - function shr(x, n) { - if (n <= 32) { - return new int64( - x.highOrder >>> n, - (x.lowOrder >>> n) | (x.highOrder << (32 - n)) - ); - } else { - return new int64(0, x.highOrder << (32 - n)); - } - } - - var str = utf8_encode(str); - var strlen = str.length * charsize; - str = str2binb(str); - - str[strlen >> 5] |= 0x80 << (24 - (strlen % 32)); - str[(((strlen + 128) >> 10) << 5) + 31] = strlen; - - for (var i = 0; i < str.length; i += 32) { - a = H[0]; - b = H[1]; - c = H[2]; - d = H[3]; - e = H[4]; - f = H[5]; - g = H[6]; - h = H[7]; - - for (var j = 0; j < 80; j++) { - if (j < 16) { - W[j] = new int64(str[j * 2 + i], str[j * 2 + i + 1]); - } else { - W[j] = safe_add_4( - gamma1(W[j - 2]), - W[j - 7], - gamma0(W[j - 15]), - W[j - 16] - ); - } - - T1 = safe_add_5(h, sigma1(e), ch(e, f, g), K[j], W[j]); - T2 = safe_add_2(sigma0(a), maj(a, b, c)); - h = g; - g = f; - f = e; - e = safe_add_2(d, T1); - d = c; - c = b; - b = a; - a = safe_add_2(T1, T2); - } - - H[0] = safe_add_2(a, H[0]); - H[1] = safe_add_2(b, H[1]); - H[2] = safe_add_2(c, H[2]); - H[3] = safe_add_2(d, H[3]); - H[4] = safe_add_2(e, H[4]); - H[5] = safe_add_2(f, H[5]); - H[6] = safe_add_2(g, H[6]); - H[7] = safe_add_2(h, H[7]); - } - - var binarray = []; - for (var i = 0; i < H.length; i++) { - binarray.push(H[i].highOrder); - binarray.push(H[i].lowOrder); - } - - return binb2hex(binarray); - }; - - if (!jSuites.login) { - jSuites.login = {}; - jSuites.login.sha512 = jSuites.sha512; - } - - jSuites.image = jSuites.upload = function (el, options) { - var obj = {}; - obj.options = {}; - - // Default configuration - var defaults = { - type: "image", - extension: "*", - input: false, - minWidth: false, - maxWidth: null, - maxHeight: null, - maxJpegSizeBytes: null, // For example, 350Kb would be 350000 - onchange: null, - multiple: false, - remoteParser: null, - text: { - extensionNotAllowed: "The extension is not allowed", - }, - }; - - // Loop through our object - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - obj.options[property] = defaults[property]; - } - } - - // Multiple - if (obj.options.multiple == true) { - el.setAttribute("data-multiple", true); - } - - // Container - el.content = []; - - // Upload icon - el.classList.add("jupload"); - - if (obj.options.input == true) { - el.classList.add("input"); - } - - obj.add = function (data) { - // Reset container for single files - if (obj.options.multiple == false) { - el.content = []; - el.innerText = ""; - } - - // Append to the element - if (obj.options.type == "image") { - var img = document.createElement("img"); - img.setAttribute("src", data.file); - img.setAttribute("tabindex", -1); - if (!el.getAttribute("name")) { - img.className = "jfile"; - img.content = data; - } - el.appendChild(img); - } else { - if (data.name) { - var name = data.name; - } else { - var name = data.file; - } - var div = document.createElement("div"); - div.innerText = name || obj.options.type; - div.classList.add("jupload-item"); - div.setAttribute("tabindex", -1); - el.appendChild(div); - } - - if (data.content) { - data.file = jSuites.guid(); - } - - // Push content - el.content.push(data); - - // Onchange - if (typeof obj.options.onchange == "function") { - obj.options.onchange(el, data); - } - }; - - obj.addFromFile = function (file) { - var type = file.type.split("/"); - if (type[0] == obj.options.type) { - var readFile = new FileReader(); - readFile.addEventListener("load", function (v) { - var data = { - file: v.srcElement.result, - extension: file.name.substr(file.name.lastIndexOf(".") + 1), - name: file.name, - size: file.size, - lastmodified: file.lastModified, - content: v.srcElement.result, - }; - - obj.add(data); - }); - - readFile.readAsDataURL(file); - } else { - alert(obj.options.text.extensionNotAllowed); - } - }; - - obj.addFromUrl = function (src) { - if (src.substr(0, 4) != "data" && !obj.options.remoteParser) { - console.error("remoteParser not defined in your initialization"); - } else { - // This is to process cross domain images - if (src.substr(0, 4) == "data") { - var extension = src.split(";"); - extension = extension[0].split("/"); - var type = extension[0].replace("data:", ""); - if (type == obj.options.type) { - var data = { - file: src, - name: "", - extension: extension[1], - content: src, - }; - obj.add(data); - } else { - alert(obj.options.text.extensionNotAllowed); - } - } else { - var extension = src.substr(src.lastIndexOf(".") + 1); - // Work for cross browsers - src = obj.options.remoteParser + src; - // Get remove content - jSuites.ajax({ - url: src, - type: "GET", - dataType: "blob", - success: function (data) { - //add(extension[0].replace('data:',''), data); - }, - }); - } - } - }; - - var getDataURL = function (canvas, type) { - var compression = 0.92; - var lastContentLength = null; - var content = canvas.toDataURL(type, compression); - while ( - obj.options.maxJpegSizeBytes && - type === "image/jpeg" && - content.length > obj.options.maxJpegSizeBytes && - content.length !== lastContentLength - ) { - // Apply the compression - compression *= 0.9; - lastContentLength = content.length; - content = canvas.toDataURL(type, compression); - } - return content; - }; - - var mime = obj.options.type + "/" + obj.options.extension; - var input = document.createElement("input"); - input.type = "file"; - input.setAttribute("accept", mime); - input.onchange = function () { - for (var i = 0; i < this.files.length; i++) { - obj.addFromFile(this.files[i]); - } - }; - - // Allow multiple files - if (obj.options.multiple == true) { - input.setAttribute("multiple", true); - } - - var current = null; - - el.addEventListener("click", function (e) { - current = null; - if (!el.children.length || e.target === el) { - jSuites.click(input); - } else { - if (e.target.parentNode == el) { - current = e.target; - } - } - }); - - el.addEventListener("dblclick", function (e) { - jSuites.click(input); - }); - - el.addEventListener("dragenter", function (e) { - el.style.border = "1px dashed #000"; - }); - - el.addEventListener("dragleave", function (e) { - el.style.border = "1px solid #eee"; - }); - - el.addEventListener("dragstop", function (e) { - el.style.border = "1px solid #eee"; - }); - - el.addEventListener("dragover", function (e) { - e.preventDefault(); - }); - - el.addEventListener("keydown", function (e) { - if (current && e.which == 46) { - var index = Array.prototype.indexOf.call(el.children, current); - if (index >= 0) { - el.content.splice(index, 1); - current.remove(); - current = null; - } - } - }); - - el.addEventListener("drop", function (e) { - e.preventDefault(); - e.stopPropagation(); - - var html = (e.originalEvent || e).dataTransfer.getData("text/html"); - var file = (e.originalEvent || e).dataTransfer.files; - - if (file.length) { - for (var i = 0; i < e.dataTransfer.files.length; i++) { - obj.addFromFile(e.dataTransfer.files[i]); - } - } else if (html) { - if (obj.options.multiple == false) { - el.innerText = ""; - } - - // Create temp element - var div = document.createElement("div"); - div.innerHTML = html; - - // Extract images - var img = div.querySelectorAll("img"); - - if (img.length) { - for (var i = 0; i < img.length; i++) { - obj.addFromUrl(img[i].src); - } - } - } - - el.style.border = "1px solid #eee"; - - return false; - }); - - el.val = function (val) { - if (val === undefined) { - return el.content && el.content.length ? el.content : null; - } else { - // Reset - el.innerText = ""; - el.content = []; - - if (val) { - if (Array.isArray(val)) { - for (var i = 0; i < val.length; i++) { - if (typeof val[i] == "string") { - obj.add({ file: val[i] }); - } else { - obj.add(val[i]); - } - } - } else if (typeof val == "string") { - obj.add({ file: val }); - } - } - } - }; - - el.upload = el.image = obj; - - return obj; - }; - - jSuites.image.create = function (data) { - var img = document.createElement("img"); - img.setAttribute("src", data.file); - img.className = "jfile"; - img.setAttribute("tabindex", -1); - img.content = data; - - return img; - }; - - jSuites.lazyLoading = function (el, options) { - var obj = {}; - - // Mandatory options - if (!options.loadUp || typeof options.loadUp != "function") { - options.loadUp = function () { - return false; - }; - } - if (!options.loadDown || typeof options.loadDown != "function") { - options.loadDown = function () { - return false; - }; - } - // Timer ms - if (!options.timer) { - options.timer = 100; - } - - // Timer - var timeControlLoading = null; - - // Controls - var scrollControls = function (e) { - if (timeControlLoading == null) { - var event = false; - var scrollTop = el.scrollTop; - if (el.scrollTop + el.clientHeight * 2 >= el.scrollHeight) { - if (options.loadDown()) { - if (scrollTop == el.scrollTop) { - el.scrollTop = el.scrollTop - el.clientHeight; - } - event = true; - } - } else if (el.scrollTop <= el.clientHeight) { - if (options.loadUp()) { - if (scrollTop == el.scrollTop) { - el.scrollTop = el.scrollTop + el.clientHeight; - } - event = true; - } - } - - timeControlLoading = setTimeout(function () { - timeControlLoading = null; - }, options.timer); - - if (event) { - if (typeof options.onupdate == "function") { - options.onupdate(); - } - } - } - }; - - // Onscroll - el.onscroll = function (e) { - scrollControls(e); - }; - - el.onwheel = function (e) { - scrollControls(e); - }; - - return obj; - }; - - jSuites.loading = (function () { - var obj = {}; - - var loading = null; - - obj.show = function () { - if (!loading) { - loading = document.createElement("div"); - loading.className = "jloading"; - } - document.body.appendChild(loading); - }; - - obj.hide = function () { - if (loading && loading.parentNode) { - document.body.removeChild(loading); - } - }; - - return obj; - })(); - - jSuites.mask = (function () { - // Currency - var tokens = { - // Text - text: ["@"], - // Currency tokens - currency: ["#(.{1})##0?(.{1}0+)?( ?;(.*)?)?", "#"], - // Percentage - percentage: ["0{1}(.{1}0+)?%"], - // Number - numeric: ["0{1}(.{1}0+)?"], - // Data tokens - datetime: [ - "YYYY", - "YYY", - "YY", - "MMMMM", - "MMMM", - "MMM", - "MM", - "DDDDD", - "DDDD", - "DDD", - "DD", - "DY", - "DAY", - "WD", - "D", - "Q", - "HH24", - "HH12", - "HH", - "\\[H\\]", - "H", - "AM/PM", - "PM", - "AM", - "MI", - "SS", - "MS", - "MONTH", - "MON", - "Y", - "M", - ], - // Other - general: ["A", "0", "[0-9a-zA-Z$]+", "."], - }; - - var getDate = function () { - if (this.mask.toLowerCase().indexOf("[h]") !== -1) { - var m = 0; - if (this.date[4]) { - m = parseFloat(this.date[4] / 60); - } - var v = parseInt(this.date[3]) + m; - v /= 24; - } else if ( - !(this.date[0] && this.date[1] && this.date[2]) && - (this.date[3] || this.date[4]) - ) { - v = - jSuites.two(this.date[3]) + - ":" + - jSuites.two(this.date[4]) + - ":" + - jSuites.two(this.date[5]); - } else { - if (this.date[0] && this.date[1] && !this.date[2]) { - this.date[2] = 1; - } - v = - jSuites.two(this.date[0]) + - "-" + - jSuites.two(this.date[1]) + - "-" + - jSuites.two(this.date[2]); - - if (this.date[3] || this.date[4] || this.date[5]) { - v += - " " + - jSuites.two(this.date[3]) + - ":" + - jSuites.two(this.date[4]) + - ":" + - jSuites.two(this.date[5]); - } - } - - return v; - }; - - var isBlank = function (v) { - return v === null || v === "" || v === undefined ? true : false; - }; - - var isFormula = function (value) { - return ("" + value).chartAt(0) == "="; - }; - - var isNumeric = function (t) { - return t === "currency" || t === "percentage" || t === "numeric" - ? true - : false; - }; - /** - * Get the decimal defined in the mask configuration - */ - var getDecimal = function (v) { - if (v && Number(v) == v) { - return "."; - } else { - if (this.options.decimal) { - return this.options.decimal; - } else { - if (this.locale) { - var t = Intl.NumberFormat(this.locale).format(1.1); - return (this.options.decimal = t[1]); - } else { - if (!v) { - v = this.mask; - } - var e = new RegExp("0{1}(.{1})0+", "ig"); - var t = e.exec(v); - if (t && t[1] && t[1].length == 1) { - // Save decimal - this.options.decimal = t[1]; - // Return decimal - return t[1]; - } else { - // Did not find any decimal last resort the default - var e = new RegExp("#{1}(.{1})#+", "ig"); - var t = e.exec(v); - if (t && t[1] && t[1].length == 1) { - if (t[1] === ",") { - this.options.decimal = "."; - } else { - this.options.decimal = ","; - } - } else { - this.options.decimal = "1.1".toLocaleString().substring(1, 2); - } - } - } - } - } - - if (this.options.decimal) { - return this.options.decimal; - } else { - return null; - } - }; - - var ParseValue = function (v, decimal) { - if (v == "") { - return ""; - } - - // Get decimal - if (!decimal) { - decimal = getDecimal.call(this); - } - - // New value - v = ("" + v).split(decimal); - - // Signal - var signal = v[0].match(/[-]+/g); - if (signal && signal.length) { - signal = true; - } else { - signal = false; - } - - v[0] = v[0].match(/[0-9]+/g); - - if (v[0]) { - if (signal) { - v[0].unshift("-"); - } - v[0] = v[0].join(""); - } else { - if (signal) { - v[0] = "-"; - } - } - - if (v[0] || v[1]) { - if (v[1] !== undefined) { - v[1] = v[1].match(/[0-9]+/g); - if (v[1]) { - v[1] = v[1].join(""); - } else { - v[1] = ""; - } - } - } else { - return ""; - } - return v; - }; - - var FormatValue = function (v, event) { - if (v == "") { - return ""; - } - // Get decimal - var d = getDecimal.call(this); - // Convert value - var o = this.options; - // Parse value - v = ParseValue.call(this, v); - if (v == "") { - return ""; - } - // Temporary value - if (v[0]) { - var t = parseFloat(v[0] + ".1"); - if (o.style == "percent") { - t /= 100; - } - } else { - var t = null; - } - - if ( - (v[0] == "-" || v[0] == "-00") && - !v[1] && - event && - event.inputType == "deleteContentBackward" - ) { - return ""; - } - - var n = new Intl.NumberFormat(this.locale, o).format(t); - n = n.split(d); - if (typeof n[1] !== "undefined") { - var s = n[1].replace(/[0-9]*/g, ""); - if (s) { - n[2] = s; - } - } - - if (v[1] !== undefined) { - n[1] = d + v[1]; - } else { - n[1] = ""; - } - - return n.join(""); - }; - - var Format = function (e, event) { - var v = Value.call(e); - if (!v) { - return; - } - - // Get decimal - var d = getDecimal.call(this); - var n = FormatValue.call(this, v, event); - var t = n.length - v.length; - var index = Caret.call(e) + t; - // Set value and update caret - Value.call(e, n, index, true); - }; - - var Extract = function (v) { - // Keep the raw value - var current = ParseValue.call(this, v); - if (current) { - // Negative values - if (current[0] === "-") { - current[0] = "-0"; - } - return parseFloat(current.join(".")); - } - return null; - }; - - /** - * Caret getter and setter methods - */ - var Caret = function (index, adjustNumeric) { - if (index === undefined) { - if (this.tagName == "DIV") { - var pos = 0; - var s = window.getSelection(); - if (s) { - if (s.rangeCount !== 0) { - var r = s.getRangeAt(0); - var p = r.cloneRange(); - p.selectNodeContents(this); - p.setEnd(r.endContainer, r.endOffset); - pos = p.toString().length; - } - } - return pos; - } else { - return this.selectionStart; - } - } else { - // Get the current value - var n = Value.call(this); - - // Review the position - if (adjustNumeric) { - var p = null; - for (var i = 0; i < n.length; i++) { - if (n[i].match(/[\-0-9]/g) || n[i] == "." || n[i] == ",") { - p = i; - } - } - - // If the string has no numbers - if (p === null) { - p = n.indexOf(" "); - } - - if (index >= p) { - index = p + 1; - } - } - - // Do not update caret - if (index > n.length) { - index = n.length; - } - - if (index) { - // Set caret - if (this.tagName == "DIV") { - var s = window.getSelection(); - var r = document.createRange(); - - if (this.childNodes[0]) { - r.setStart(this.childNodes[0], index); - s.removeAllRanges(); - s.addRange(r); - } - } else { - this.selectionStart = index; - this.selectionEnd = index; - } - } - } - }; - - /** - * Value getter and setter method - */ - var Value = function (v, updateCaret, adjustNumeric) { - if (this.tagName == "DIV") { - if (v === undefined) { - var v = this.innerText; - if (this.value && this.value.length > v.length) { - v = this.value; - } - return v; - } else { - if (this.innerText !== v) { - this.innerText = v; - - if (updateCaret) { - Caret.call(this, updateCaret, adjustNumeric); - } - } - } - } else { - if (v === undefined) { - return this.value; - } else { - if (this.value !== v) { - this.value = v; - if (updateCaret) { - Caret.call(this, updateCaret, adjustNumeric); - } - } - } - } - }; - - // Labels - var weekDaysFull = jSuites.calendar.weekdays; - var weekDays = jSuites.calendar.weekdaysShort; - var monthsFull = jSuites.calendar.months; - var months = jSuites.calendar.monthsShort; - - var parser = { - YEAR: function (v, s) { - var y = "" + new Date().getFullYear(); - - if (typeof this.values[this.index] === "undefined") { - this.values[this.index] = ""; - } - if (parseInt(v) >= 0 && parseInt(v) <= 10) { - if (this.values[this.index].length < s) { - this.values[this.index] += v; - } - } - if (this.values[this.index].length == s) { - if (s == 2) { - var y = y.substr(0, 2) + this.values[this.index]; - } else if (s == 3) { - var y = y.substr(0, 1) + this.values[this.index]; - } else if (s == 4) { - var y = this.values[this.index]; - } - this.date[0] = y; - this.index++; - } - }, - YYYY: function (v) { - parser.YEAR.call(this, v, 4); - }, - YYY: function (v) { - parser.YEAR.call(this, v, 3); - }, - YY: function (v) { - parser.YEAR.call(this, v, 2); - }, - FIND: function (v, a) { - if (isBlank(this.values[this.index])) { - this.values[this.index] = ""; - } - var pos = 0; - var count = 0; - var value = (this.values[this.index] + v).toLowerCase(); - for (var i = 0; i < a.length; i++) { - if (a[i].toLowerCase().indexOf(value) == 0) { - pos = i; - count++; - } - } - if (count > 1) { - this.values[this.index] += v; - } else if (count == 1) { - // Jump number of chars - var t = a[pos].length - this.values[this.index].length - 1; - this.position += t; - - this.values[this.index] = a[pos]; - this.index++; - return pos; - } - }, - MMM: function (v) { - var ret = parser.FIND.call(this, v, months); - if (ret !== undefined) { - this.date[1] = ret + 1; - } - }, - MMMM: function (v) { - var ret = parser.FIND.call(this, v, monthsFull); - if (ret !== undefined) { - this.date[1] = ret + 1; - } - }, - MMMMM: function (v) { - if (isBlank(this.values[this.index])) { - this.values[this.index] = ""; - } - var pos = 0; - var count = 0; - var value = (this.values[this.index] + v).toLowerCase(); - for (var i = 0; i < monthsFull.length; i++) { - if (monthsFull[i][0].toLowerCase().indexOf(value) == 0) { - this.values[this.index] = monthsFull[i][0]; - this.date[1] = i + 1; - this.index++; - break; - } - } - }, - MM: function (v) { - if (isBlank(this.values[this.index])) { - if (parseInt(v) > 1 && parseInt(v) < 10) { - this.date[1] = this.values[this.index] = "0" + v; - this.index++; - } else if (parseInt(v) < 2) { - this.values[this.index] = v; - } - } else { - if (this.values[this.index] == 1 && parseInt(v) < 3) { - this.date[1] = this.values[this.index] += v; - this.index++; - } else if ( - this.values[this.index] == 0 && - parseInt(v) > 0 && - parseInt(v) < 10 - ) { - this.date[1] = this.values[this.index] += v; - this.index++; - } - } - }, - M: function (v) { - var test = false; - if (parseInt(v) >= 0 && parseInt(v) < 10) { - if (isBlank(this.values[this.index])) { - this.values[this.index] = v; - if (v > 1) { - this.date[1] = this.values[this.index]; - this.index++; - } - } else { - if (this.values[this.index] == 1 && parseInt(v) < 3) { - this.date[1] = this.values[this.index] += v; - this.index++; - } else if (this.values[this.index] == 0 && parseInt(v) > 0) { - this.date[1] = this.values[this.index] += v; - this.index++; - } else { - var test = true; - } - } - } else { - var test = true; - } - - // Re-test - if (test == true) { - var t = parseInt(this.values[this.index]); - if (t > 0 && t < 12) { - this.date[2] = this.values[this.index]; - this.index++; - // Repeat the character - this.position--; - } - } - }, - D: function (v) { - var test = false; - if (parseInt(v) >= 0 && parseInt(v) < 10) { - if (isBlank(this.values[this.index])) { - this.values[this.index] = v; - if (parseInt(v) > 3) { - this.date[2] = this.values[this.index]; - this.index++; - } - } else { - if (this.values[this.index] == 3 && parseInt(v) < 2) { - this.date[2] = this.values[this.index] += v; - this.index++; - } else if ( - this.values[this.index] == 1 || - this.values[this.index] == 2 - ) { - this.date[2] = this.values[this.index] += v; - this.index++; - } else if (this.values[this.index] == 0 && parseInt(v) > 0) { - this.date[2] = this.values[this.index] += v; - this.index++; - } else { - var test = true; - } - } - } else { - var test = true; - } - - // Re-test - if (test == true) { - var t = parseInt(this.values[this.index]); - if (t > 0 && t < 32) { - this.date[2] = this.values[this.index]; - this.index++; - // Repeat the character - this.position--; - } - } - }, - DD: function (v) { - if (isBlank(this.values[this.index])) { - if (parseInt(v) > 3 && parseInt(v) < 10) { - this.date[2] = this.values[this.index] = "0" + v; - this.index++; - } else if (parseInt(v) < 10) { - this.values[this.index] = v; - } - } else { - if (this.values[this.index] == 3 && parseInt(v) < 2) { - this.date[2] = this.values[this.index] += v; - this.index++; - } else if ( - (this.values[this.index] == 1 || this.values[this.index] == 2) && - parseInt(v) < 10 - ) { - this.date[2] = this.values[this.index] += v; - this.index++; - } else if ( - this.values[this.index] == 0 && - parseInt(v) > 0 && - parseInt(v) < 10 - ) { - this.date[2] = this.values[this.index] += v; - this.index++; - } - } - }, - DDD: function (v) { - parser.FIND.call(this, v, weekDays); - }, - DDDD: function (v) { - parser.FIND.call(this, v, weekDaysFull); - }, - HH12: function (v, two) { - if (isBlank(this.values[this.index])) { - if (parseInt(v) > 1 && parseInt(v) < 10) { - if (two) { - v = 0 + v; - } - this.date[3] = this.values[this.index] = v; - this.index++; - } else if (parseInt(v) < 10) { - this.values[this.index] = v; - } - } else { - if (this.values[this.index] == 1 && parseInt(v) < 3) { - this.date[3] = this.values[this.index] += v; - this.index++; - } else if (this.values[this.index] < 1 && parseInt(v) < 10) { - this.date[3] = this.values[this.index] += v; - this.index++; - } - } - }, - HH24: function (v, two) { - var test = false; - if (parseInt(v) >= 0 && parseInt(v) < 10) { - if ( - this.values[this.index] == null || - this.values[this.index] == "" - ) { - if (parseInt(v) > 2 && parseInt(v) < 10) { - if (two) { - v = 0 + v; - } - this.date[3] = this.values[this.index] = v; - this.index++; - } else if (parseInt(v) < 10) { - this.values[this.index] = v; - } - } else { - if (this.values[this.index] == 2 && parseInt(v) < 4) { - this.date[3] = this.values[this.index] += v; - this.index++; - } else if (this.values[this.index] < 2 && parseInt(v) < 10) { - this.date[3] = this.values[this.index] += v; - this.index++; - } - } - } - }, - HH: function (v) { - parser["HH24"].call(this, v, 1); - }, - H: function (v) { - parser["HH24"].call(this, v, 0); - }, - "\\[H\\]": function (v) { - if (this.values[this.index] == undefined) { - this.values[this.index] = ""; - } - if (v.match(/[0-9]/g)) { - this.date[3] = this.values[this.index] += v; - } else { - if (this.values[this.index].match(/[0-9]/g)) { - this.date[3] = this.values[this.index]; - this.index++; - // Repeat the character - this.position--; - } - } - }, - N60: function (v, i) { - if (this.values[this.index] == null || this.values[this.index] == "") { - if (parseInt(v) > 5 && parseInt(v) < 10) { - this.date[i] = this.values[this.index] = "0" + v; - this.index++; - } else if (parseInt(v) < 10) { - this.values[this.index] = v; - } - } else { - if (parseInt(v) < 10) { - this.date[i] = this.values[this.index] += v; - this.index++; - } - } - }, - MI: function (v) { - parser.N60.call(this, v, 4); - }, - SS: function (v) { - parser.N60.call(this, v, 5); - }, - "AM/PM": function (v) { - this.values[this.index] = ""; - if (v) { - if (this.date[3] > 12) { - this.values[this.index] = "PM"; - } else { - this.values[this.index] = "AM"; - } - } - this.index++; - }, - WD: function (v) { - if (typeof this.values[this.index] === "undefined") { - this.values[this.index] = ""; - } - if (parseInt(v) >= 0 && parseInt(v) < 7) { - this.values[this.index] = v; - } - if (this.value[this.index].length == 1) { - this.index++; - } - }, - "0{1}(.{1}0+)?": function (v) { - // Get decimal - var decimal = getDecimal.call(this); - // Negative number - var neg = false; - // Create if is blank - if (isBlank(this.values[this.index])) { - this.values[this.index] = ""; - } else { - if (this.values[this.index] == "-") { - neg = true; - } - } - var current = ParseValue.call(this, this.values[this.index], decimal); - if (current) { - this.values[this.index] = current.join(decimal); - } - // New entry - if (parseInt(v) >= 0 && parseInt(v) < 10) { - // Replace the zero for a number - if (this.values[this.index] == "0" && v > 0) { - this.values[this.index] = ""; - } else if (this.values[this.index] == "-0" && v > 0) { - this.values[this.index] = "-"; - } - // Don't add up zeros because does not mean anything here - if ( - (this.values[this.index] != "0" && - this.values[this.index] != "-0") || - v == decimal - ) { - this.values[this.index] += v; - } - } else if (decimal && v == decimal) { - if (this.values[this.index].indexOf(decimal) == -1) { - if (!this.values[this.index]) { - this.values[this.index] = "0"; - } - this.values[this.index] += v; - } - } else if (v == "-") { - // Negative signed - neg = true; - } - - if (neg === true && this.values[this.index][0] !== "-") { - this.values[this.index] = "-" + this.values[this.index]; - } - }, - "0{1}(.{1}0+)?%": function (v) { - parser["0{1}(.{1}0+)?"].call(this, v); - - if (this.values[this.index].match(/[\-0-9]/g)) { - if ( - this.values[this.index] && - this.values[this.index].indexOf("%") == -1 - ) { - this.values[this.index] += "%"; - } - } else { - this.values[this.index] = ""; - } - }, - "#(.{1})##0?(.{1}0+)?( ?;(.*)?)?": function (v) { - // Parse number - parser["0{1}(.{1}0+)?"].call(this, v); - // Get decimal - var decimal = getDecimal.call(this); - // Get separator - var separator = this.tokens[this.index].substr(1, 1); - // Negative - var negative = this.values[this.index][0] === "-" ? true : false; - // Current value - var current = ParseValue.call(this, this.values[this.index], decimal); - - // Get main and decimal parts - if (current !== "") { - // Format number - var n = current[0].match(/[0-9]/g); - if (n) { - // Format - n = n.join(""); - var t = []; - var s = 0; - for (var j = n.length - 1; j >= 0; j--) { - t.push(n[j]); - s++; - if (!(s % 3)) { - t.push(separator); - } - } - t = t.reverse(); - current[0] = t.join(""); - if (current[0].substr(0, 1) == separator) { - current[0] = current[0].substr(1); - } - } else { - current[0] = ""; - } - - // Value - this.values[this.index] = current.join(decimal); - - // Negative - if (negative) { - this.values[this.index] = "-" + this.values[this.index]; - } - } - }, - 0: function (v) { - if (v.match(/[0-9]/g)) { - this.values[this.index] = v; - this.index++; - } - }, - "[0-9a-zA-Z$]+": function (v) { - if (isBlank(this.values[this.index])) { - this.values[this.index] = ""; - } - var t = this.tokens[this.index]; - var s = this.values[this.index]; - var i = s.length; - - if (t[i] == v) { - this.values[this.index] += v; - - if (this.values[this.index] == t) { - this.index++; - } - } else { - this.values[this.index] = t; - this.index++; - - if (v.match(/[\-0-9]/g)) { - // Repeat the character - this.position--; - } - } - }, - A: function (v) { - if (v.match(/[a-zA-Z]/gi)) { - this.values[this.index] = v; - this.index++; - } - }, - ".": function (v) { - parser["[0-9a-zA-Z$]+"].call(this, v); - }, - "@": function (v) { - if (isBlank(this.values[this.index])) { - this.values[this.index] = ""; - } - this.values[this.index] += v; - }, - }; - - /** - * Get the tokens in the mask string - */ - var getTokens = function (str) { - if (this.type == "general") { - var t = [].concat(tokens.general); - } else { - var t = [].concat( - tokens.currency, - tokens.datetime, - tokens.percentage, - tokens.numeric, - tokens.text, - tokens.general - ); - } - // Expression to extract all tokens from the string - var e = new RegExp(t.join("|"), "gi"); - // Extract - return str.match(e); - }; - - /** - * Get the method of one given token - */ - var getMethod = function (str) { - if (!this.type) { - var types = Object.keys(tokens); - } else if (this.type == "text") { - var types = ["text"]; - } else if (this.type == "general") { - var types = ["general"]; - } else if (this.type == "datetime") { - var types = ["numeric", "datetime", "general"]; - } else { - var types = ["currency", "percentage", "numeric", "general"]; - } - - // Found - for (var i = 0; i < types.length; i++) { - var type = types[i]; - for (var j = 0; j < tokens[type].length; j++) { - var e = new RegExp(tokens[type][j], "gi"); - var r = str.match(e); - if (r) { - return { type: type, method: tokens[type][j] }; - } - } - } - }; - - /** - * Identify each method for each token - */ - var getMethods = function (t) { - var result = []; - for (var i = 0; i < t.length; i++) { - var m = getMethod.call(this, t[i]); - if (m) { - result.push(m.method); - } else { - result.push(null); - } - } - - // Compatibility with excel - for (var i = 0; i < result.length; i++) { - if (result[i] == "MM") { - // Not a month, correct to minutes - if (result[i - 1] && result[i - 1].indexOf("H") >= 0) { - result[i] = "MI"; - } else if (result[i - 2] && result[i - 2].indexOf("H") >= 0) { - result[i] = "MI"; - } else if (result[i + 1] && result[i + 1].indexOf("S") >= 0) { - result[i] = "MI"; - } else if (result[i + 2] && result[i + 2].indexOf("S") >= 0) { - result[i] = "MI"; - } - } - } - - return result; - }; - - /** - * Get the type for one given token - */ - var getType = function (str) { - var m = getMethod.call(this, str); - if (m) { - var type = m.type; - } - - if (type) { - var numeric = 0; - // Make sure the correct type - var t = getTokens.call(this, str); - for (var i = 0; i < t.length; i++) { - m = getMethod.call(this, t[i]); - if (m && isNumeric(m.type)) { - numeric++; - } - } - if (numeric > 1) { - type = "general"; - } - } - - return type; - }; - - /** - * Parse character per character using the detected tokens in the mask - */ - var parse = function () { - // Parser method for this position - if (typeof parser[this.methods[this.index]] == "function") { - parser[this.methods[this.index]].call(this, this.value[this.position]); - this.position++; - } else { - this.values[this.index] = this.tokens[this.index]; - this.index++; - } - }; - - var isFormula = function (value) { - var v = ("" + value)[0]; - return v == "=" ? true : false; - }; - - var toPlainString = function (num) { - return ("" + +num).replace( - /(-?)(\d*)\.?(\d*)e([+-]\d+)/, - function (a, b, c, d, e) { - return e < 0 - ? b + "0." + Array(1 - e - c.length).join(0) + c + d - : b + c + d + Array(e - d.length + 1).join(0); - } - ); - }; - - /** - * Mask function - * @param {mixed|string} JS input or a string to be parsed - * @param {object|string} When the first param is a string, the second is the mask or object with the mask options - */ - var obj = function (e, config, returnObject) { - // Options - var r = null; - var t = null; - var o = { - // Element - input: null, - // Current value - value: null, - // Mask options - options: {}, - // New values for each token found - values: [], - // Token position - index: 0, - // Character position - position: 0, - // Date raw values - date: [0, 0, 0, 0, 0, 0], - // Raw number for the numeric values - number: 0, - }; - - // This is a JavaScript Event - if (typeof e == "object") { - // Element - o.input = e.target; - // Current value - o.value = Value.call(e.target); - // Current caret position - o.caret = Caret.call(e.target); - // Mask - if ((t = e.target.getAttribute("data-mask"))) { - o.mask = t; - } - // Type - if ((t = e.target.getAttribute("data-type"))) { - o.type = t; - } - // Options - if (e.target.mask) { - if (e.target.mask.options) { - o.options = e.target.mask.options; - } - if (e.target.mask.locale) { - o.locale = e.target.mask.locale; - } - } else { - // Locale - if ((t = e.target.getAttribute("data-locale"))) { - o.locale = t; - if (o.mask) { - o.options.style = o.mask; - } - } - } - // Extra configuration - if (e.target.attributes && e.target.attributes.length) { - for (var i = 0; i < e.target.attributes.length; i++) { - var k = e.target.attributes[i].name; - var v = e.target.attributes[i].value; - if (k.substr(0, 4) == "data") { - o.options[k.substr(5)] = v; - } - } - } - } else { - // Options - if (typeof config == "string") { - // Mask - o.mask = config; - } else { - // Mask - var k = Object.keys(config); - for (var i = 0; i < k.length; i++) { - o[k[i]] = config[k[i]]; - } - } - - if (typeof e === "number") { - // Get decimal - getDecimal.call(o, o.mask); - // Replace to the correct decimal - e = ("" + e).replace(".", o.options.decimal); - } - - // Current - o.value = e; - - if (o.input) { - // Value - Value.call(o.input, e); - // Focus - jSuites.focus(o.input); - // Caret - o.caret = Caret.call(o.input); - } - } - - // Mask detected start the process - if (!isFormula(o.value) && (o.mask || o.locale)) { - // Compatibility fixes - if (o.mask) { - // Remove [] - o.mask = o.mask.replace(new RegExp(/\[h]/), "|h|"); - o.mask = o.mask.replace(new RegExp(/\[.*?\]/), ""); - o.mask = o.mask.replace(new RegExp(/\|h\|/), "[h]"); - if (o.mask.indexOf(";") !== -1) { - var t = o.mask.split(";"); - o.mask = t[0]; - } - // Excel mask TODO: Improve - if (o.mask.indexOf("##") !== -1) { - var d = o.mask.split(";"); - if (d[0]) { - d[0] = d[0].replace("*", "\t"); - d[0] = d[0].replace(new RegExp(/_-/g), " "); - d[0] = d[0].replace(new RegExp(/_/g), ""); - d[0] = d[0].replace("##0.###", "##0.000"); - d[0] = d[0].replace("##0.##", "##0.00"); - d[0] = d[0].replace("##0.#", "##0.0"); - d[0] = d[0].replace("##0,###", "##0,000"); - d[0] = d[0].replace("##0,##", "##0,00"); - d[0] = d[0].replace("##0,#", "##0,0"); - } - o.mask = d[0]; - } - // Get type - if (!o.type) { - o.type = getType.call(o, o.mask); - } - // Get tokens - o.tokens = getTokens.call(o, o.mask); - } - // On new input - if ( - typeof e !== "object" || - !e.inputType || - !e.inputType.indexOf("insert") || - !e.inputType.indexOf("delete") - ) { - // Start transformation - if (o.locale) { - if (o.input) { - Format.call(o, o.input, e); - } else { - var newValue = FormatValue.call(o, o.value); - } - } else { - // Get tokens - o.methods = getMethods.call(o, o.tokens); - // Go through all tokes - while ( - o.position < o.value.length && - typeof o.tokens[o.index] !== "undefined" - ) { - // Get the appropriate parser - parse.call(o); - } - - // New value - var newValue = o.values.join(""); - - // Add tokens to the end of string only if string is not empty - if (isNumeric(o.type) && newValue !== "") { - // Complement things in the end of the mask - while (typeof o.tokens[o.index] !== "undefined") { - var t = getMethod.call(o, o.tokens[o.index]); - if (t && t.type == "general") { - o.values[o.index] = o.tokens[o.index]; - } - o.index++; - } - - var adjustNumeric = true; - } else { - var adjustNumeric = false; - } - - // New value - newValue = o.values.join(""); - - // Reset value - if (o.input) { - t = newValue.length - o.value.length; - if (t > 0) { - var caret = o.caret + t; - } else { - var caret = o.caret; - } - Value.call(o.input, newValue, caret, adjustNumeric); - } - } - } - - // Update raw data - if (o.input) { - var label = null; - if (isNumeric(o.type)) { - // Extract the number - o.number = Extract.call(o, Value.call(o.input)); - // Keep the raw data as a property of the tag - if (o.type == "percentage") { - label = o.number / 100; - } else { - label = o.number; - } - } else if (o.type == "datetime") { - label = getDate.call(o); - - if (o.date[0] && o.date[1] && o.date[2]) { - o.input.setAttribute("data-completed", true); - } - } - - if (label) { - o.input.setAttribute("data-value", label); - } - } - - if (newValue !== undefined) { - if (returnObject) { - return o; - } else { - return newValue; - } - } - } - }; - - // Get the type of the mask - obj.getType = getType; - - // Extract the tokens from a mask - obj.prepare = function (str, o) { - if (!o) { - o = {}; - } - return getTokens.call(o, str); - }; - - /** - * Apply the mask to a element (legacy) - */ - obj.apply = function (e) { - var v = Value.call(e.target); - if (e.key.length == 1) { - v += e.key; - } - Value.call(e.target, obj(v, e.target.getAttribute("data-mask"))); - }; - - /** - * Legacy support - */ - obj.run = function (value, mask, decimal) { - return obj(value, { mask: mask, decimal: decimal }); - }; - - /** - * Extract number from masked string - */ - obj.extract = function (v, options, returnObject) { - if (isBlank(v)) { - return v; - } - if (typeof options != "object") { - return value; - } else { - options = Object.assign({}, options); - - if (!options.options) { - options.options = {}; - } - } - - // Compatibility - if (!options.mask && options.format) { - options.mask = options.format; - } - - // Remove [] - if (options.mask) { - if (options.mask.indexOf(";") !== -1) { - var t = options.mask.split(";"); - options.mask = t[0]; - } - options.mask = options.mask.replace(new RegExp(/\[.*?\]/), ""); - } - - // Get decimal - getDecimal.call(options, options.mask); - - var type = null; - if (options.type == "percent" || options.options.style == "percent") { - type = "percentage"; - } else if (options.mask) { - type = getType.call(options, options.mask); - } - - if (type === "general") { - var o = obj(v, options, true); - - value = v; - } else if (type === "datetime") { - if (v instanceof Date) { - var t = jSuites.calendar.getDateString(value, options.mask); - } - - var o = obj(v, options, true); - - if (jSuites.isNumeric(v)) { - value = v; - } else { - var value = getDate.call(o); - var t = jSuites.calendar.now(o.date); - value = jSuites.calendar.dateToNum(t); - } - } else { - var value = Extract.call(options, v); - // Percentage - if (type == "percentage") { - value /= 100; - } - var o = options; - } - - o.value = value; - - if (!o.type && type) { - o.type = type; - } - - if (returnObject) { - return o; - } else { - return value; - } - }; - - /** - * Render - */ - obj.render = function (value, options, fullMask) { - if (isBlank(value)) { - return value; - } - - if (typeof options != "object") { - return value; - } else { - options = Object.assign({}, options); - - if (!options.options) { - options.options = {}; - } - } - - // Compatibility - if (!options.mask && options.format) { - options.mask = options.format; - } - - // Remove [] - if (options.mask) { - if (options.mask.indexOf(";") !== -1) { - var t = options.mask.split(";"); - options.mask = t[0]; - } - options.mask = options.mask.replace(new RegExp(/\[h]/), "|h|"); - options.mask = options.mask.replace(new RegExp(/\[.*?\]/), ""); - options.mask = options.mask.replace(new RegExp(/\|h\|/), "[h]"); - } - - var type = null; - if (options.type == "percent" || options.options.style == "percent") { - type = "percentage"; - } else if (options.mask) { - type = getType.call(options, options.mask); - } else if (value instanceof Date) { - type = "datetime"; - } - - // Fill with blanks - var fillWithBlanks = false; - - if (type == "datetime" || options.type == "calendar") { - var t = jSuites.calendar.getDateString(value, options.mask); - if (t) { - value = t; - } - - if (options.mask && fullMask) { - fillWithBlanks = true; - } - } else { - // Percentage - if (type == "percentage") { - value *= 100; - } - // Number of decimal places - if (typeof value === "number") { - var t = null; - if (options.mask && fullMask) { - var d = getDecimal.call(options, options.mask); - if (options.mask.indexOf(d) !== -1) { - d = options.mask.split(d); - d = "" + d[1].match(/[0-9]+/g); - d = d.length; - t = value.toFixed(d); - } else { - t = value.toFixed(0); - } - } else if (options.locale && fullMask) { - // Append zeros - var d = ("" + value).split("."); - if (options.options) { - if (typeof d[1] === "undefined") { - d[1] = ""; - } - var len = d[1].length; - if (options.options.minimumFractionDigits > len) { - for ( - var i = 0; - i < options.options.minimumFractionDigits - len; - i++ - ) { - d[1] += "0"; - } - } - } - if (!d[1].length) { - t = d[0]; - } else { - t = d.join("."); - } - var len = d[1].length; - if ( - options.options && - options.options.maximumFractionDigits < len - ) { - t = parseFloat(t).toFixed(options.options.maximumFractionDigits); - } - } else { - t = toPlainString(value); - } - - if (t !== null) { - value = t; - // Get decimal - getDecimal.call(options, options.mask); - // Replace to the correct decimal - if (options.options.decimal) { - value = value.replace(".", options.options.decimal); - } - } - } else { - if (options.mask && fullMask) { - fillWithBlanks = true; - } - } - } - - if (fillWithBlanks) { - var s = options.mask.length - value.length; - if (s > 0) { - for (var i = 0; i < s; i++) { - value += " "; - } - } - } - - value = obj(value, options); - - // Numeric mask, number of zeros - if (fullMask && type === "numeric") { - var maskZeros = options.mask.match(new RegExp(/^[0]+$/gm)); - if (maskZeros && maskZeros.length === 1) { - var maskLength = maskZeros[0].length; - if (maskLength > 3) { - value = "" + value; - while (value.length < maskLength) { - value = "0" + value; - } - } - } - } - - return value; - }; - - obj.set = function (e, m) { - if (m) { - e.setAttribute("data-mask", m); - // Reset the value - var event = new Event("input", { - bubbles: true, - cancelable: true, - }); - e.dispatchEvent(event); - } - }; - - if (typeof document !== "undefined") { - document.addEventListener("input", function (e) { - if (e.target.getAttribute("data-mask") || e.target.mask) { - obj(e); - } - }); - } - - return obj; - })(); - - jSuites.modal = function (el, options) { - var obj = {}; - obj.options = {}; - - // Default configuration - var defaults = { - url: null, - onopen: null, - onclose: null, - closed: false, - width: null, - height: null, - title: null, - padding: null, - backdrop: true, - }; - - // Loop through our object - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - obj.options[property] = defaults[property]; - } - } - - // Title - if (!obj.options.title && el.getAttribute("title")) { - obj.options.title = el.getAttribute("title"); - } - - var temp = document.createElement("div"); - while (el.children[0]) { - temp.appendChild(el.children[0]); - } - - obj.content = document.createElement("div"); - obj.content.className = "jmodal_content"; - obj.content.innerHTML = el.innerHTML; - - while (temp.children[0]) { - obj.content.appendChild(temp.children[0]); - } - - obj.container = document.createElement("div"); - obj.container.className = "jmodal"; - obj.container.appendChild(obj.content); - - if (obj.options.padding) { - obj.content.style.padding = obj.options.padding; - } - if (obj.options.width) { - obj.container.style.width = obj.options.width; - } - if (obj.options.height) { - obj.container.style.height = obj.options.height; - } - if (obj.options.title) { - obj.container.setAttribute("title", obj.options.title); - } else { - obj.container.classList.add("no-title"); - } - el.innerHTML = ""; - el.style.display = "none"; - el.appendChild(obj.container); - - // Backdrop - if (obj.options.backdrop) { - var backdrop = document.createElement("div"); - backdrop.className = "jmodal_backdrop"; - backdrop.onclick = function () { - obj.close(); - }; - el.appendChild(backdrop); - } - - obj.open = function () { - el.style.display = "block"; - // Fullscreen - var rect = obj.container.getBoundingClientRect(); - if (jSuites.getWindowWidth() < rect.width) { - obj.container.style.top = ""; - obj.container.style.left = ""; - obj.container.classList.add("jmodal_fullscreen"); - jSuites.animation.slideBottom(obj.container, 1); - } else { - if (obj.options.backdrop) { - backdrop.style.display = "block"; - } - } - // Event - if (typeof obj.options.onopen == "function") { - obj.options.onopen(el, obj); - } - }; - - obj.resetPosition = function () { - obj.container.style.top = ""; - obj.container.style.left = ""; - }; - - obj.isOpen = function () { - return el.style.display != "none" ? true : false; - }; - - obj.close = function () { - if (obj.isOpen()) { - el.style.display = "none"; - if (obj.options.backdrop) { - // Backdrop - backdrop.style.display = ""; - } - // Remove fullscreen class - obj.container.classList.remove("jmodal_fullscreen"); - // Event - if (typeof obj.options.onclose == "function") { - obj.options.onclose(el, obj); - } - } - }; - - if (!jSuites.modal.hasEvents) { - // Position - var tracker = null; - - document.addEventListener("keydown", function (e) { - if (e.which == 27) { - var modals = document.querySelectorAll(".jmodal"); - for (var i = 0; i < modals.length; i++) { - modals[i].parentNode.modal.close(); - } - } - }); - - document.addEventListener("mouseup", function (e) { - var item = jSuites.findElement(e.target, "jmodal"); - if (item) { - // Get target info - var rect = item.getBoundingClientRect(); - - if (e.changedTouches && e.changedTouches[0]) { - var x = e.changedTouches[0].clientX; - var y = e.changedTouches[0].clientY; - } else { - var x = e.clientX; - var y = e.clientY; - } - - if (rect.width - (x - rect.left) < 50 && y - rect.top < 50) { - item.parentNode.modal.close(); - } - } - - if (tracker) { - tracker.element.style.cursor = "auto"; - tracker = null; - } - }); - - document.addEventListener("mousedown", function (e) { - var item = jSuites.findElement(e.target, "jmodal"); - if (item) { - // Get target info - var rect = item.getBoundingClientRect(); - - if (e.changedTouches && e.changedTouches[0]) { - var x = e.changedTouches[0].clientX; - var y = e.changedTouches[0].clientY; - } else { - var x = e.clientX; - var y = e.clientY; - } - - if (rect.width - (x - rect.left) < 50 && y - rect.top < 50) { - // Do nothing - } else { - if (e.target.getAttribute("title") && y - rect.top < 50) { - if (document.selection) { - document.selection.empty(); - } else if (window.getSelection) { - window.getSelection().removeAllRanges(); - } - - tracker = { - left: rect.left, - top: rect.top, - x: e.clientX, - y: e.clientY, - width: rect.width, - height: rect.height, - element: item, - }; - } - } - } - }); - - document.addEventListener("mousemove", function (e) { - if (tracker) { - e = e || window.event; - if (e.buttons) { - var mouseButton = e.buttons; - } else if (e.button) { - var mouseButton = e.button; - } else { - var mouseButton = e.which; - } - - if (mouseButton) { - tracker.element.style.top = - tracker.top + (e.clientY - tracker.y) + tracker.height / 2 + "px"; - tracker.element.style.left = - tracker.left + (e.clientX - tracker.x) + tracker.width / 2 + "px"; - tracker.element.style.cursor = "move"; - } else { - tracker.element.style.cursor = "auto"; - } - } - }); - - jSuites.modal.hasEvents = true; - } - - if (obj.options.url) { - jSuites.ajax({ - url: obj.options.url, - method: "GET", - dataType: "text/html", - success: function (data) { - obj.content.innerHTML = data; - - if (!obj.options.closed) { - obj.open(); - } - }, - }); - } else { - if (!obj.options.closed) { - obj.open(); - } - } - - // Keep object available from the node - el.modal = obj; - - return obj; - }; - - jSuites.notification = function (options) { - var obj = {}; - obj.options = {}; - - // Default configuration - var defaults = { - icon: null, - name: "Notification", - date: null, - error: null, - title: null, - message: null, - timeout: 4000, - autoHide: true, - closeable: true, - }; - - // Loop through our object - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - obj.options[property] = defaults[property]; - } - } - - var notification = document.createElement("div"); - notification.className = "jnotification"; - - if (obj.options.error) { - notification.classList.add("jnotification-error"); - } - - var notificationContainer = document.createElement("div"); - notificationContainer.className = "jnotification-container"; - notification.appendChild(notificationContainer); - - var notificationHeader = document.createElement("div"); - notificationHeader.className = "jnotification-header"; - notificationContainer.appendChild(notificationHeader); - - var notificationImage = document.createElement("div"); - notificationImage.className = "jnotification-image"; - notificationHeader.appendChild(notificationImage); - - if (obj.options.icon) { - var notificationIcon = document.createElement("img"); - notificationIcon.src = obj.options.icon; - notificationImage.appendChild(notificationIcon); - } - - var notificationName = document.createElement("div"); - notificationName.className = "jnotification-name"; - notificationName.innerHTML = obj.options.name; - notificationHeader.appendChild(notificationName); - - if (obj.options.closeable == true) { - var notificationClose = document.createElement("div"); - notificationClose.className = "jnotification-close"; - notificationClose.onclick = function () { - obj.hide(); - }; - notificationHeader.appendChild(notificationClose); - } - - var notificationDate = document.createElement("div"); - notificationDate.className = "jnotification-date"; - notificationHeader.appendChild(notificationDate); - - var notificationContent = document.createElement("div"); - notificationContent.className = "jnotification-content"; - notificationContainer.appendChild(notificationContent); - - if (obj.options.title) { - var notificationTitle = document.createElement("div"); - notificationTitle.className = "jnotification-title"; - notificationTitle.innerHTML = obj.options.title; - notificationContent.appendChild(notificationTitle); - } - - var notificationMessage = document.createElement("div"); - notificationMessage.className = "jnotification-message"; - notificationMessage.innerHTML = obj.options.message; - notificationContent.appendChild(notificationMessage); - - obj.show = function () { - document.body.appendChild(notification); - if (jSuites.getWindowWidth() > 800) { - jSuites.animation.fadeIn(notification); - } else { - jSuites.animation.slideTop(notification, 1); - } - }; - - obj.hide = function () { - if (jSuites.getWindowWidth() > 800) { - jSuites.animation.fadeOut(notification, function () { - if (notification.parentNode) { - notification.parentNode.removeChild(notification); - if (notificationTimeout) { - clearTimeout(notificationTimeout); - } - } - }); - } else { - jSuites.animation.slideTop(notification, 0, function () { - if (notification.parentNode) { - notification.parentNode.removeChild(notification); - if (notificationTimeout) { - clearTimeout(notificationTimeout); - } - } - }); - } - }; - - obj.show(); - - if (obj.options.autoHide == true) { - var notificationTimeout = setTimeout(function () { - obj.hide(); - }, obj.options.timeout); - } - - if (jSuites.getWindowWidth() < 800) { - notification.addEventListener("swipeup", function (e) { - obj.hide(); - e.preventDefault(); - e.stopPropagation(); - }); - } - - return obj; - }; - - jSuites.notification.isVisible = function () { - var j = document.querySelector(".jnotification"); - return j && j.parentNode ? true : false; - }; - - // More palettes https://coolors.co/ or https://gka.github.io/palettes/#/10|s|003790,005647,ffffe0|ffffe0,ff005e,93003a|1|1 - jSuites.palette = (function () { - /** - * Available palettes - */ - var palette = { - material: [ - [ - "#ffebee", - "#fce4ec", - "#f3e5f5", - "#e8eaf6", - "#e3f2fd", - "#e0f7fa", - "#e0f2f1", - "#e8f5e9", - "#f1f8e9", - "#f9fbe7", - "#fffde7", - "#fff8e1", - "#fff3e0", - "#fbe9e7", - "#efebe9", - "#fafafa", - "#eceff1", - ], - [ - "#ffcdd2", - "#f8bbd0", - "#e1bee7", - "#c5cae9", - "#bbdefb", - "#b2ebf2", - "#b2dfdb", - "#c8e6c9", - "#dcedc8", - "#f0f4c3", - "#fff9c4", - "#ffecb3", - "#ffe0b2", - "#ffccbc", - "#d7ccc8", - "#f5f5f5", - "#cfd8dc", - ], - [ - "#ef9a9a", - "#f48fb1", - "#ce93d8", - "#9fa8da", - "#90caf9", - "#80deea", - "#80cbc4", - "#a5d6a7", - "#c5e1a5", - "#e6ee9c", - "#fff59d", - "#ffe082", - "#ffcc80", - "#ffab91", - "#bcaaa4", - "#eeeeee", - "#b0bec5", - ], - [ - "#e57373", - "#f06292", - "#ba68c8", - "#7986cb", - "#64b5f6", - "#4dd0e1", - "#4db6ac", - "#81c784", - "#aed581", - "#dce775", - "#fff176", - "#ffd54f", - "#ffb74d", - "#ff8a65", - "#a1887f", - "#e0e0e0", - "#90a4ae", - ], - [ - "#ef5350", - "#ec407a", - "#ab47bc", - "#5c6bc0", - "#42a5f5", - "#26c6da", - "#26a69a", - "#66bb6a", - "#9ccc65", - "#d4e157", - "#ffee58", - "#ffca28", - "#ffa726", - "#ff7043", - "#8d6e63", - "#bdbdbd", - "#78909c", - ], - [ - "#f44336", - "#e91e63", - "#9c27b0", - "#3f51b5", - "#2196f3", - "#00bcd4", - "#009688", - "#4caf50", - "#8bc34a", - "#cddc39", - "#ffeb3b", - "#ffc107", - "#ff9800", - "#ff5722", - "#795548", - "#9e9e9e", - "#607d8b", - ], - [ - "#e53935", - "#d81b60", - "#8e24aa", - "#3949ab", - "#1e88e5", - "#00acc1", - "#00897b", - "#43a047", - "#7cb342", - "#c0ca33", - "#fdd835", - "#ffb300", - "#fb8c00", - "#f4511e", - "#6d4c41", - "#757575", - "#546e7a", - ], - [ - "#d32f2f", - "#c2185b", - "#7b1fa2", - "#303f9f", - "#1976d2", - "#0097a7", - "#00796b", - "#388e3c", - "#689f38", - "#afb42b", - "#fbc02d", - "#ffa000", - "#f57c00", - "#e64a19", - "#5d4037", - "#616161", - "#455a64", - ], - [ - "#c62828", - "#ad1457", - "#6a1b9a", - "#283593", - "#1565c0", - "#00838f", - "#00695c", - "#2e7d32", - "#558b2f", - "#9e9d24", - "#f9a825", - "#ff8f00", - "#ef6c00", - "#d84315", - "#4e342e", - "#424242", - "#37474f", - ], - [ - "#b71c1c", - "#880e4f", - "#4a148c", - "#1a237e", - "#0d47a1", - "#006064", - "#004d40", - "#1b5e20", - "#33691e", - "#827717", - "#f57f17", - "#ff6f00", - "#e65100", - "#bf360c", - "#3e2723", - "#212121", - "#263238", - ], - ], - fire: [ - [ - "0b1a6d", - "840f38", - "b60718", - "de030b", - "ff0c0c", - "fd491c", - "fc7521", - "faa331", - "fbb535", - "ffc73a", - ], - [ - "071147", - "5f0b28", - "930513", - "be0309", - "ef0000", - "fa3403", - "fb670b", - "f9991b", - "faad1e", - "ffc123", - ], - [ - "03071e", - "370617", - "6a040f", - "9d0208", - "d00000", - "dc2f02", - "e85d04", - "f48c06", - "faa307", - "ffba08", - ], - [ - "020619", - "320615", - "61040d", - "8c0207", - "bc0000", - "c82a02", - "d05203", - "db7f06", - "e19405", - "efab00", - ], - [ - "020515", - "2d0513", - "58040c", - "7f0206", - "aa0000", - "b62602", - "b94903", - "c57205", - "ca8504", - "d89b00", - ], - ], - baby: [ - [ - "eddcd2", - "fff1e6", - "fde2e4", - "fad2e1", - "c5dedd", - "dbe7e4", - "f0efeb", - "d6e2e9", - "bcd4e6", - "99c1de", - ], - [ - "e1c4b3", - "ffd5b5", - "fab6ba", - "f5a8c4", - "aacecd", - "bfd5cf", - "dbd9d0", - "baceda", - "9dc0db", - "7eb1d5", - ], - [ - "daa990", - "ffb787", - "f88e95", - "f282a9", - "8fc4c3", - "a3c8be", - "cec9b3", - "9dbcce", - "82acd2", - "649dcb", - ], - [ - "d69070", - "ff9c5e", - "f66770", - "f05f8f", - "74bbb9", - "87bfae", - "c5b993", - "83aac3", - "699bca", - "4d89c2", - ], - [ - "c97d5d", - "f58443", - "eb4d57", - "e54a7b", - "66a9a7", - "78ae9c", - "b5a67e", - "7599b1", - "5c88b7", - "4978aa", - ], - ], - chart: [ - [ - "#C1D37F", - "#4C5454", - "#FFD275", - "#66586F", - "#D05D5B", - "#C96480", - "#95BF8F", - "#6EA240", - "#0F0F0E", - "#EB8258", - "#95A3B3", - "#995D81", - ], - ], - }; - - /** - * Get a pallete - */ - var component = function (o) { - // Otherwise get palette value - if (palette[o]) { - return palette[o]; - } else { - return palette.material; - } - }; - - component.get = function (o) { - // Otherwise get palette value - if (palette[o]) { - return palette[o]; - } else { - return palette; - } - }; - - component.set = function (o, v) { - palette[o] = v; - }; - - return component; - })(); - - jSuites.picker = function (el, options) { - // Already created, update options - if (el.picker) { - return el.picker.setOptions(options, true); - } - - // New instance - var obj = { type: "picker" }; - obj.options = {}; - - var dropdownHeader = null; - var dropdownContent = null; - - /** - * Create the content options - */ - var createContent = function () { - dropdownContent.innerHTML = ""; - - // Create items - var keys = Object.keys(obj.options.data); - - // Go though all options - for (var i = 0; i < keys.length; i++) { - // Item - var dropdownItem = document.createElement("div"); - dropdownItem.classList.add("jpicker-item"); - dropdownItem.k = keys[i]; - dropdownItem.v = obj.options.data[keys[i]]; - // Label - dropdownItem.innerHTML = obj.getLabel(keys[i]); - // Append - dropdownContent.appendChild(dropdownItem); - } - }; - - /** - * Set or reset the options for the picker - */ - obj.setOptions = function (options, reset) { - // Default configuration - var defaults = { - value: 0, - data: null, - render: null, - onchange: null, - onselect: null, - onopen: null, - onclose: null, - onload: null, - width: null, - header: true, - right: false, - content: false, - columns: null, - height: null, - }; - - // Legacy purpose only - if (options && options.options) { - options.data = options.options; - } - - // Loop through the initial configuration - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - if (typeof obj.options[property] == "undefined" || reset === true) { - obj.options[property] = defaults[property]; - } - } - } - - // Start using the options - if (obj.options.header === false) { - dropdownHeader.style.display = "none"; - } else { - dropdownHeader.style.display = ""; - } - - // Width - if (obj.options.width) { - dropdownHeader.style.width = parseInt(obj.options.width) + "px"; - } else { - dropdownHeader.style.width = ""; - } - - // Height - if (obj.options.height) { - dropdownContent.style.maxHeight = obj.options.height + "px"; - dropdownContent.style.overflow = "scroll"; - } else { - dropdownContent.style.overflow = ""; - } - - if (obj.options.columns > 0) { - dropdownContent.classList.add("jpicker-columns"); - dropdownContent.style.width = obj.options.width - ? obj.options.width - : 36 * obj.options.columns + "px"; - } - - if (isNaN(obj.options.value)) { - obj.options.value = "0"; - } - - // Create list from data - createContent(); - - // Set value - obj.setValue(obj.options.value); - - // Set options all returns the own instance - return obj; - }; - - obj.getValue = function () { - return obj.options.value; - }; - - obj.setValue = function (v) { - // Set label - obj.setLabel(v); - - // Update value - obj.options.value = String(v); - - // Lemonade JS - if (el.value != obj.options.value) { - el.value = obj.options.value; - if (typeof el.oninput == "function") { - el.oninput({ - type: "input", - target: el, - value: el.value, - }); - } - } - - if (dropdownContent.children[v].getAttribute("type") !== "generic") { - obj.close(); - } - }; - - obj.getLabel = function (v) { - var label = obj.options.data[v] || null; - if (typeof obj.options.render == "function") { - label = obj.options.render(label); - } - return label; - }; - - obj.setLabel = function (v) { - if (obj.options.content) { - var label = '' + obj.options.content + ""; - } else { - var label = obj.getLabel(v); - } - - dropdownHeader.innerHTML = label; - }; - - obj.open = function () { - if (!el.classList.contains("jpicker-focus")) { - // Start tracking the element - jSuites.tracking(obj, true); - - // Open picker - el.classList.add("jpicker-focus"); - el.focus(); - - var top = 0; - var left = 0; - - dropdownContent.style.marginLeft = ""; - - var rectHeader = dropdownHeader.getBoundingClientRect(); - var rectContent = dropdownContent.getBoundingClientRect(); - - if (window.innerHeight < rectHeader.bottom + rectContent.height) { - top = -1 * (rectContent.height + 4); - } else { - top = rectHeader.height + 4; - } - - if (obj.options.right === true) { - left = -1 * rectContent.width + rectHeader.width; - } - - if (rectContent.left + left < 0) { - left = left + rectContent.left + 10; - } - if (rectContent.left + rectContent.width > window.innerWidth) { - left = - -1 * - (10 + rectContent.left + rectContent.width - window.innerWidth); - } - - dropdownContent.style.marginTop = parseInt(top) + "px"; - dropdownContent.style.marginLeft = parseInt(left) + "px"; - - //dropdownContent.style.marginTop - if (typeof obj.options.onopen == "function") { - obj.options.onopen(el, obj); - } - } - }; - - obj.close = function () { - if (el.classList.contains("jpicker-focus")) { - el.classList.remove("jpicker-focus"); - - // Start tracking the element - jSuites.tracking(obj, false); - - if (typeof obj.options.onclose == "function") { - obj.options.onclose(el, obj); - } - } - }; - - /** - * Create floating picker - */ - var init = function () { - // Class - el.classList.add("jpicker"); - el.setAttribute("tabindex", "900"); - el.onmousedown = function (e) { - if (!el.classList.contains("jpicker-focus")) { - obj.open(); - } - }; - - // Dropdown Header - dropdownHeader = document.createElement("div"); - dropdownHeader.classList.add("jpicker-header"); - - // Dropdown content - dropdownContent = document.createElement("div"); - dropdownContent.classList.add("jpicker-content"); - dropdownContent.onclick = function (e) { - var item = jSuites.findElement(e.target, "jpicker-item"); - if (item) { - if (item.parentNode === dropdownContent) { - // Update label - obj.setValue(item.k); - // Call method - if (typeof obj.options.onchange == "function") { - obj.options.onchange.call( - obj, - el, - obj, - item.v, - item.v, - item.k, - e - ); - } - } - } - }; - - // Append content and header - el.appendChild(dropdownHeader); - el.appendChild(dropdownContent); - - // Default value - el.value = options.value || 0; - - // Set options - obj.setOptions(options); - - if (typeof obj.options.onload == "function") { - obj.options.onload(el, obj); - } - - // Change - el.change = obj.setValue; - - // Global generic value handler - el.val = function (val) { - if (val === undefined) { - return obj.getValue(); - } else { - obj.setValue(val); - } - }; - - // Reference - el.picker = obj; - }; - - init(); - - return obj; - }; - - jSuites.progressbar = function (el, options) { - var obj = {}; - obj.options = {}; - - // Default configuration - var defaults = { - value: 0, - onchange: null, - width: null, - }; - - // Loop through the initial configuration - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - obj.options[property] = defaults[property]; - } - } - - // Class - el.classList.add("jprogressbar"); - el.setAttribute("tabindex", 1); - el.setAttribute("data-value", obj.options.value); - - var bar = document.createElement("div"); - bar.style.width = obj.options.value + "%"; - bar.style.color = "#fff"; - el.appendChild(bar); - - if (obj.options.width) { - el.style.width = obj.options.width; - } - - // Set value - obj.setValue = function (value) { - value = parseInt(value); - obj.options.value = value; - bar.style.width = value + "%"; - el.setAttribute("data-value", value + "%"); - - if (value < 6) { - el.style.color = "#000"; - } else { - el.style.color = "#fff"; - } - - // Update value - obj.options.value = value; - - if (typeof obj.options.onchange == "function") { - obj.options.onchange(el, value); - } - - // Lemonade JS - if (el.value != obj.options.value) { - el.value = obj.options.value; - if (typeof el.oninput == "function") { - el.oninput({ - type: "input", - target: el, - value: el.value, - }); - } - } - }; - - obj.getValue = function () { - return obj.options.value; - }; - - var action = function (e) { - if (e.which) { - // Get target info - var rect = el.getBoundingClientRect(); - - if (e.changedTouches && e.changedTouches[0]) { - var x = e.changedTouches[0].clientX; - var y = e.changedTouches[0].clientY; - } else { - var x = e.clientX; - var y = e.clientY; - } - - obj.setValue(Math.round(((x - rect.left) / rect.width) * 100)); - } - }; - - // Events - if ("touchstart" in document.documentElement === true) { - el.addEventListener("touchstart", action); - el.addEventListener("touchend", action); - } else { - el.addEventListener("mousedown", action); - el.addEventListener("mousemove", action); - } - - // Change - el.change = obj.setValue; - - // Global generic value handler - el.val = function (val) { - if (val === undefined) { - return obj.getValue(); - } else { - obj.setValue(val); - } - }; - - // Reference - el.progressbar = obj; - - return obj; - }; - - jSuites.rating = function (el, options) { - // Already created, update options - if (el.rating) { - return el.rating.setOptions(options, true); - } - - // New instance - var obj = {}; - obj.options = {}; - - obj.setOptions = function (options, reset) { - // Default configuration - var defaults = { - number: 5, - value: 0, - tooltip: ["Very bad", "Bad", "Average", "Good", "Very good"], - onchange: null, - }; - - // Loop through the initial configuration - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - if (typeof obj.options[property] == "undefined" || reset === true) { - obj.options[property] = defaults[property]; - } - } - } - - // Make sure the container is empty - el.innerHTML = ""; - - // Add elements - for (var i = 0; i < obj.options.number; i++) { - var div = document.createElement("div"); - div.setAttribute("data-index", i + 1); - div.setAttribute("title", obj.options.tooltip[i]); - el.appendChild(div); - } - - // Selected option - if (obj.options.value) { - for (var i = 0; i < obj.options.number; i++) { - if (i < obj.options.value) { - el.children[i].classList.add("jrating-selected"); - } - } - } - - return obj; - }; - - // Set value - obj.setValue = function (index) { - for (var i = 0; i < obj.options.number; i++) { - if (i < index) { - el.children[i].classList.add("jrating-selected"); - } else { - el.children[i].classList.remove("jrating-over"); - el.children[i].classList.remove("jrating-selected"); - } - } - - obj.options.value = index; - - if (typeof obj.options.onchange == "function") { - obj.options.onchange(el, index); - } - - // Lemonade JS - if (el.value != obj.options.value) { - el.value = obj.options.value; - if (typeof el.oninput == "function") { - el.oninput({ - type: "input", - target: el, - value: el.value, - }); - } - } - }; - - obj.getValue = function () { - return obj.options.value; - }; - - var init = function () { - // Start plugin - obj.setOptions(options); - - // Class - el.classList.add("jrating"); - - // Events - el.addEventListener("click", function (e) { - var index = e.target.getAttribute("data-index"); - if (index != undefined) { - if (index == obj.options.value) { - obj.setValue(0); - } else { - obj.setValue(index); - } - } - }); - - el.addEventListener("mouseover", function (e) { - var index = e.target.getAttribute("data-index"); - for (var i = 0; i < obj.options.number; i++) { - if (i < index) { - el.children[i].classList.add("jrating-over"); - } else { - el.children[i].classList.remove("jrating-over"); - } - } - }); - - el.addEventListener("mouseout", function (e) { - for (var i = 0; i < obj.options.number; i++) { - el.children[i].classList.remove("jrating-over"); - } - }); - - // Change - el.change = obj.setValue; - - // Global generic value handler - el.val = function (val) { - if (val === undefined) { - return obj.getValue(); - } else { - obj.setValue(val); - } - }; - - // Reference - el.rating = obj; - }; - - init(); - - return obj; - }; - - jSuites.search = function (el, options) { - if (el.search) { - return el.search; - } - - var index = null; - - var select = function (e) { - if (e.target.classList.contains("jsearch_item")) { - var element = e.target; - } else { - var element = e.target.parentNode; - } - - obj.selectIndex(element); - e.preventDefault(); - }; - - var createList = function (data) { - // Reset container - container.innerHTML = ""; - // Print results - if (!data.length) { - // Show container - el.style.display = ""; - } else { - // Show container - el.style.display = "block"; - - // Show items (only 10) - var len = data.length < 11 ? data.length : 10; - for (var i = 0; i < len; i++) { - if (typeof data[i] == "string") { - var text = data[i]; - var value = data[i]; - } else { - // Legacy - var text = data[i].text; - if (!text && data[i].name) { - text = data[i].name; - } - var value = data[i].value; - if (!value && data[i].id) { - value = data[i].id; - } - } - - var div = document.createElement("div"); - div.setAttribute("data-value", value); - div.setAttribute("data-text", text); - div.className = "jsearch_item"; - - if (data[i].id) { - div.setAttribute("id", data[i].id); - } - - if (obj.options.forceSelect && i == 0) { - div.classList.add("selected"); - } - var img = document.createElement("img"); - if (data[i].image) { - img.src = data[i].image; - } else { - img.style.display = "none"; - } - div.appendChild(img); - - var item = document.createElement("div"); - item.innerHTML = text; - div.appendChild(item); - - // Append item to the container - container.appendChild(div); - } - } - }; - - var execute = function (str) { - if (str != obj.terms) { - // New terms - obj.terms = str; - // New index - if (obj.options.forceSelect) { - index = 0; - } else { - index = null; - } - // Array or remote search - if (Array.isArray(obj.options.data)) { - var test = function (o) { - if (typeof o == "string") { - if (("" + o).toLowerCase().search(str.toLowerCase()) >= 0) { - return true; - } - } else { - for (var key in o) { - var value = o[key]; - if (("" + value).toLowerCase().search(str.toLowerCase()) >= 0) { - return true; - } - } - } - return false; - }; - - var results = obj.options.data.filter(function (item) { - return test(item); - }); - - // Show items - createList(results); - } else { - // Get remove results - jSuites.ajax({ - url: obj.options.data + str, - method: "GET", - dataType: "json", - success: function (data) { - // Show items - createList(data); - }, - }); - } - } - }; - - // Search timer - var timer = null; - - // Search methods - var obj = function (str) { - if (timer) { - clearTimeout(timer); - } - timer = setTimeout(function () { - execute(str); - }, 500); - }; - if (options.forceSelect === null) { - options.forceSelect = true; - } - obj.options = { - data: options.data || null, - input: options.input || null, - searchByNode: options.searchByNode || null, - onselect: options.onselect || null, - forceSelect: options.forceSelect, - onbeforesearch: options.onbeforesearch || null, - }; - - obj.selectIndex = function (item) { - var id = item.getAttribute("id"); - var text = item.getAttribute("data-text"); - var value = item.getAttribute("data-value"); - // Onselect - if (typeof obj.options.onselect == "function") { - obj.options.onselect(obj, text, value, id); - } - // Close container - obj.close(); - }; - - obj.open = function () { - el.style.display = "block"; - }; - - obj.close = function () { - if (timer) { - clearTimeout(timer); - } - // Current terms - obj.terms = ""; - // Remove results - container.innerHTML = ""; - // Hide - el.style.display = ""; - }; - - obj.isOpened = function () { - return el.style.display ? true : false; - }; - - obj.keydown = function (e) { - if (obj.isOpened()) { - if (e.key == "Enter") { - // Enter - if (index !== null && container.children[index]) { - obj.selectIndex(container.children[index]); - e.preventDefault(); - } else { - obj.close(); - } - } else if (e.key === "ArrowUp") { - // Up - if (index !== null && container.children[0]) { - container.children[index].classList.remove("selected"); - if (!obj.options.forceSelect && index === 0) { - index = null; - } else { - index = Math.max(0, index - 1); - container.children[index].classList.add("selected"); - } - } - e.preventDefault(); - } else if (e.key === "ArrowDown") { - // Down - if (index == null) { - index = -1; - } else { - container.children[index].classList.remove("selected"); - } - if (index < 9 && container.children[index + 1]) { - index++; - } - container.children[index].classList.add("selected"); - e.preventDefault(); - } - } - }; - - obj.keyup = function (e) { - if (!obj.options.searchByNode) { - if (obj.options.input.tagName === "DIV") { - var terms = obj.options.input.innerText; - } else { - var terms = obj.options.input.value; - } - } else { - // Current node - var node = jSuites.getNode(); - if (node) { - var terms = node.innerText; - } - } - - if (typeof obj.options.onbeforesearch == "function") { - var ret = obj.options.onbeforesearch(obj, terms); - if (ret) { - terms = ret; - } else { - if (ret === false) { - // Ignore event - return; - } - } - } - - obj(terms); - }; - - // Add events - if (obj.options.input) { - obj.options.input.addEventListener("keyup", obj.keyup); - obj.options.input.addEventListener("keydown", obj.keydown); - } - - // Append element - var container = document.createElement("div"); - container.classList.add("jsearch_container"); - container.onmousedown = select; - el.appendChild(container); - - el.classList.add("jsearch"); - el.search = obj; - - return obj; - }; - - jSuites.slider = function (el, options) { - var obj = {}; - obj.options = {}; - obj.currentImage = null; - - if (options) { - obj.options = options; - } - - // Focus - el.setAttribute("tabindex", "900"); - - // Items - obj.options.items = []; - - if (!el.classList.contains("jslider")) { - el.classList.add("jslider"); - el.classList.add("unselectable"); - - if (obj.options.height) { - el.style.minHeight = obj.options.height; - } - if (obj.options.width) { - el.style.width = obj.options.width; - } - if (obj.options.grid) { - el.classList.add("jslider-grid"); - var number = el.children.length; - if (number > 4) { - el.setAttribute("data-total", number - 4); - } - el.setAttribute("data-number", number > 4 ? 4 : number); - } - - // Add slider counter - var counter = document.createElement("div"); - counter.classList.add("jslider-counter"); - - // Move children inside - if (el.children.length > 0) { - // Keep children items - for (var i = 0; i < el.children.length; i++) { - obj.options.items.push(el.children[i]); - - // counter click event - var item = document.createElement("div"); - item.onclick = function () { - var index = Array.prototype.slice - .call(counter.children) - .indexOf(this); - obj.show((obj.currentImage = obj.options.items[index])); - }; - counter.appendChild(item); - } - } - // Add caption - var caption = document.createElement("div"); - caption.className = "jslider-caption"; - - // Add close buttom - var controls = document.createElement("div"); - var close = document.createElement("div"); - close.className = "jslider-close"; - close.innerHTML = ""; - - close.onclick = function () { - obj.close(); - }; - controls.appendChild(caption); - controls.appendChild(close); - } - - obj.updateCounter = function (index) { - for (var i = 0; i < counter.children.length; i++) { - if (counter.children[i].classList.contains("jslider-counter-focus")) { - counter.children[i].classList.remove("jslider-counter-focus"); - break; - } - } - counter.children[index].classList.add("jslider-counter-focus"); - }; - - obj.show = function (target) { - if (!target) { - var target = el.children[0]; - } - - // Focus element - el.classList.add("jslider-focus"); - el.classList.remove("jslider-grid"); - el.appendChild(controls); - el.appendChild(counter); - - // Update counter - var index = obj.options.items.indexOf(target); - obj.updateCounter(index); - - // Remove display - for (var i = 0; i < el.children.length; i++) { - el.children[i].style.display = ""; - } - target.style.display = "block"; - - // Is there any previous - if (target.previousElementSibling) { - el.classList.add("jslider-left"); - } else { - el.classList.remove("jslider-left"); - } - - // Is there any next - if ( - target.nextElementSibling && - target.nextElementSibling.tagName == "IMG" - ) { - el.classList.add("jslider-right"); - } else { - el.classList.remove("jslider-right"); - } - - obj.currentImage = target; - - // Vertical image - if (obj.currentImage.offsetHeight > obj.currentImage.offsetWidth) { - obj.currentImage.classList.add("jslider-vertical"); - } - - controls.children[0].innerText = obj.currentImage.getAttribute("title"); - }; - - obj.open = function () { - obj.show(); - - // Event - if (typeof obj.options.onopen == "function") { - obj.options.onopen(el); - } - }; - - obj.close = function () { - // Remove control classes - el.classList.remove("jslider-focus"); - el.classList.remove("jslider-left"); - el.classList.remove("jslider-right"); - // Show as a grid depending on the configuration - if (obj.options.grid) { - el.classList.add("jslider-grid"); - } - // Remove display - for (var i = 0; i < el.children.length; i++) { - el.children[i].style.display = ""; - } - // Remove controls from the component - counter.remove(); - controls.remove(); - // Current image - obj.currentImage = null; - // Event - if (typeof obj.options.onclose == "function") { - obj.options.onclose(el); - } - }; - - obj.reset = function () { - el.innerHTML = ""; - }; - - obj.next = function () { - var nextImage = obj.currentImage.nextElementSibling; - if (nextImage && nextImage.tagName === "IMG") { - obj.show(obj.currentImage.nextElementSibling); - } - }; - - obj.prev = function () { - if (obj.currentImage.previousElementSibling) { - obj.show(obj.currentImage.previousElementSibling); - } - }; - - var mouseUp = function (e) { - // Open slider - if (e.target.tagName == "IMG") { - obj.show(e.target); - } else if ( - !e.target.classList.contains("jslider-close") && - !( - e.target.parentNode.classList.contains("jslider-counter") || - e.target.classList.contains("jslider-counter") - ) - ) { - // Arrow controls - var offsetX = e.offsetX || e.changedTouches[0].clientX; - if (e.target.clientWidth - offsetX < 40) { - // Show next image - obj.next(); - } else if (offsetX < 40) { - // Show previous image - obj.prev(); - } - } - }; - - if ("ontouchend" in document.documentElement === true) { - el.addEventListener("touchend", mouseUp); - } else { - el.addEventListener("mouseup", mouseUp); - } - - // Add global events - el.addEventListener("swipeleft", function (e) { - obj.next(); - e.preventDefault(); - e.stopPropagation(); - }); - - el.addEventListener("swiperight", function (e) { - obj.prev(); - e.preventDefault(); - e.stopPropagation(); - }); - - el.addEventListener("keydown", function (e) { - if (e.which == 27) { - obj.close(); - } - }); - - el.slider = obj; - - return obj; - }; - - jSuites.sorting = function (el, options) { - var obj = {}; - obj.options = {}; - - var defaults = { - pointer: null, - direction: null, - ondragstart: null, - ondragend: null, - ondrop: null, - }; - - var dragElement = null; - - // Loop through the initial configuration - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - obj.options[property] = defaults[property]; - } - } - - el.classList.add("jsorting"); - - el.addEventListener("dragstart", function (e) { - var position = Array.prototype.indexOf.call( - e.target.parentNode.children, - e.target - ); - dragElement = { - element: e.target, - o: position, - d: position, - }; - e.target.style.opacity = "0.25"; - - if (typeof obj.options.ondragstart == "function") { - obj.options.ondragstart(el, e.target, e); - } - }); - - el.addEventListener("dragover", function (e) { - e.preventDefault(); - - if (getElement(e.target) && dragElement) { - if ( - e.target.getAttribute("draggable") == "true" && - dragElement.element != e.target - ) { - if (!obj.options.direction) { - var condition = e.target.clientHeight / 2 > e.offsetY; - } else { - var condition = e.target.clientWidth / 2 > e.offsetX; - } - - if (condition) { - e.target.parentNode.insertBefore(dragElement.element, e.target); - } else { - e.target.parentNode.insertBefore( - dragElement.element, - e.target.nextSibling - ); - } - - dragElement.d = Array.prototype.indexOf.call( - e.target.parentNode.children, - dragElement.element - ); - } - } - }); - - el.addEventListener("dragleave", function (e) { - e.preventDefault(); - }); - - el.addEventListener("dragend", function (e) { - e.preventDefault(); - - if (dragElement) { - if (typeof obj.options.ondragend == "function") { - obj.options.ondragend(el, dragElement.element, e); - } - - // Cancelled put element to the original position - if (dragElement.o < dragElement.d) { - e.target.parentNode.insertBefore( - dragElement.element, - e.target.parentNode.children[dragElement.o] - ); - } else { - e.target.parentNode.insertBefore( - dragElement.element, - e.target.parentNode.children[dragElement.o].nextSibling - ); - } - - dragElement.element.style.opacity = ""; - dragElement = null; - } - }); - - el.addEventListener("drop", function (e) { - e.preventDefault(); - - if (dragElement && dragElement.o != dragElement.d) { - if (typeof obj.options.ondrop == "function") { - obj.options.ondrop( - el, - dragElement.o, - dragElement.d, - dragElement.element, - e.target, - e - ); - } - } - - dragElement.element.style.opacity = ""; - dragElement = null; - }); - - var getElement = function (element) { - var sorting = false; - - function path(element) { - if (element.className) { - if (element.classList.contains("jsorting")) { - sorting = true; - } - } - - if (!sorting) { - path(element.parentNode); - } - } - - path(element); - - return sorting; - }; - - for (var i = 0; i < el.children.length; i++) { - if (!el.children[i].hasAttribute("draggable")) { - el.children[i].setAttribute("draggable", "true"); - } - } - - el.val = function () { - var id = null; - var data = []; - for (var i = 0; i < el.children.length; i++) { - if ((id = el.children[i].getAttribute("data-id"))) { - data.push(id); - } - } - return data; - }; - - return el; - }; - - jSuites.tabs = function (el, options) { - var obj = {}; - obj.options = {}; - - // Default configuration - var defaults = { - data: [], - position: null, - allowCreate: false, - allowChangePosition: false, - onclick: null, - onload: null, - onchange: null, - oncreate: null, - ondelete: null, - onbeforecreate: null, - onchangeposition: null, - animation: false, - hideHeaders: false, - padding: null, - palette: null, - maxWidth: null, - }; - - // Loop through the initial configuration - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - obj.options[property] = defaults[property]; - } - } - - // Class - el.classList.add("jtabs"); - - var prev = null; - var next = null; - var border = null; - - // Helpers - var setBorder = function (index) { - if (obj.options.animation) { - setTimeout(function () { - var rect = obj.headers.children[index].getBoundingClientRect(); - - if (obj.options.palette == "modern") { - border.style.width = rect.width - 4 + "px"; - border.style.left = - obj.headers.children[index].offsetLeft + 2 + "px"; - } else { - border.style.width = rect.width + "px"; - border.style.left = obj.headers.children[index].offsetLeft + "px"; - } - - if (obj.options.position == "bottom") { - border.style.top = "0px"; - } else { - border.style.bottom = "0px"; - } - }, 150); - } - }; - - var updateControls = function (x) { - if (typeof obj.headers.scrollTo == "function") { - obj.headers.scrollTo({ - left: x, - behavior: "smooth", - }); - } else { - obj.headers.scrollLeft = x; - } - - if (x <= 1) { - prev.classList.add("disabled"); - } else { - prev.classList.remove("disabled"); - } - - if (x >= obj.headers.scrollWidth - obj.headers.offsetWidth) { - next.classList.add("disabled"); - } else { - next.classList.remove("disabled"); - } - - if (obj.headers.scrollWidth <= obj.headers.offsetWidth) { - prev.style.display = "none"; - next.style.display = "none"; - } else { - prev.style.display = ""; - next.style.display = ""; - } - }; - - obj.setBorder = setBorder; - - // Set value - obj.open = function (index) { - var previous = null; - for (var i = 0; i < obj.headers.children.length; i++) { - if (obj.headers.children[i].classList.contains("jtabs-selected")) { - // Current one - previous = i; - } - // Remote selected - obj.headers.children[i].classList.remove("jtabs-selected"); - if (obj.content.children[i]) { - obj.content.children[i].classList.remove("jtabs-selected"); - } - } - - obj.headers.children[index].classList.add("jtabs-selected"); - if (obj.content.children[index]) { - obj.content.children[index].classList.add("jtabs-selected"); - } - - if (previous != index && typeof obj.options.onchange == "function") { - if (obj.content.children[index]) { - obj.options.onchange( - el, - obj, - index, - obj.headers.children[index], - obj.content.children[index] - ); - } - } - - // Hide - if ( - obj.options.hideHeaders == true && - obj.headers.children.length < 3 && - obj.options.allowCreate == false - ) { - obj.headers.parentNode.style.display = "none"; - } else { - // Set border - setBorder(index); - - obj.headers.parentNode.style.display = ""; - - var x1 = obj.headers.children[index].offsetLeft; - var x2 = x1 + obj.headers.children[index].offsetWidth; - var r1 = obj.headers.scrollLeft; - var r2 = r1 + obj.headers.offsetWidth; - - if (!(r1 <= x1 && r2 >= x2)) { - // Out of the viewport - updateControls(x1 - 1); - } - } - }; - - obj.selectIndex = function (a) { - var index = Array.prototype.indexOf.call(obj.headers.children, a); - if (index >= 0) { - obj.open(index); - } - - return index; - }; - - obj.rename = function (i, title) { - if (!title) { - title = prompt("New title", obj.headers.children[i].innerText); - } - obj.headers.children[i].innerText = title; - obj.open(i); - }; - - obj.create = function (title, url) { - if (typeof obj.options.onbeforecreate == "function") { - var ret = obj.options.onbeforecreate(el); - if (ret === false) { - return false; - } else { - title = ret; - } - } - - var div = obj.appendElement(title); - - if (typeof obj.options.oncreate == "function") { - obj.options.oncreate(el, div); - } - - setBorder(); - - return div; - }; - - obj.remove = function (index) { - return obj.deleteElement(index); - }; - - obj.nextNumber = function () { - var num = 0; - for (var i = 0; i < obj.headers.children.length; i++) { - var tmp = obj.headers.children[i].innerText.match(/[0-9].*/); - if (tmp > num) { - num = parseInt(tmp); - } - } - if (!num) { - num = 1; - } else { - num++; - } - - return num; - }; - - obj.deleteElement = function (index) { - if (!obj.headers.children[index]) { - return false; - } else { - obj.headers.removeChild(obj.headers.children[index]); - obj.content.removeChild(obj.content.children[index]); - } - - obj.open(0); - - if (typeof obj.options.ondelete == "function") { - obj.options.ondelete(el, index); - } - }; - - obj.appendElement = function (title, cb) { - if (!title) { - var title = prompt("Title?", ""); - } - - if (title) { - // Add content - var div = document.createElement("div"); - obj.content.appendChild(div); - - // Add headers - var h = document.createElement("div"); - h.innerHTML = title; - h.content = div; - obj.headers.insertBefore(h, obj.headers.lastChild); - - // Sortable - if (obj.options.allowChangePosition) { - h.setAttribute("draggable", "true"); - } - // Open new tab - obj.selectIndex(h); - - // Callback - if (typeof cb == "function") { - cb(div, h); - } - - // Return element - return div; - } - }; - - obj.getActive = function () { - for (var i = 0; i < obj.headers.children.length; i++) { - if (obj.headers.children[i].classList.contains("jtabs-selected")) { - return i; - } - } - return 0; - }; - - obj.updateContent = function (position, newContent) { - if (typeof newContent !== "string") { - var contentItem = newContent; - } else { - var contentItem = document.createElement("div"); - contentItem.innerHTML = newContent; - } - - if (obj.content.children[position].classList.contains("jtabs-selected")) { - newContent.classList.add("jtabs-selected"); - } - - obj.content.replaceChild(newContent, obj.content.children[position]); - - setBorder(); - }; - - obj.updatePosition = function (f, t) { - // Ondrop update position of content - if (f > t) { - obj.content.insertBefore( - obj.content.children[f], - obj.content.children[t] - ); - } else { - obj.content.insertBefore( - obj.content.children[f], - obj.content.children[t].nextSibling - ); - } - - // Open destination tab - obj.open(t); - - // Call event - if (typeof obj.options.onchangeposition == "function") { - obj.options.onchangeposition(obj.headers, f, t); - } - }; - - obj.move = function (f, t) { - if (f > t) { - obj.headers.insertBefore( - obj.headers.children[f], - obj.headers.children[t] - ); - } else { - obj.headers.insertBefore( - obj.headers.children[f], - obj.headers.children[t].nextSibling - ); - } - - obj.updatePosition(f, t); - }; - - obj.setBorder = setBorder; - - obj.init = function () { - el.innerHTML = ""; - - // Make sure the component is blank - obj.headers = document.createElement("div"); - obj.content = document.createElement("div"); - obj.headers.classList.add("jtabs-headers"); - obj.content.classList.add("jtabs-content"); - - if (obj.options.palette) { - el.classList.add("jtabs-modern"); - } else { - el.classList.remove("jtabs-modern"); - } - - // Padding - if (obj.options.padding) { - obj.content.style.padding = parseInt(obj.options.padding) + "px"; - } - - // Header - var header = document.createElement("div"); - header.className = "jtabs-headers-container"; - header.appendChild(obj.headers); - if (obj.options.maxWidth) { - header.style.maxWidth = parseInt(obj.options.maxWidth) + "px"; - } - - // Controls - var controls = document.createElement("div"); - controls.className = "jtabs-controls"; - controls.setAttribute("draggable", "false"); - header.appendChild(controls); - - // Append DOM elements - if (obj.options.position == "bottom") { - el.appendChild(obj.content); - el.appendChild(header); - } else { - el.appendChild(header); - el.appendChild(obj.content); - } - - // New button - if (obj.options.allowCreate == true) { - var add = document.createElement("div"); - add.className = "jtabs-add"; - add.onclick = function () { - obj.create(); - }; - controls.appendChild(add); - } - - prev = document.createElement("div"); - prev.className = "jtabs-prev"; - prev.onclick = function () { - updateControls(obj.headers.scrollLeft - obj.headers.offsetWidth); - }; - controls.appendChild(prev); - - next = document.createElement("div"); - next.className = "jtabs-next"; - next.onclick = function () { - updateControls(obj.headers.scrollLeft + obj.headers.offsetWidth); - }; - controls.appendChild(next); - - // Data - for (var i = 0; i < obj.options.data.length; i++) { - // Title - if (obj.options.data[i].titleElement) { - var headerItem = obj.options.data[i].titleElement; - } else { - var headerItem = document.createElement("div"); - } - // Icon - if (obj.options.data[i].icon) { - var iconContainer = document.createElement("div"); - var icon = document.createElement("i"); - icon.classList.add("material-icons"); - icon.innerHTML = obj.options.data[i].icon; - iconContainer.appendChild(icon); - headerItem.appendChild(iconContainer); - } - // Title - if (obj.options.data[i].title) { - var title = document.createTextNode(obj.options.data[i].title); - headerItem.appendChild(title); - } - // Width - if (obj.options.data[i].width) { - headerItem.style.width = obj.options.data[i].width; - } - // Content - if (obj.options.data[i].contentElement) { - var contentItem = obj.options.data[i].contentElement; - } else { - var contentItem = document.createElement("div"); - contentItem.innerHTML = obj.options.data[i].content; - } - obj.headers.appendChild(headerItem); - obj.content.appendChild(contentItem); - } - - // Animation - border = document.createElement("div"); - border.className = "jtabs-border"; - obj.headers.appendChild(border); - - if (obj.options.animation) { - el.classList.add("jtabs-animation"); - } - - // Events - obj.headers.addEventListener("click", function (e) { - if (e.target.parentNode.classList.contains("jtabs-headers")) { - var target = e.target; - } else { - if (e.target.tagName == "I") { - var target = e.target.parentNode.parentNode; - } else { - var target = e.target.parentNode; - } - } - - var index = obj.selectIndex(target); - - if (typeof obj.options.onclick == "function") { - obj.options.onclick( - el, - obj, - index, - obj.headers.children[index], - obj.content.children[index] - ); - } - }); - - obj.headers.addEventListener("contextmenu", function (e) { - obj.selectIndex(e.target); - }); - - if (obj.headers.children.length) { - // Open first tab - obj.open(0); - } - - // Update controls - updateControls(0); - - if (obj.options.allowChangePosition == true) { - jSuites.sorting(obj.headers, { - direction: 1, - ondrop: function (a, b, c) { - obj.updatePosition(b, c); - }, - }); - } - - if (typeof obj.options.onload == "function") { - obj.options.onload(el, obj); - } - }; - - // Loading existing nodes as the data - if (el.children[0] && el.children[0].children.length) { - // Create from existing elements - for (var i = 0; i < el.children[0].children.length; i++) { - var item = - obj.options.data && obj.options.data[i] ? obj.options.data[i] : {}; - - if (el.children[1] && el.children[1].children[i]) { - item.titleElement = el.children[0].children[i]; - item.contentElement = el.children[1].children[i]; - } else { - item.contentElement = el.children[0].children[i]; - } - - obj.options.data[i] = item; - } - } - - // Remote controller flag - var loadingRemoteData = false; - - // Create from data - if (obj.options.data) { - // Append children - for (var i = 0; i < obj.options.data.length; i++) { - if (obj.options.data[i].url) { - jSuites.ajax({ - url: obj.options.data[i].url, - type: "GET", - dataType: "text/html", - index: i, - success: function (result) { - obj.options.data[this.index].content = result; - }, - complete: function () { - obj.init(); - }, - }); - - // Flag loading - loadingRemoteData = true; - } - } - } - - if (!loadingRemoteData) { - obj.init(); - } - - el.tabs = obj; - - return obj; - }; - - jSuites.tags = function (el, options) { - // Redefine configuration - if (el.tags) { - return el.tags.setOptions(options, true); - } - - var obj = { type: "tags" }; - obj.options = {}; - - // Limit - var limit = function () { - return obj.options.limit && el.children.length >= obj.options.limit - ? true - : false; - }; - - // Search helpers - var search = null; - var searchContainer = null; - - obj.setOptions = function (options, reset) { - /** - * @typedef {Object} defaults - * @property {(string|Array)} value - Initial value of the compontent - * @property {number} limit - Max number of tags inside the element - * @property {string} search - The URL for suggestions - * @property {string} placeholder - The default instruction text on the element - * @property {validation} validation - Method to validate the tags - * @property {requestCallback} onbeforechange - Method to be execute before any changes on the element - * @property {requestCallback} onchange - Method to be execute after any changes on the element - * @property {requestCallback} onfocus - Method to be execute when on focus - * @property {requestCallback} onblur - Method to be execute when on blur - * @property {requestCallback} onload - Method to be execute when the element is loaded - */ - var defaults = { - value: "", - limit: null, - limitMessage: null, - search: null, - placeholder: null, - validation: null, - onbeforepaste: null, - onbeforechange: null, - onlimit: null, - onchange: null, - onfocus: null, - onblur: null, - onload: null, - colors: null, - }; - - // Loop through though the default configuration - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - if (typeof obj.options[property] == "undefined" || reset === true) { - obj.options[property] = defaults[property]; - } - } - } - - // Placeholder - if (obj.options.placeholder) { - el.setAttribute("data-placeholder", obj.options.placeholder); - } else { - el.removeAttribute("data-placeholder"); - } - el.placeholder = obj.options.placeholder; - - // Update value - obj.setValue(obj.options.value); - - // Validate items - filter(); - - // Create search box - if (obj.options.search) { - if (!searchContainer) { - searchContainer = document.createElement("div"); - el.parentNode.insertBefore(searchContainer, el.nextSibling); - - // Create container - search = jSuites.search(searchContainer, { - data: obj.options.search, - onselect: function (a, b, c) { - obj.selectIndex(b, c); - }, - }); - } - } else { - if (searchContainer) { - search = null; - searchContainer.remove(); - searchContainer = null; - } - } - - return obj; - }; - - /** - * Add a new tag to the element - * @param {(?string|Array)} value - The value of the new element - */ - obj.add = function (value, focus) { - if (typeof obj.options.onbeforechange == "function") { - var ret = obj.options.onbeforechange(el, obj, obj.options.value, value); - if (ret === false) { - return false; - } else { - if (ret != null) { - value = ret; - } - } - } - - // Make sure search is closed - if (search) { - search.close(); - } - - if (limit()) { - if (typeof obj.options.onlimit == "function") { - obj.options.onlimit(obj, obj.options.limit); - } else if (obj.options.limitMessage) { - alert(obj.options.limitMessage + " " + obj.options.limit); - } - } else { - // Get node - var node = jSuites.getNode(); - - if ( - node && - node.parentNode && - node.parentNode.classList.contains("jtags") && - node.nextSibling && - !(node.nextSibling.innerText && node.nextSibling.innerText.trim()) - ) { - div = node.nextSibling; - } else { - // Remove not used last item - if (el.lastChild) { - if (!el.lastChild.innerText.trim()) { - el.removeChild(el.lastChild); - } - } - - // Mix argument string or array - if (!value || typeof value == "string") { - var div = createElement(value, value, node); - } else { - for (var i = 0; i <= value.length; i++) { - if (!limit()) { - if (!value[i] || typeof value[i] == "string") { - var t = value[i] || ""; - var v = null; - } else { - var t = value[i].text; - var v = value[i].value; - } - - // Add element - var div = createElement(t, v); - } - } - } - - // Change - change(); - } - - // Place caret - if (focus) { - setFocus(div); - } - } - }; - - obj.setLimit = function (limit) { - obj.options.limit = limit; - var n = el.children.length - limit; - while (el.children.length > limit) { - el.removeChild(el.lastChild); - } - }; - - // Remove a item node - obj.remove = function (node) { - // Remove node - node.parentNode.removeChild(node); - // Make sure element is not blank - if (!el.children.length) { - obj.add("", true); - } else { - change(); - } - }; - - /** - * Get all tags in the element - * @return {Array} data - All tags as an array - */ - obj.getData = function () { - var data = []; - for (var i = 0; i < el.children.length; i++) { - // Get value - var text = el.children[i].innerText.replace("\n", ""); - // Get id - var value = el.children[i].getAttribute("data-value"); - if (!value) { - value = text; - } - // Item - if (text || value) { - data.push({ text: text, value: value }); - } - } - return data; - }; - - /** - * Get the value of one tag. Null for all tags - * @param {?number} index - Tag index number. Null for all tags. - * @return {string} value - All tags separated by comma - */ - obj.getValue = function (index) { - var value = null; - - if (index != null) { - // Get one individual value - value = el.children[index].getAttribute("data-value"); - if (!value) { - value = el.children[index].innerText.replace("\n", ""); - } - } else { - // Get all - var data = []; - for (var i = 0; i < el.children.length; i++) { - value = el.children[i].innerText.replace("\n", ""); - if (value) { - data.push(obj.getValue(i)); - } - } - value = data.join(","); - } - - return value; - }; - - /** - * Set the value of the element based on a string separeted by (,|;|\r\n) - * @param {mixed} value - A string or array object with values - */ - obj.setValue = function (mixed) { - if (!mixed) { - obj.reset(); - } else { - if (el.value != mixed) { - if (Array.isArray(mixed)) { - obj.add(mixed); - } else { - // Remove whitespaces - var text = ("" + mixed).trim(); - // Tags - var data = extractTags(text); - // Reset - el.innerHTML = ""; - // Add tags to the element - obj.add(data); - } - } - } - }; - - /** - * Reset the data from the element - */ - obj.reset = function () { - // Empty class - el.classList.add("jtags-empty"); - // Empty element - el.innerHTML = "
"; - // Execute changes - change(); - }; - - /** - * Verify if all tags in the element are valid - * @return {boolean} - */ - obj.isValid = function () { - var test = 0; - for (var i = 0; i < el.children.length; i++) { - if (el.children[i].classList.contains("jtags_error")) { - test++; - } - } - return test == 0 ? true : false; - }; - - /** - * Add one element from the suggestions to the element - * @param {object} item - Node element in the suggestions container - */ - obj.selectIndex = function (text, value) { - var node = jSuites.getNode(); - if (node) { - // Append text to the caret - node.innerText = text; - // Set node id - if (value) { - node.setAttribute("data-value", value); - } - // Remove any error - node.classList.remove("jtags_error"); - if (!limit()) { - // Add new item - obj.add("", true); - } - } - }; - - /** - * Search for suggestions - * @param {object} node - Target node for any suggestions - */ - obj.search = function (node) { - // Search for - var terms = node.innerText; - }; - - // Destroy tags element - obj.destroy = function () { - // Bind events - el.removeEventListener("mouseup", tagsMouseUp); - el.removeEventListener("keydown", tagsKeyDown); - el.removeEventListener("keyup", tagsKeyUp); - el.removeEventListener("paste", tagsPaste); - el.removeEventListener("focus", tagsFocus); - el.removeEventListener("blur", tagsBlur); - - // Remove element - el.parentNode.removeChild(el); - }; - - var setFocus = function (node) { - if (el.children.length > 1) { - var range = document.createRange(); - var sel = window.getSelection(); - if (!node) { - var node = el.childNodes[el.childNodes.length - 1]; - } - range.setStart(node, node.length); - range.collapse(true); - sel.removeAllRanges(); - sel.addRange(range); - el.scrollLeft = el.scrollWidth; - } - }; - - var createElement = function (label, value, node) { - var div = document.createElement("div"); - div.innerHTML = label ? label : ""; - if (value) { - div.setAttribute("data-value", value); - } - - if (node && node.parentNode.classList.contains("jtags")) { - el.insertBefore(div, node.nextSibling); - } else { - el.appendChild(div); - } - - return div; - }; - - var change = function () { - // Value - var value = obj.getValue(); - - if (value != obj.options.value) { - obj.options.value = value; - if (typeof obj.options.onchange == "function") { - obj.options.onchange(el, obj, obj.options.value); - } - - // Lemonade JS - if (el.value != obj.options.value) { - el.value = obj.options.value; - if (typeof el.oninput == "function") { - el.oninput({ - type: "input", - target: el, - value: el.value, - }); - } - } - } - - filter(); - }; - - /** - * Filter tags - */ - var filter = function () { - for (var i = 0; i < el.children.length; i++) { - // Create label design - if (!obj.getValue(i)) { - el.children[i].classList.remove("jtags_label"); - } else { - el.children[i].classList.add("jtags_label"); - - // Validation in place - if (typeof obj.options.validation == "function") { - if (obj.getValue(i)) { - if ( - !obj.options.validation( - el.children[i], - el.children[i].innerText, - el.children[i].getAttribute("data-value") - ) - ) { - el.children[i].classList.add("jtags_error"); - } else { - el.children[i].classList.remove("jtags_error"); - } - } else { - el.children[i].classList.remove("jtags_error"); - } - } else { - el.children[i].classList.remove("jtags_error"); - } - } - } - - isEmpty(); - }; - - var isEmpty = function () { - // Can't be empty - if (!el.innerText.trim()) { - el.innerHTML = "
"; - el.classList.add("jtags-empty"); - } else { - el.classList.remove("jtags-empty"); - } - }; - - /** - * Extract tags from a string - * @param {string} text - Raw string - * @return {Array} data - Array with extracted tags - */ - var extractTags = function (text) { - /** @type {Array} */ - var data = []; - - /** @type {string} */ - var word = ""; - - // Remove whitespaces - text = text.trim(); - - if (text) { - for (var i = 0; i < text.length; i++) { - if (text[i] == "," || text[i] == ";" || text[i] == "\n") { - if (word) { - data.push(word.trim()); - word = ""; - } - } else { - word += text[i]; - } - } - - if (word) { - data.push(word); - } - } - - return data; - }; - - /** @type {number} */ - var anchorOffset = 0; - - /** - * Processing event keydown on the element - * @param e {object} - */ - var tagsKeyDown = function (e) { - // Anchoroffset - anchorOffset = window.getSelection().anchorOffset; - - // Verify if is empty - isEmpty(); - - // Comma - if (e.key === "Tab" || e.key === ";" || e.key === ",") { - var n = window.getSelection().anchorOffset; - if (n > 1) { - if (limit()) { - if (typeof obj.options.onlimit == "function") { - obj.options.onlimit(obj, obj.options.limit); - } - } else { - obj.add("", true); - } - } - e.preventDefault(); - } else if (e.key == "Enter") { - if (!search || !search.isOpened()) { - var n = window.getSelection().anchorOffset; - if (n > 1) { - if (!limit()) { - obj.add("", true); - } - } - e.preventDefault(); - } - } else if (e.key == "Backspace") { - // Back space - do not let last item to be removed - if (el.children.length == 1 && window.getSelection().anchorOffset < 1) { - e.preventDefault(); - } - } - - // Search events - if (search) { - search.keydown(e); - } - }; - - /** - * Processing event keyup on the element - * @param e {object} - */ - var tagsKeyUp = function (e) { - if (e.which == 39) { - // Right arrow - var n = window.getSelection().anchorOffset; - if (n > 1 && n == anchorOffset) { - obj.add("", true); - } - } else if (e.which == 13 || e.which == 38 || e.which == 40) { - e.preventDefault(); - } else { - if (search) { - search.keyup(e); - } - } - - filter(); - }; - - /** - * Processing event paste on the element - * @param e {object} - */ - var tagsPaste = function (e) { - if (e.clipboardData || e.originalEvent.clipboardData) { - var text = (e.originalEvent || e).clipboardData.getData("text/plain"); - } else if (window.clipboardData) { - var text = window.clipboardData.getData("Text"); - } - - var data = extractTags(text); - - if (typeof obj.options.onbeforepaste == "function") { - var ret = obj.options.onbeforepaste(el, obj, data); - if (ret === false) { - e.preventDefault(); - return false; - } else { - if (ret) { - data = ret; - } - } - } - - if (data.length > 1) { - obj.add(data, true); - e.preventDefault(); - } else if (data[0]) { - document.execCommand("insertText", false, data[0]); - e.preventDefault(); - } - }; - - /** - * Processing event mouseup on the element - * @param e {object} - */ - var tagsMouseUp = function (e) { - if ( - e.target.parentNode && - e.target.parentNode.classList.contains("jtags") - ) { - if ( - e.target.classList.contains("jtags_label") || - e.target.classList.contains("jtags_error") - ) { - var rect = e.target.getBoundingClientRect(); - if (rect.width - (e.clientX - rect.left) < 16) { - obj.remove(e.target); - } - } - } - - // Set focus in the last item - if (e.target == el) { - setFocus(); - } - }; - - var tagsFocus = function () { - if (!el.classList.contains("jtags-focus")) { - if (!el.children.length || obj.getValue(el.children.length - 1)) { - if (!limit()) { - createElement(""); - } - } - - if (typeof obj.options.onfocus == "function") { - obj.options.onfocus(el, obj, obj.getValue()); - } - - el.classList.add("jtags-focus"); - } - }; - - var tagsBlur = function () { - if (el.classList.contains("jtags-focus")) { - if (search) { - search.close(); - } - - for (var i = 0; i < el.children.length - 1; i++) { - // Create label design - if (!obj.getValue(i)) { - el.removeChild(el.children[i]); - } - } - - change(); - - el.classList.remove("jtags-focus"); - - if (typeof obj.options.onblur == "function") { - obj.options.onblur(el, obj, obj.getValue()); - } - } - }; - - var init = function () { - // Bind events - if ("touchend" in document.documentElement === true) { - el.addEventListener("touchend", tagsMouseUp); - } else { - el.addEventListener("mouseup", tagsMouseUp); - } - - el.addEventListener("keydown", tagsKeyDown); - el.addEventListener("keyup", tagsKeyUp); - el.addEventListener("paste", tagsPaste); - el.addEventListener("focus", tagsFocus); - el.addEventListener("blur", tagsBlur); - - // Editable - el.setAttribute("contenteditable", true); - - // Prepare container - el.classList.add("jtags"); - - // Initial options - obj.setOptions(options); - - if (typeof obj.options.onload == "function") { - obj.options.onload(el, obj); - } - - // Change methods - el.change = obj.setValue; - - // Global generic value handler - el.val = function (val) { - if (val === undefined) { - return obj.getValue(); - } else { - obj.setValue(val); - } - }; - - el.tags = obj; - }; - - init(); - - return obj; - }; - - jSuites.toolbar = function (el, options) { - // New instance - var obj = { type: "toolbar" }; - obj.options = {}; - - // Default configuration - var defaults = { - app: null, - container: false, - badge: false, - title: false, - responsive: false, - maxWidth: null, - bottom: true, - items: [], - }; - - // Loop through our object - for (var property in defaults) { - if (options && options.hasOwnProperty(property)) { - obj.options[property] = options[property]; - } else { - obj.options[property] = defaults[property]; - } - } - - if (!el && options.app && options.app.el) { - el = document.createElement("div"); - options.app.el.appendChild(el); - } - - // Arrow - var toolbarArrow = document.createElement("div"); - toolbarArrow.classList.add("jtoolbar-item"); - toolbarArrow.classList.add("jtoolbar-arrow"); - - var toolbarFloating = document.createElement("div"); - toolbarFloating.classList.add("jtoolbar-floating"); - toolbarArrow.appendChild(toolbarFloating); - - obj.selectItem = function (element) { - var elements = toolbarContent.children; - for (var i = 0; i < elements.length; i++) { - if (element != elements[i]) { - elements[i].classList.remove("jtoolbar-selected"); - } - } - element.classList.add("jtoolbar-selected"); - }; - - obj.hide = function () { - jSuites.animation.slideBottom(el, 0, function () { - el.style.display = "none"; - }); - }; - - obj.show = function () { - el.style.display = ""; - jSuites.animation.slideBottom(el, 1); - }; - - obj.get = function () { - return el; - }; - - obj.setBadge = function (index, value) { - toolbarContent.children[index].children[1].firstChild.innerHTML = value; - }; - - obj.destroy = function () { - toolbar.remove(); - el.innerHTML = ""; - }; - - obj.update = function (a, b) { - for (var i = 0; i < toolbarContent.children.length; i++) { - // Toolbar element - var toolbarItem = toolbarContent.children[i]; - // State management - if (typeof toolbarItem.updateState == "function") { - toolbarItem.updateState(el, obj, toolbarItem, a, b); - } - } - for (var i = 0; i < toolbarFloating.children.length; i++) { - // Toolbar element - var toolbarItem = toolbarFloating.children[i]; - // State management - if (typeof toolbarItem.updateState == "function") { - toolbarItem.updateState(el, obj, toolbarItem, a, b); - } - } - }; - - obj.create = function (items) { - // Reset anything in the toolbar - toolbarContent.innerHTML = ""; - // Create elements in the toolbar - for (var i = 0; i < items.length; i++) { - var toolbarItem = document.createElement("div"); - toolbarItem.classList.add("jtoolbar-item"); - - if (items[i].width) { - toolbarItem.style.width = parseInt(items[i].width) + "px"; - } - - if (items[i].k) { - toolbarItem.k = items[i].k; - } - - if (items[i].tooltip) { - toolbarItem.setAttribute("title", items[i].tooltip); - } - - // Id - if (items[i].id) { - toolbarItem.setAttribute("id", items[i].id); - } - - // Selected - if (items[i].updateState) { - toolbarItem.updateState = items[i].updateState; - } - - if (items[i].active) { - toolbarItem.classList.add("jtoolbar-active"); - } - - if (items[i].type == "select" || items[i].type == "dropdown") { - jSuites.picker(toolbarItem, items[i]); - } else if (items[i].type == "divisor") { - toolbarItem.classList.add("jtoolbar-divisor"); - } else if (items[i].type == "label") { - toolbarItem.classList.add("jtoolbar-label"); - toolbarItem.innerHTML = items[i].content; - } else { - // Material icons - var toolbarIcon = document.createElement("i"); - if (typeof items[i].class === "undefined") { - toolbarIcon.classList.add("material-icons"); - } else { - var c = items[i].class.split(" "); - for (var j = 0; j < c.length; j++) { - toolbarIcon.classList.add(c[j]); - } - } - toolbarIcon.innerHTML = items[i].content ? items[i].content : ""; - toolbarItem.appendChild(toolbarIcon); - - // Badge options - if (obj.options.badge == true) { - var toolbarBadge = document.createElement("div"); - toolbarBadge.classList.add("jbadge"); - var toolbarBadgeContent = document.createElement("div"); - toolbarBadgeContent.innerHTML = items[i].badge - ? items[i].badge - : ""; - toolbarBadge.appendChild(toolbarBadgeContent); - toolbarItem.appendChild(toolbarBadge); - } - - // Title - if (items[i].title) { - if (obj.options.title == true) { - var toolbarTitle = document.createElement("span"); - toolbarTitle.innerHTML = items[i].title; - toolbarItem.appendChild(toolbarTitle); - } else { - toolbarItem.setAttribute("title", items[i].title); - } - } - - if (obj.options.app && items[i].route) { - // Route - toolbarItem.route = items[i].route; - // Onclick for route - toolbarItem.onclick = function () { - obj.options.app.pages(this.route); - }; - // Create pages - obj.options.app.pages(items[i].route, { - toolbarItem: toolbarItem, - closed: true, - }); - } - } - - if (items[i].onclick) { - toolbarItem.onclick = items[i].onclick.bind( - items[i], - el, - obj, - toolbarItem - ); - } - - toolbarContent.appendChild(toolbarItem); - } - - // Fits to the page - setTimeout(function () { - obj.refresh(); - }, 0); - }; - - obj.open = function () { - toolbarArrow.classList.add("jtoolbar-arrow-selected"); - - var rectElement = el.getBoundingClientRect(); - var rect = toolbarFloating.getBoundingClientRect(); - if (rect.bottom > window.innerHeight || obj.options.bottom) { - toolbarFloating.style.bottom = "0"; - } else { - toolbarFloating.style.removeProperty("bottom"); - } - - toolbarFloating.style.right = "0"; - - toolbarArrow.children[0].focus(); - // Start tracking - jSuites.tracking(obj, true); - }; - - obj.close = function () { - toolbarArrow.classList.remove("jtoolbar-arrow-selected"); - // End tracking - jSuites.tracking(obj, false); - }; - - obj.refresh = function () { - if (obj.options.responsive == true) { - // Width of the c - var rect = el.parentNode.getBoundingClientRect(); - if (!obj.options.maxWidth) { - obj.options.maxWidth = rect.width; - } - // Available parent space - var available = parseInt(obj.options.maxWidth); - // Remove arrow - if (toolbarArrow.parentNode) { - toolbarArrow.parentNode.removeChild(toolbarArrow); - } - // Move all items to the toolbar - while (toolbarFloating.firstChild) { - toolbarContent.appendChild(toolbarFloating.firstChild); - } - // Toolbar is larger than the parent, move elements to the floating element - if (available < toolbarContent.offsetWidth) { - // Give space to the floating element - available -= 50; - // Move to the floating option - while ( - toolbarContent.lastChild && - available < toolbarContent.offsetWidth - ) { - toolbarFloating.insertBefore( - toolbarContent.lastChild, - toolbarFloating.firstChild - ); - } - } - // Show arrow - if (toolbarFloating.children.length > 0) { - toolbarContent.appendChild(toolbarArrow); - } - } - }; - - obj.setReadonly = function (state) { - state = state ? "add" : "remove"; - el.classList[state]("jtoolbar-readonly"); - }; - - el.onclick = function (e) { - var element = jSuites.findElement(e.target, "jtoolbar-item"); - if (element) { - obj.selectItem(element); - } - - if (e.target.classList.contains("jtoolbar-arrow")) { - obj.open(); - } - }; - - window.addEventListener("resize", function () { - obj.refresh(); - }); - - // Toolbar - el.classList.add("jtoolbar"); - // Reset content - el.innerHTML = ""; - // Container - if (obj.options.container == true) { - el.classList.add("jtoolbar-container"); - } - // Content - var toolbarContent = document.createElement("div"); - el.appendChild(toolbarContent); - // Special toolbar for mobile applications - if (obj.options.app) { - el.classList.add("jtoolbar-mobile"); - } - // Create toolbar - obj.create(obj.options.items); - // Shortcut - el.toolbar = obj; - - return obj; - }; - - jSuites.validations = (function () { - /** - * Options: Object, - * Properties: - * Constraint, - * Reference, - * Value - */ - - var isNumeric = function (num) { - return !isNaN(num) && num !== null && num !== ""; - }; - - var numberCriterias = { - between: function (value, range) { - return value >= range[0] && value <= range[1]; - }, - "not between": function (value, range) { - return value < range[0] || value > range[1]; - }, - "<": function (value, range) { - return value < range[0]; - }, - "<=": function (value, range) { - return value <= range[0]; - }, - ">": function (value, range) { - return value > range[0]; - }, - ">=": function (value, range) { - return value >= range[0]; - }, - "=": function (value, range) { - return value == range[0]; - }, - "!=": function (value, range) { - return value != range[0]; - }, - }; - - var dateCriterias = { - "valid date": function () { - return true; - }, - "=": function (value, range) { - return value === range[0]; - }, - "<": function (value, range) { - return value < range[0]; - }, - "<=": function (value, range) { - return value <= range[0]; - }, - ">": function (value, range) { - return value > range[0]; - }, - ">=": function (value, range) { - return value >= range[0]; - }, - between: function (value, range) { - return value >= range[0] && value <= range[1]; - }, - "not between": function (value, range) { - return value < range[0] || value > range[1]; - }, - }; - - var textCriterias = { - contains: function (value, range) { - return value.includes(range[0]); - }, - "not contains": function (value, range) { - return !value.includes(range[0]); - }, - "begins with": function (value, range) { - return value.startsWith(range[0]); - }, - "ends with": function (value, range) { - return value.endsWith(range[0]); - }, - "=": function (value, range) { - return value === range[0]; - }, - "valid email": function (value) { - var pattern = new RegExp(/^[^\s@]+@[^\s@]+\.[^\s@]+$/); - - return pattern.test(value); - }, - "valid url": function (value) { - var pattern = new RegExp( - /(((https?:\/\/)|(www\.))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]+)/gi - ); - - return pattern.test(value); - }, - }; - - // Component router - var component = function (value, options) { - if (typeof component[options.type] === "function") { - if (options.allowBlank && value === "") { - return true; - } - - return component[options.type](value, options); - } - return null; - }; - - component.url = function () { - var pattern = new RegExp( - /(((https?:\/\/)|(www\.))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]+)/gi - ); - return pattern.test(data) ? true : false; - }; - - component.email = function (data) { - var pattern = new RegExp(/^[^\s@]+@[^\s@]+\.[^\s@]+$/); - return data && pattern.test(data) ? true : false; - }; - - component.required = function (data) { - return data.trim() ? true : false; - }; - - component.exist = function (data, options) { - return !!data.toString(); - }; - - component["not exist"] = function (data, options) { - return !data.toString(); - }; - - component.number = function (data, options) { - if (!isNumeric(data)) { - return false; - } - - if (!options || !options.criteria) { - return true; - } - - if (!numberCriterias[options.criteria]) { - return false; - } - - var values = options.value.map(function (num) { - return parseFloat(num); - }); - - return numberCriterias[options.criteria](data, values); - }; - - component.login = function (data) { - var pattern = new RegExp(/^[a-zA-Z0-9\_\-\.\s+]+$/); - return data && pattern.test(data) ? true : false; - }; - - component.list = function (data, options) { - var dataType = typeof data; - if (dataType !== "string" && dataType !== "number") { - return false; - } - if (typeof options.value[0] === "string") { - var list = options.value[0].split(","); - } else { - var list = options.value[0]; - } - - var validOption = list.findIndex(function name(item) { - return item == data; - }); - - return validOption > -1; - }; - - component.date = function (data, options) { - if (new Date(data) == "Invalid Date") { - return false; - } - - if (!options || !options.criteria) { - return true; - } - - if (!dateCriterias[options.criteria]) { - return false; - } - - var values = options.value.map(function (date) { - return new Date(date).getTime(); - }); - - return dateCriterias[options.criteria](new Date(data).getTime(), values); - }; - - component.text = function (data, options) { - if (typeof data !== "string") { - return false; - } - - if (!options || !options.criteria) { - return true; - } - - if (!textCriterias[options.criteria]) { - return false; - } - - return textCriterias[options.criteria](data, options.value); - }; - - component.textLength = function (data, options) { - data = data.toString(); - - return component.number(data.length, options); - }; - - return component; - })(); - - return jSuites; -}); - /** * Jspreadsheet v4.10.1 * diff --git a/assets/jsuites.js b/assets/jsuites.js new file mode 100644 index 0000000..09fadc6 --- /dev/null +++ b/assets/jsuites.js @@ -0,0 +1,13310 @@ +/** + * (c) jSuites Javascript Web Components + * + * Website: https://jsuites.net + * Description: Create amazing web based applications. + * + * MIT License + * + */ +(function (global, factory) { + typeof exports === "object" && typeof module !== "undefined" + ? (module.exports = factory()) + : typeof define === "function" && define.amd + ? define(factory) + : (global.jSuites = factory()); +})(this, function () { + "use strict"; + + var jSuites = {}; + + var Version = "4.14.3"; + + var Events = function () { + document.jsuitesComponents = []; + + var find = function (DOMElement, component) { + if ( + DOMElement[component.type] && + DOMElement[component.type] == component + ) { + return true; + } + if (DOMElement.component && DOMElement.component == component) { + return true; + } + if (DOMElement.parentNode) { + return find(DOMElement.parentNode, component); + } + return false; + }; + + var isOpened = function (e) { + if (document.jsuitesComponents && document.jsuitesComponents.length > 0) { + for (var i = 0; i < document.jsuitesComponents.length; i++) { + if ( + document.jsuitesComponents[i] && + !find(e, document.jsuitesComponents[i]) + ) { + document.jsuitesComponents[i].close(); + } + } + } + }; + + // Width of the border + var cornerSize = 15; + + // Current element + var element = null; + + // Controllers + var editorAction = false; + + // Event state + var state = { + x: null, + y: null, + }; + + // Tooltip element + var tooltip = document.createElement("div"); + tooltip.classList.add("jtooltip"); + + // Events + var mouseDown = function (e) { + // Check if this is the floating + var item = jSuites.findElement(e.target, "jpanel"); + // Jfloating found + if (item && !item.classList.contains("readonly")) { + // Add focus to the chart container + item.focus(); + // Keep the tracking information + var rect = e.target.getBoundingClientRect(); + editorAction = { + e: item, + x: e.clientX, + y: e.clientY, + w: rect.width, + h: rect.height, + d: item.style.cursor, + resizing: item.style.cursor ? true : false, + actioned: false, + }; + + // Make sure width and height styling is OK + if (!item.style.width) { + item.style.width = rect.width + "px"; + } + + if (!item.style.height) { + item.style.height = rect.height + "px"; + } + + // Remove any selection from the page + var s = window.getSelection(); + if (s.rangeCount) { + for (var i = 0; i < s.rangeCount; i++) { + s.removeRange(s.getRangeAt(i)); + } + } + + e.preventDefault(); + e.stopPropagation(); + } else { + // No floating action found + editorAction = false; + } + + // Verify current components tracking + if (e.changedTouches && e.changedTouches[0]) { + var x = e.changedTouches[0].clientX; + var y = e.changedTouches[0].clientY; + } else { + var x = e.clientX; + var y = e.clientY; + } + + // Which component I am clicking + var path = e.path || (e.composedPath && e.composedPath()); + + // If path available get the first element in the chain + if (path) { + element = path[0]; + } else { + // Try to guess using the coordinates + if (e.target && e.target.shadowRoot) { + var d = e.target.shadowRoot; + } else { + var d = document; + } + // Get the first target element + element = d.elementFromPoint(x, y); + } + + isOpened(element); + }; + + var mouseUp = function (e) { + if (editorAction && editorAction.e) { + if (typeof editorAction.e.refresh == "function" && state.actioned) { + editorAction.e.refresh(); + } + editorAction.e.style.cursor = ""; + } + + // Reset + state = { + x: null, + y: null, + }; + + editorAction = false; + }; + + var mouseMove = function (e) { + if (editorAction) { + var x = e.clientX || e.pageX; + var y = e.clientY || e.pageY; + + // Action on going + if (!editorAction.resizing) { + if (state.x == null && state.y == null) { + state.x = x; + state.y = y; + } + + var dx = x - state.x; + var dy = y - state.y; + var top = editorAction.e.offsetTop + dy; + var left = editorAction.e.offsetLeft + dx; + + // Update position + editorAction.e.style.top = top + "px"; + editorAction.e.style.left = left + "px"; + editorAction.e.style.cursor = "move"; + + state.x = x; + state.y = y; + + // Update element + if (typeof editorAction.e.refresh == "function") { + state.actioned = true; + editorAction.e.refresh("position", top, left); + } + } else { + var width = null; + var height = null; + + if ( + editorAction.d == "e-resize" || + editorAction.d == "ne-resize" || + editorAction.d == "se-resize" + ) { + // Update width + width = editorAction.w + (x - editorAction.x); + editorAction.e.style.width = width + "px"; + + // Update Height + if (e.shiftKey) { + var newHeight = + (x - editorAction.x) * (editorAction.h / editorAction.w); + height = editorAction.h + newHeight; + editorAction.e.style.height = height + "px"; + } else { + var newHeight = false; + } + } + + if (!newHeight) { + if ( + editorAction.d == "s-resize" || + editorAction.d == "se-resize" || + editorAction.d == "sw-resize" + ) { + height = editorAction.h + (y - editorAction.y); + editorAction.e.style.height = height + "px"; + } + } + + // Update element + if (typeof editorAction.e.refresh == "function") { + state.actioned = true; + editorAction.e.refresh("dimensions", width, height); + } + } + } else { + // Resizing action + var item = jSuites.findElement(e.target, "jpanel"); + // Found eligible component + if (item) { + if (item.getAttribute("tabindex")) { + var rect = item.getBoundingClientRect(); + if (e.clientY - rect.top < cornerSize) { + if (rect.width - (e.clientX - rect.left) < cornerSize) { + item.style.cursor = "ne-resize"; + } else if (e.clientX - rect.left < cornerSize) { + item.style.cursor = "nw-resize"; + } else { + item.style.cursor = "n-resize"; + } + } else if (rect.height - (e.clientY - rect.top) < cornerSize) { + if (rect.width - (e.clientX - rect.left) < cornerSize) { + item.style.cursor = "se-resize"; + } else if (e.clientX - rect.left < cornerSize) { + item.style.cursor = "sw-resize"; + } else { + item.style.cursor = "s-resize"; + } + } else if (rect.width - (e.clientX - rect.left) < cornerSize) { + item.style.cursor = "e-resize"; + } else if (e.clientX - rect.left < cornerSize) { + item.style.cursor = "w-resize"; + } else { + item.style.cursor = ""; + } + } + } + } + }; + + var mouseOver = function (e) { + var message = e.target.getAttribute("data-tooltip"); + if (message) { + // Instructions + tooltip.innerText = message; + + // Position + if (e.changedTouches && e.changedTouches[0]) { + var x = e.changedTouches[0].clientX; + var y = e.changedTouches[0].clientY; + } else { + var x = e.clientX; + var y = e.clientY; + } + + tooltip.style.top = y + "px"; + tooltip.style.left = x + "px"; + document.body.appendChild(tooltip); + } else if (tooltip.innerText) { + tooltip.innerText = ""; + document.body.removeChild(tooltip); + } + }; + + var dblClick = function (e) { + var item = jSuites.findElement(e.target, "jpanel"); + if (item && typeof item.dblclick == "function") { + // Create edition + item.dblclick(e); + } + }; + + var contextMenu = function (e) { + var item = document.activeElement; + if (item && typeof item.contextmenu == "function") { + // Create edition + item.contextmenu(e); + + e.preventDefault(); + e.stopImmediatePropagation(); + } else { + // Search for possible context menus + item = jSuites.findElement(e.target, function (o) { + return o.tagName && o.getAttribute("aria-contextmenu-id"); + }); + + if (item) { + var o = document.querySelector("#" + item); + if (!o) { + console.error("JSUITES: contextmenu id not found: " + item); + } else { + o.contextmenu.open(e); + e.preventDefault(); + e.stopImmediatePropagation(); + } + } + } + }; + + var keyDown = function (e) { + var item = document.activeElement; + if (item) { + if (e.key == "Delete" && typeof item.delete == "function") { + item.delete(); + e.preventDefault(); + e.stopImmediatePropagation(); + } + } + + if (document.jsuitesComponents && document.jsuitesComponents.length) { + if ( + (item = + document.jsuitesComponents[document.jsuitesComponents.length - 1]) + ) { + if (e.key == "Escape" && typeof item.close == "function") { + item.close(); + e.preventDefault(); + e.stopImmediatePropagation(); + } + } + } + }; + + document.addEventListener("mouseup", mouseUp); + document.addEventListener("mousedown", mouseDown); + document.addEventListener("mousemove", mouseMove); + document.addEventListener("mouseover", mouseOver); + document.addEventListener("dblclick", dblClick); + document.addEventListener("keydown", keyDown); + document.addEventListener("contextmenu", contextMenu); + }; + + /** + * Global jsuites event + */ + if (typeof document !== "undefined" && !document.jsuitesComponents) { + Events(); + } + + jSuites.version = Version; + + jSuites.setExtensions = function (o) { + if (typeof o == "object") { + var k = Object.keys(o); + for (var i = 0; i < k.length; i++) { + jSuites[k[i]] = o[k[i]]; + } + } + }; + + jSuites.tracking = function (component, state) { + if (state == true) { + document.jsuitesComponents = document.jsuitesComponents.filter(function ( + v + ) { + return v !== null; + }); + + // Start after all events + setTimeout(function () { + document.jsuitesComponents.push(component); + }, 0); + } else { + var index = document.jsuitesComponents.indexOf(component); + if (index >= 0) { + document.jsuitesComponents.splice(index, 1); + } + } + }; + + /** + * Get or set a property from a JSON from a string. + */ + jSuites.path = function (str, val) { + str = str.split("."); + if (str.length) { + var o = this; + var p = null; + while (str.length > 1) { + // Get the property + p = str.shift(); + // Check if the property exists + if (o.hasOwnProperty(p)) { + o = o[p]; + } else { + // Property does not exists + if (val === undefined) { + return undefined; + } else { + // Create the property + o[p] = {}; + // Next property + o = o[p]; + } + } + } + // Get the property + p = str.shift(); + // Set or get the value + if (val !== undefined) { + o[p] = val; + // Success + return true; + } else { + // Return the value + if (o) { + return o[p]; + } + } + } + // Something went wrong + return false; + }; + + // Update dictionary + jSuites.setDictionary = function (d) { + if (!document.dictionary) { + document.dictionary = {}; + } + // Replace the key into the dictionary and append the new ones + var k = Object.keys(d); + for (var i = 0; i < k.length; i++) { + document.dictionary[k[i]] = d[k[i]]; + } + + // Translations + var t = null; + for (var i = 0; i < jSuites.calendar.weekdays.length; i++) { + t = jSuites.translate(jSuites.calendar.weekdays[i]); + if (jSuites.calendar.weekdays[i]) { + jSuites.calendar.weekdays[i] = t; + jSuites.calendar.weekdaysShort[i] = t.substr(0, 3); + } + } + for (var i = 0; i < jSuites.calendar.months.length; i++) { + t = jSuites.translate(jSuites.calendar.months[i]); + if (t) { + jSuites.calendar.months[i] = t; + jSuites.calendar.monthsShort[i] = t.substr(0, 3); + } + } + }; + + // Translate + jSuites.translate = function (t) { + if (document.dictionary) { + return document.dictionary[t] || t; + } else { + return t; + } + }; + + jSuites.ajax = function (options, complete) { + if (Array.isArray(options)) { + // Create multiple request controller + var multiple = { + instance: [], + complete: complete, + }; + + if (options.length > 0) { + for (var i = 0; i < options.length; i++) { + options[i].multiple = multiple; + multiple.instance.push(jSuites.ajax(options[i])); + } + } + + return multiple; + } + + if (!options.data) { + options.data = {}; + } + + if (options.type) { + options.method = options.type; + } + + // Default method + if (!options.method) { + options.method = "GET"; + } + + // Default type + if (!options.dataType) { + options.dataType = "json"; + } + + if (options.data) { + // Parse object to variables format + var parseData = function (value, key) { + var vars = []; + if (value) { + var keys = Object.keys(value); + if (keys.length) { + for (var i = 0; i < keys.length; i++) { + if (key) { + var k = key + "[" + keys[i] + "]"; + } else { + var k = keys[i]; + } + + if (value[k] instanceof FileList) { + vars[k] = value[keys[i]]; + } else if ( + value[keys[i]] === null || + value[keys[i]] === undefined + ) { + vars[k] = ""; + } else if (typeof value[keys[i]] == "object") { + var r = parseData(value[keys[i]], k); + var o = Object.keys(r); + for (var j = 0; j < o.length; j++) { + vars[o[j]] = r[o[j]]; + } + } else { + vars[k] = value[keys[i]]; + } + } + } + } + + return vars; + }; + + var d = parseData(options.data); + var k = Object.keys(d); + + // Data form + if (options.method == "GET") { + if (k.length) { + var data = []; + for (var i = 0; i < k.length; i++) { + data.push(k[i] + "=" + encodeURIComponent(d[k[i]])); + } + + if (options.url.indexOf("?") < 0) { + options.url += "?"; + } + options.url += data.join("&"); + } + } else { + var data = new FormData(); + for (var i = 0; i < k.length; i++) { + if (d[k[i]] instanceof FileList) { + if (d[k[i]].length) { + for (var j = 0; j < d[k[i]].length; j++) { + data.append(k[i], d[k[i]][j], d[k[i]][j].name); + } + } + } else { + data.append(k[i], d[k[i]]); + } + } + } + } + + var httpRequest = new XMLHttpRequest(); + httpRequest.open(options.method, options.url, true); + httpRequest.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + + // Content type + if (options.contentType) { + httpRequest.setRequestHeader("Content-Type", options.contentType); + } + + // Headers + if (options.method == "POST") { + httpRequest.setRequestHeader("Accept", "application/json"); + } else { + if (options.dataType == "blob") { + httpRequest.responseType = "blob"; + } else { + if (!options.contentType) { + if (options.dataType == "json") { + httpRequest.setRequestHeader("Content-Type", "text/json"); + } else if (options.dataType == "html") { + httpRequest.setRequestHeader("Content-Type", "text/html"); + } + } + } + } + + // No cache + if (options.cache != true) { + httpRequest.setRequestHeader("pragma", "no-cache"); + httpRequest.setRequestHeader("cache-control", "no-cache"); + } + + // Authentication + if (options.withCredentials == true) { + httpRequest.withCredentials = true; + } + + // Before send + if (typeof options.beforeSend == "function") { + options.beforeSend(httpRequest); + } + + // Before send + if (typeof jSuites.ajax.beforeSend == "function") { + jSuites.ajax.beforeSend(httpRequest); + } + + if (document.ajax && typeof document.ajax.beforeSend == "function") { + document.ajax.beforeSend(httpRequest); + } + + httpRequest.onload = function () { + if (httpRequest.status === 200) { + if (options.dataType == "json") { + try { + var result = JSON.parse(httpRequest.responseText); + + if (options.success && typeof options.success == "function") { + options.success(result); + } + } catch (err) { + if (options.error && typeof options.error == "function") { + options.error(err, result); + } + } + } else { + if (options.dataType == "blob") { + var result = httpRequest.response; + } else { + var result = httpRequest.responseText; + } + + if (options.success && typeof options.success == "function") { + options.success(result); + } + } + } else { + if (options.error && typeof options.error == "function") { + options.error(httpRequest.responseText, httpRequest.status); + } + } + + // Global queue + if (jSuites.ajax.queue && jSuites.ajax.queue.length > 0) { + jSuites.ajax.send(jSuites.ajax.queue.shift()); + } + + // Global complete method + if (jSuites.ajax.requests && jSuites.ajax.requests.length) { + // Get index of this request in the container + var index = jSuites.ajax.requests.indexOf(httpRequest); + // Remove from the ajax requests container + jSuites.ajax.requests.splice(index, 1); + // Deprected: Last one? + if (!jSuites.ajax.requests.length) { + // Object event + if (options.complete && typeof options.complete == "function") { + options.complete(result); + } + } + // Group requests + if (options.group) { + if ( + jSuites.ajax.oncomplete && + typeof jSuites.ajax.oncomplete[options.group] == "function" + ) { + if (!jSuites.ajax.pending(options.group)) { + jSuites.ajax.oncomplete[options.group](); + jSuites.ajax.oncomplete[options.group] = null; + } + } + } + // Multiple requests controller + if (options.multiple && options.multiple.instance) { + // Get index of this request in the container + var index = options.multiple.instance.indexOf(httpRequest); + // Remove from the ajax requests container + options.multiple.instance.splice(index, 1); + // If this is the last one call method complete + if (!options.multiple.instance.length) { + if ( + options.multiple.complete && + typeof options.multiple.complete == "function" + ) { + options.multiple.complete(result); + } + } + } + } + }; + + // Keep the options + httpRequest.options = options; + // Data + httpRequest.data = data; + + // Queue + if (options.queue == true && jSuites.ajax.requests.length > 0) { + jSuites.ajax.queue.push(httpRequest); + } else { + jSuites.ajax.send(httpRequest); + } + + return httpRequest; + }; + + jSuites.ajax.send = function (httpRequest) { + if (httpRequest.data) { + if (Array.isArray(httpRequest.data)) { + httpRequest.send(httpRequest.data.join("&")); + } else { + httpRequest.send(httpRequest.data); + } + } else { + httpRequest.send(); + } + + jSuites.ajax.requests.push(httpRequest); + }; + + jSuites.ajax.exists = function (url, __callback) { + var http = new XMLHttpRequest(); + http.open("HEAD", url, false); + http.send(); + if (http.status) { + __callback(http.status); + } + }; + + jSuites.ajax.pending = function (group) { + var n = 0; + var o = jSuites.ajax.requests; + if (o && o.length) { + for (var i = 0; i < o.length; i++) { + if (!group || group == o[i].options.group) { + n++; + } + } + } + return n; + }; + + jSuites.ajax.oncomplete = {}; + jSuites.ajax.requests = []; + jSuites.ajax.queue = []; + + jSuites.alert = function (message) { + if (jSuites.getWindowWidth() < 800 && jSuites.dialog) { + jSuites.dialog.open({ + title: "Alert", + message: message, + }); + } else { + alert(message); + } + }; + + jSuites.animation = {}; + + jSuites.animation.slideLeft = function (element, direction, done) { + if (direction == true) { + element.classList.add("slide-left-in"); + setTimeout(function () { + element.classList.remove("slide-left-in"); + if (typeof done == "function") { + done(); + } + }, 400); + } else { + element.classList.add("slide-left-out"); + setTimeout(function () { + element.classList.remove("slide-left-out"); + if (typeof done == "function") { + done(); + } + }, 400); + } + }; + + jSuites.animation.slideRight = function (element, direction, done) { + if (direction == true) { + element.classList.add("slide-right-in"); + setTimeout(function () { + element.classList.remove("slide-right-in"); + if (typeof done == "function") { + done(); + } + }, 400); + } else { + element.classList.add("slide-right-out"); + setTimeout(function () { + element.classList.remove("slide-right-out"); + if (typeof done == "function") { + done(); + } + }, 400); + } + }; + + jSuites.animation.slideTop = function (element, direction, done) { + if (direction == true) { + element.classList.add("slide-top-in"); + setTimeout(function () { + element.classList.remove("slide-top-in"); + if (typeof done == "function") { + done(); + } + }, 400); + } else { + element.classList.add("slide-top-out"); + setTimeout(function () { + element.classList.remove("slide-top-out"); + if (typeof done == "function") { + done(); + } + }, 400); + } + }; + + jSuites.animation.slideBottom = function (element, direction, done) { + if (direction == true) { + element.classList.add("slide-bottom-in"); + setTimeout(function () { + element.classList.remove("slide-bottom-in"); + if (typeof done == "function") { + done(); + } + }, 400); + } else { + element.classList.add("slide-bottom-out"); + setTimeout(function () { + element.classList.remove("slide-bottom-out"); + if (typeof done == "function") { + done(); + } + }, 100); + } + }; + + jSuites.animation.fadeIn = function (element, done) { + element.style.display = ""; + element.classList.add("fade-in"); + setTimeout(function () { + element.classList.remove("fade-in"); + if (typeof done == "function") { + done(); + } + }, 2000); + }; + + jSuites.animation.fadeOut = function (element, done) { + element.classList.add("fade-out"); + setTimeout(function () { + element.style.display = "none"; + element.classList.remove("fade-out"); + if (typeof done == "function") { + done(); + } + }, 1000); + }; + + jSuites.calendar = function (el, options) { + // Already created, update options + if (el.calendar) { + return el.calendar.setOptions(options, true); + } + + // New instance + var obj = { type: "calendar" }; + obj.options = {}; + + // Date + obj.date = null; + + /** + * Update options + */ + obj.setOptions = function (options, reset) { + // Default configuration + var defaults = { + // Render type: [ default | year-month-picker ] + type: "default", + // Restrictions + validRange: null, + // Starting weekday - 0 for sunday, 6 for saturday + startingDay: null, + // Date format + format: "DD/MM/YYYY", + // Allow keyboard date entry + readonly: true, + // Today is default + today: false, + // Show timepicker + time: false, + // Show the reset button + resetButton: true, + // Placeholder + placeholder: "", + // Translations can be done here + months: jSuites.calendar.monthsShort, + monthsFull: jSuites.calendar.months, + weekdays: jSuites.calendar.weekdays, + textDone: jSuites.translate("Done"), + textReset: jSuites.translate("Reset"), + textUpdate: jSuites.translate("Update"), + // Value + value: null, + // Fullscreen (this is automatic set for screensize < 800) + fullscreen: false, + // Create the calendar closed as default + opened: false, + // Events + onopen: null, + onclose: null, + onchange: null, + onupdate: null, + // Internal mode controller + mode: null, + position: null, + // Data type + dataType: null, + }; + + // Loop through our object + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + if (typeof obj.options[property] == "undefined" || reset === true) { + obj.options[property] = defaults[property]; + } + } + } + + // Reset button + if (obj.options.resetButton == false) { + calendarReset.style.display = "none"; + } else { + calendarReset.style.display = ""; + } + + // Readonly + if (obj.options.readonly) { + el.setAttribute("readonly", "readonly"); + } else { + el.removeAttribute("readonly"); + } + + // Placeholder + if (obj.options.placeholder) { + el.setAttribute("placeholder", obj.options.placeholder); + } else { + el.removeAttribute("placeholder"); + } + + if (jSuites.isNumeric(obj.options.value) && obj.options.value > 0) { + obj.options.value = jSuites.calendar.numToDate(obj.options.value); + // Data type numberic + obj.options.dataType = "numeric"; + } + + // Texts + calendarReset.innerHTML = obj.options.textReset; + calendarConfirm.innerHTML = obj.options.textDone; + calendarControlsUpdateButton.innerHTML = obj.options.textUpdate; + + // Define mask + el.setAttribute("data-mask", obj.options.format.toLowerCase()); + + // Value + if (!obj.options.value && obj.options.today) { + var value = jSuites.calendar.now(); + } else { + var value = obj.options.value; + } + + // Set internal date + if (value) { + // Force the update + obj.options.value = null; + // New value + obj.setValue(value); + } + + return obj; + }; + + /** + * Open the calendar + */ + obj.open = function (value) { + if (!calendar.classList.contains("jcalendar-focus")) { + if (!calendar.classList.contains("jcalendar-inline")) { + // Current + jSuites.calendar.current = obj; + // Start tracking + jSuites.tracking(obj, true); + // Create the days + obj.getDays(); + // Render months + if (obj.options.type == "year-month-picker") { + obj.getMonths(); + } + // Get time + if (obj.options.time) { + calendarSelectHour.value = obj.date[3]; + calendarSelectMin.value = obj.date[4]; + } + + // Show calendar + calendar.classList.add("jcalendar-focus"); + + // Get the position of the corner helper + if (jSuites.getWindowWidth() < 800 || obj.options.fullscreen) { + calendar.classList.add("jcalendar-fullsize"); + // Animation + jSuites.animation.slideBottom(calendarContent, 1); + } else { + calendar.classList.remove("jcalendar-fullsize"); + + var rect = el.getBoundingClientRect(); + var rectContent = calendarContent.getBoundingClientRect(); + + if (obj.options.position) { + calendarContainer.style.position = "fixed"; + if (window.innerHeight < rect.bottom + rectContent.height) { + calendarContainer.style.top = + rect.top - (rectContent.height + 2) + "px"; + } else { + calendarContainer.style.top = rect.top + rect.height + 2 + "px"; + } + calendarContainer.style.left = rect.left + "px"; + } else { + if (window.innerHeight < rect.bottom + rectContent.height) { + var d = -1 * (rect.height + rectContent.height + 2); + if (d + rect.top < 0) { + d = -1 * (rect.top + rect.height); + } + calendarContainer.style.top = d + "px"; + } else { + calendarContainer.style.top = 2 + "px"; + } + + if (window.innerWidth < rect.left + rectContent.width) { + var d = + window.innerWidth - (rect.left + rectContent.width + 20); + calendarContainer.style.left = d + "px"; + } else { + calendarContainer.style.left = "0px"; + } + } + } + + // Events + if (typeof obj.options.onopen == "function") { + obj.options.onopen(el); + } + } + } + }; + + obj.close = function (ignoreEvents, update) { + if (calendar.classList.contains("jcalendar-focus")) { + if (update !== false) { + var element = calendar.querySelector(".jcalendar-selected"); + + if (typeof update == "string") { + var value = update; + } else if ( + !element || + element.classList.contains("jcalendar-disabled") + ) { + var value = obj.options.value; + } else { + var value = obj.getValue(); + } + + obj.setValue(value); + } + + // Events + if (!ignoreEvents && typeof obj.options.onclose == "function") { + obj.options.onclose(el); + } + // Hide + calendar.classList.remove("jcalendar-focus"); + // Stop tracking + jSuites.tracking(obj, false); + // Current + jSuites.calendar.current = null; + } + + return obj.options.value; + }; + + obj.prev = function () { + // Check if the visualization is the days picker or years picker + if (obj.options.mode == "years") { + obj.date[0] = obj.date[0] - 12; + + // Update picker table of days + obj.getYears(); + } else if (obj.options.mode == "months") { + obj.date[0] = parseInt(obj.date[0]) - 1; + // Update picker table of months + obj.getMonths(); + } else { + // Go to the previous month + if (obj.date[1] < 2) { + obj.date[0] = obj.date[0] - 1; + obj.date[1] = 12; + } else { + obj.date[1] = obj.date[1] - 1; + } + + // Update picker table of days + obj.getDays(); + } + }; + + obj.next = function () { + // Check if the visualization is the days picker or years picker + if (obj.options.mode == "years") { + obj.date[0] = parseInt(obj.date[0]) + 12; + + // Update picker table of days + obj.getYears(); + } else if (obj.options.mode == "months") { + obj.date[0] = parseInt(obj.date[0]) + 1; + // Update picker table of months + obj.getMonths(); + } else { + // Go to the previous month + if (obj.date[1] > 11) { + obj.date[0] = parseInt(obj.date[0]) + 1; + obj.date[1] = 1; + } else { + obj.date[1] = parseInt(obj.date[1]) + 1; + } + + // Update picker table of days + obj.getDays(); + } + }; + + /** + * Set today + */ + obj.setToday = function () { + // Today + var value = new Date().toISOString().substr(0, 10); + // Change value + obj.setValue(value); + // Value + return value; + }; + + obj.setValue = function (val) { + if (!val) { + val = "" + val; + } + // Values + var newValue = val; + var oldValue = obj.options.value; + + if (oldValue != newValue) { + // Set label + if (!newValue) { + obj.date = null; + var val = ""; + } else { + var value = obj.setLabel(newValue, obj.options); + var date = newValue.split(" "); + if (!date[1]) { + date[1] = "00:00:00"; + } + var time = date[1].split(":"); + var date = date[0].split("-"); + var y = parseInt(date[0]); + var m = parseInt(date[1]); + var d = parseInt(date[2]); + var h = parseInt(time[0]); + var i = parseInt(time[1]); + obj.date = [y, m, d, h, i, 0]; + var val = obj.setLabel(newValue, obj.options); + } + + // New value + obj.options.value = newValue; + + if (typeof obj.options.onchange == "function") { + obj.options.onchange(el, newValue, oldValue); + } + + // Lemonade JS + if (el.value != val) { + el.value = val; + if (typeof el.oninput == "function") { + el.oninput({ + type: "input", + target: el, + value: el.value, + }); + } + } + } + + obj.getDays(); + }; + + obj.getValue = function () { + if (obj.date) { + if (obj.options.time) { + return ( + jSuites.two(obj.date[0]) + + "-" + + jSuites.two(obj.date[1]) + + "-" + + jSuites.two(obj.date[2]) + + " " + + jSuites.two(obj.date[3]) + + ":" + + jSuites.two(obj.date[4]) + + ":" + + jSuites.two(0) + ); + } else { + return ( + jSuites.two(obj.date[0]) + + "-" + + jSuites.two(obj.date[1]) + + "-" + + jSuites.two(obj.date[2]) + + " " + + jSuites.two(0) + + ":" + + jSuites.two(0) + + ":" + + jSuites.two(0) + ); + } + } else { + return ""; + } + }; + + /** + * Calendar + */ + obj.update = function (element, v) { + if (element.classList.contains("jcalendar-disabled")) { + // Do nothing + } else { + var elements = calendar.querySelector(".jcalendar-selected"); + if (elements) { + elements.classList.remove("jcalendar-selected"); + } + element.classList.add("jcalendar-selected"); + + if (element.classList.contains("jcalendar-set-month")) { + obj.date[1] = v; + obj.date[2] = 1; // first day of the month + } else { + obj.date[2] = element.innerText; + } + + if (!obj.options.time) { + obj.close(); + } else { + obj.date[3] = calendarSelectHour.value; + obj.date[4] = calendarSelectMin.value; + } + } + + // Update + updateActions(); + }; + + /** + * Set to blank + */ + obj.reset = function () { + // Close calendar + obj.setValue(""); + obj.date = null; + obj.close(false, false); + }; + + /** + * Get calendar days + */ + obj.getDays = function () { + // Mode + obj.options.mode = "days"; + + // Setting current values in case of NULLs + var date = new Date(); + + // Current selection + var year = + obj.date && jSuites.isNumeric(obj.date[0]) + ? obj.date[0] + : parseInt(date.getFullYear()); + var month = + obj.date && jSuites.isNumeric(obj.date[1]) + ? obj.date[1] + : parseInt(date.getMonth()) + 1; + var day = + obj.date && jSuites.isNumeric(obj.date[2]) + ? obj.date[2] + : parseInt(date.getDate()); + var hour = + obj.date && jSuites.isNumeric(obj.date[3]) + ? obj.date[3] + : parseInt(date.getHours()); + var min = + obj.date && jSuites.isNumeric(obj.date[4]) + ? obj.date[4] + : parseInt(date.getMinutes()); + + // Selection container + obj.date = [year, month, day, hour, min, 0]; + + // Update title + calendarLabelYear.innerHTML = year; + calendarLabelMonth.innerHTML = obj.options.months[month - 1]; + + // Current month and Year + var isCurrentMonthAndYear = + date.getMonth() == month - 1 && date.getFullYear() == year + ? true + : false; + var currentDay = date.getDate(); + + // Number of days in the month + var date = new Date(year, month, 0, 0, 0); + var numberOfDays = date.getDate(); + + // First day + var date = new Date(year, month - 1, 0, 0, 0); + var firstDay = date.getDay() + 1; + + // Index value + var index = obj.options.startingDay || 0; + + // First of day relative to the starting calendar weekday + firstDay = firstDay - index; + + // Reset table + calendarBody.innerHTML = ""; + + // Weekdays Row + var row = document.createElement("tr"); + row.setAttribute("align", "center"); + calendarBody.appendChild(row); + + // Create weekdays row + for (var i = 0; i < 7; i++) { + var cell = document.createElement("td"); + cell.classList.add("jcalendar-weekday"); + cell.innerHTML = obj.options.weekdays[index].substr(0, 1); + row.appendChild(cell); + // Next week day + index++; + // Restart index + if (index > 6) { + index = 0; + } + } + + // Index of days + var index = 0; + var d = 0; + + // Calendar table + for (var j = 0; j < 6; j++) { + // Reset cells container + var row = document.createElement("tr"); + row.setAttribute("align", "center"); + // Data control + var emptyRow = true; + // Create cells + for (var i = 0; i < 7; i++) { + // Create cell + var cell = document.createElement("td"); + cell.classList.add("jcalendar-set-day"); + + if (index >= firstDay && index < firstDay + numberOfDays) { + // Day cell + d++; + cell.innerHTML = d; + + // Selected + if (d == day) { + cell.classList.add("jcalendar-selected"); + } + + // Current selection day is today + if (isCurrentMonthAndYear && currentDay == d) { + cell.style.fontWeight = "bold"; + } + + // Current selection day + var current = jSuites.calendar.now( + new Date(year, month - 1, d), + true + ); + + // Available ranges + if (obj.options.validRange) { + if ( + !obj.options.validRange[0] || + current >= obj.options.validRange[0] + ) { + var test1 = true; + } else { + var test1 = false; + } + + if ( + !obj.options.validRange[1] || + current <= obj.options.validRange[1] + ) { + var test2 = true; + } else { + var test2 = false; + } + + if (!(test1 && test2)) { + cell.classList.add("jcalendar-disabled"); + } + } + + // Control + emptyRow = false; + } + // Day cell + row.appendChild(cell); + // Index + index++; + } + + // Add cell to the calendar body + if (emptyRow == false) { + calendarBody.appendChild(row); + } + } + + // Show time controls + if (obj.options.time) { + calendarControlsTime.style.display = ""; + } else { + calendarControlsTime.style.display = "none"; + } + + // Update + updateActions(); + }; + + obj.getMonths = function () { + // Mode + obj.options.mode = "months"; + + // Loading month labels + var months = obj.options.months; + + // Value + var value = obj.options.value; + + // Current date + var date = new Date(); + var currentYear = parseInt(date.getFullYear()); + var currentMonth = parseInt(date.getMonth()) + 1; + var selectedYear = + obj.date && jSuites.isNumeric(obj.date[0]) ? obj.date[0] : currentYear; + var selectedMonth = + obj.date && jSuites.isNumeric(obj.date[1]) ? obj.date[1] : currentMonth; + + // Update title + calendarLabelYear.innerHTML = obj.date[0]; + calendarLabelMonth.innerHTML = months[selectedMonth - 1]; + + // Table + var table = document.createElement("table"); + table.setAttribute("width", "100%"); + + // Row + var row = null; + + // Calendar table + for (var i = 0; i < 12; i++) { + if (!(i % 4)) { + // Reset cells container + var row = document.createElement("tr"); + row.setAttribute("align", "center"); + table.appendChild(row); + } + + // Create cell + var cell = document.createElement("td"); + cell.classList.add("jcalendar-set-month"); + cell.setAttribute("data-value", i + 1); + cell.innerText = months[i]; + + if (obj.options.validRange) { + var current = selectedYear + "-" + jSuites.two(i + 1); + if ( + !obj.options.validRange[0] || + current >= obj.options.validRange[0].substr(0, 7) + ) { + var test1 = true; + } else { + var test1 = false; + } + + if ( + !obj.options.validRange[1] || + current <= obj.options.validRange[1].substr(0, 7) + ) { + var test2 = true; + } else { + var test2 = false; + } + + if (!(test1 && test2)) { + cell.classList.add("jcalendar-disabled"); + } + } + + if (i + 1 == selectedMonth) { + cell.classList.add("jcalendar-selected"); + } + + if (currentYear == selectedYear && i + 1 == currentMonth) { + cell.style.fontWeight = "bold"; + } + + row.appendChild(cell); + } + + calendarBody.innerHTML = ''; + calendarBody.children[0].children[0].appendChild(table); + + // Update + updateActions(); + }; + + obj.getYears = function () { + // Mode + obj.options.mode = "years"; + + // Current date + var date = new Date(); + var currentYear = date.getFullYear(); + var selectedYear = + obj.date && jSuites.isNumeric(obj.date[0]) + ? obj.date[0] + : parseInt(date.getFullYear()); + + // Array of years + var y = []; + for (var i = 0; i < 25; i++) { + y[i] = parseInt(obj.date[0]) + (i - 12); + } + + // Assembling the year tables + var table = document.createElement("table"); + table.setAttribute("width", "100%"); + + for (var i = 0; i < 25; i++) { + if (!(i % 5)) { + // Reset cells container + var row = document.createElement("tr"); + row.setAttribute("align", "center"); + table.appendChild(row); + } + + // Create cell + var cell = document.createElement("td"); + cell.classList.add("jcalendar-set-year"); + cell.innerText = y[i]; + + if (selectedYear == y[i]) { + cell.classList.add("jcalendar-selected"); + } + + if (currentYear == y[i]) { + cell.style.fontWeight = "bold"; + } + + row.appendChild(cell); + } + + calendarBody.innerHTML = ''; + calendarBody.firstChild.firstChild.appendChild(table); + + // Update + updateActions(); + }; + + obj.setLabel = function (value, mixed) { + return jSuites.calendar.getDateString(value, mixed); + }; + + obj.fromFormatted = function (value, format) { + return jSuites.calendar.extractDateFromString(value, format); + }; + + var mouseUpControls = function (e) { + var element = jSuites.findElement(e.target, "jcalendar-container"); + if (element) { + var action = e.target.className; + + // Object id + if (action == "jcalendar-prev") { + obj.prev(); + } else if (action == "jcalendar-next") { + obj.next(); + } else if (action == "jcalendar-month") { + obj.getMonths(); + } else if (action == "jcalendar-year") { + obj.getYears(); + } else if (action == "jcalendar-set-year") { + obj.date[0] = e.target.innerText; + if (obj.options.type == "year-month-picker") { + obj.getMonths(); + } else { + obj.getDays(); + } + } else if (e.target.classList.contains("jcalendar-set-month")) { + var month = parseInt(e.target.getAttribute("data-value")); + if (obj.options.type == "year-month-picker") { + obj.update(e.target, month); + } else { + obj.date[1] = month; + obj.getDays(); + } + } else if ( + action == "jcalendar-confirm" || + action == "jcalendar-update" || + action == "jcalendar-close" + ) { + obj.close(); + } else if (action == "jcalendar-backdrop") { + obj.close(false, false); + } else if (action == "jcalendar-reset") { + obj.reset(); + } else if ( + e.target.classList.contains("jcalendar-set-day") && + e.target.innerText + ) { + obj.update(e.target); + } + } else { + obj.close(); + } + }; + + var keyUpControls = function (e) { + if (e.target.value && e.target.value.length > 3) { + var test = jSuites.calendar.extractDateFromString( + e.target.value, + obj.options.format + ); + if (test) { + obj.setValue(test); + } + } + }; + + // Update actions button + var updateActions = function () { + var currentDay = calendar.querySelector(".jcalendar-selected"); + + if (currentDay && currentDay.classList.contains("jcalendar-disabled")) { + calendarControlsUpdateButton.setAttribute("disabled", "disabled"); + calendarSelectHour.setAttribute("disabled", "disabled"); + calendarSelectMin.setAttribute("disabled", "disabled"); + } else { + calendarControlsUpdateButton.removeAttribute("disabled"); + calendarSelectHour.removeAttribute("disabled"); + calendarSelectMin.removeAttribute("disabled"); + } + + // Event + if (typeof obj.options.onupdate == "function") { + obj.options.onupdate(el, obj.getValue()); + } + }; + + var calendar = null; + var calendarReset = null; + var calendarConfirm = null; + var calendarContainer = null; + var calendarContent = null; + var calendarLabelYear = null; + var calendarLabelMonth = null; + var calendarTable = null; + var calendarBody = null; + + var calendarControls = null; + var calendarControlsTime = null; + var calendarControlsUpdate = null; + var calendarControlsUpdateButton = null; + var calendarSelectHour = null; + var calendarSelectMin = null; + + var init = function () { + // Get value from initial element if that is an input + if (el.tagName == "INPUT" && el.value) { + options.value = el.value; + } + + // Calendar DOM elements + calendarReset = document.createElement("div"); + calendarReset.className = "jcalendar-reset"; + + calendarConfirm = document.createElement("div"); + calendarConfirm.className = "jcalendar-confirm"; + + calendarControls = document.createElement("div"); + calendarControls.className = "jcalendar-controls"; + calendarControls.style.borderBottom = "1px solid #ddd"; + calendarControls.appendChild(calendarReset); + calendarControls.appendChild(calendarConfirm); + + calendarContainer = document.createElement("div"); + calendarContainer.className = "jcalendar-container"; + + calendarContent = document.createElement("div"); + calendarContent.className = "jcalendar-content"; + calendarContainer.appendChild(calendarContent); + + // Main element + if (el.tagName == "DIV") { + calendar = el; + calendar.classList.add("jcalendar-inline"); + } else { + // Add controls to the screen + calendarContent.appendChild(calendarControls); + + calendar = document.createElement("div"); + calendar.className = "jcalendar"; + } + calendar.classList.add("jcalendar-container"); + calendar.appendChild(calendarContainer); + + // Table container + var calendarTableContainer = document.createElement("div"); + calendarTableContainer.className = "jcalendar-table"; + calendarContent.appendChild(calendarTableContainer); + + // Previous button + var calendarHeaderPrev = document.createElement("td"); + calendarHeaderPrev.setAttribute("colspan", "2"); + calendarHeaderPrev.className = "jcalendar-prev"; + + // Header with year and month + calendarLabelYear = document.createElement("span"); + calendarLabelYear.className = "jcalendar-year"; + calendarLabelMonth = document.createElement("span"); + calendarLabelMonth.className = "jcalendar-month"; + + var calendarHeaderTitle = document.createElement("td"); + calendarHeaderTitle.className = "jcalendar-header"; + calendarHeaderTitle.setAttribute("colspan", "3"); + calendarHeaderTitle.appendChild(calendarLabelMonth); + calendarHeaderTitle.appendChild(calendarLabelYear); + + var calendarHeaderNext = document.createElement("td"); + calendarHeaderNext.setAttribute("colspan", "2"); + calendarHeaderNext.className = "jcalendar-next"; + + var calendarHeader = document.createElement("thead"); + var calendarHeaderRow = document.createElement("tr"); + calendarHeaderRow.appendChild(calendarHeaderPrev); + calendarHeaderRow.appendChild(calendarHeaderTitle); + calendarHeaderRow.appendChild(calendarHeaderNext); + calendarHeader.appendChild(calendarHeaderRow); + + calendarTable = document.createElement("table"); + calendarBody = document.createElement("tbody"); + calendarTable.setAttribute("cellpadding", "0"); + calendarTable.setAttribute("cellspacing", "0"); + calendarTable.appendChild(calendarHeader); + calendarTable.appendChild(calendarBody); + calendarTableContainer.appendChild(calendarTable); + + calendarSelectHour = document.createElement("select"); + calendarSelectHour.className = "jcalendar-select"; + calendarSelectHour.onchange = function () { + obj.date[3] = this.value; + + // Event + if (typeof obj.options.onupdate == "function") { + obj.options.onupdate(el, obj.getValue()); + } + }; + + for (var i = 0; i < 24; i++) { + var element = document.createElement("option"); + element.value = i; + element.innerHTML = jSuites.two(i); + calendarSelectHour.appendChild(element); + } + + calendarSelectMin = document.createElement("select"); + calendarSelectMin.className = "jcalendar-select"; + calendarSelectMin.onchange = function () { + obj.date[4] = this.value; + + // Event + if (typeof obj.options.onupdate == "function") { + obj.options.onupdate(el, obj.getValue()); + } + }; + + for (var i = 0; i < 60; i++) { + var element = document.createElement("option"); + element.value = i; + element.innerHTML = jSuites.two(i); + calendarSelectMin.appendChild(element); + } + + // Footer controls + var calendarControlsFooter = document.createElement("div"); + calendarControlsFooter.className = "jcalendar-controls"; + + calendarControlsTime = document.createElement("div"); + calendarControlsTime.className = "jcalendar-time"; + calendarControlsTime.style.maxWidth = "140px"; + calendarControlsTime.appendChild(calendarSelectHour); + calendarControlsTime.appendChild(calendarSelectMin); + + calendarControlsUpdateButton = document.createElement("button"); + calendarControlsUpdateButton.setAttribute("type", "button"); + calendarControlsUpdateButton.className = "jcalendar-update"; + + calendarControlsUpdate = document.createElement("div"); + calendarControlsUpdate.style.flexGrow = "10"; + calendarControlsUpdate.appendChild(calendarControlsUpdateButton); + calendarControlsFooter.appendChild(calendarControlsTime); + + // Only show the update button for input elements + if (el.tagName == "INPUT") { + calendarControlsFooter.appendChild(calendarControlsUpdate); + } + + calendarContent.appendChild(calendarControlsFooter); + + var calendarBackdrop = document.createElement("div"); + calendarBackdrop.className = "jcalendar-backdrop"; + calendar.appendChild(calendarBackdrop); + + // Handle events + el.addEventListener("keyup", keyUpControls); + + // Add global events + calendar.addEventListener("swipeleft", function (e) { + jSuites.animation.slideLeft(calendarTable, 0, function () { + obj.next(); + jSuites.animation.slideRight(calendarTable, 1); + }); + e.preventDefault(); + e.stopPropagation(); + }); + + calendar.addEventListener("swiperight", function (e) { + jSuites.animation.slideRight(calendarTable, 0, function () { + obj.prev(); + jSuites.animation.slideLeft(calendarTable, 1); + }); + e.preventDefault(); + e.stopPropagation(); + }); + + el.onmouseup = function () { + obj.open(); + }; + + if ("ontouchend" in document.documentElement === true) { + calendar.addEventListener("touchend", mouseUpControls); + } else { + calendar.addEventListener("mouseup", mouseUpControls); + } + + // Global controls + if (!jSuites.calendar.hasEvents) { + // Execute only one time + jSuites.calendar.hasEvents = true; + // Enter and Esc + document.addEventListener("keydown", jSuites.calendar.keydown); + } + + // Set configuration + obj.setOptions(options); + + // Append element to the DOM + if (el.tagName == "INPUT") { + el.parentNode.insertBefore(calendar, el.nextSibling); + // Add properties + el.setAttribute("autocomplete", "off"); + // Element + el.classList.add("jcalendar-input"); + // Value + el.value = obj.setLabel(obj.getValue(), obj.options); + } else { + // Get days + obj.getDays(); + // Hour + if (obj.options.time) { + calendarSelectHour.value = obj.date[3]; + calendarSelectMin.value = obj.date[4]; + } + } + + // Default opened + if (obj.options.opened == true) { + obj.open(); + } + + // Change method + el.change = obj.setValue; + + // Global generic value handler + el.val = function (val) { + if (val === undefined) { + return obj.getValue(); + } else { + obj.setValue(val); + } + }; + + // Keep object available from the node + el.calendar = calendar.calendar = obj; + }; + + init(); + + return obj; + }; + + jSuites.calendar.keydown = function (e) { + var calendar = null; + if ((calendar = jSuites.calendar.current)) { + if (e.which == 13) { + // ENTER + calendar.close(false, true); + } else if (e.which == 27) { + // ESC + calendar.close(false, false); + } + } + }; + + jSuites.calendar.prettify = function (d, texts) { + if (!texts) { + var texts = { + justNow: "Just now", + xMinutesAgo: "{0}m ago", + xHoursAgo: "{0}h ago", + xDaysAgo: "{0}d ago", + xWeeksAgo: "{0}w ago", + xMonthsAgo: "{0} mon ago", + xYearsAgo: "{0}y ago", + }; + } + + var d1 = new Date(); + var d2 = new Date(d); + var total = parseInt((d1 - d2) / 1000 / 60); + + String.prototype.format = function (o) { + return this.replace("{0}", o); + }; + + if (total == 0) { + var text = texts.justNow; + } else if (total < 90) { + var text = texts.xMinutesAgo.format(total); + } else if (total < 1440) { + // One day + var text = texts.xHoursAgo.format(Math.round(total / 60)); + } else if (total < 20160) { + // 14 days + var text = texts.xDaysAgo.format(Math.round(total / 1440)); + } else if (total < 43200) { + // 30 days + var text = texts.xWeeksAgo.format(Math.round(total / 10080)); + } else if (total < 1036800) { + // 24 months + var text = texts.xMonthsAgo.format(Math.round(total / 43200)); + } else { + // 24 months+ + var text = texts.xYearsAgo.format(Math.round(total / 525600)); + } + + return text; + }; + + jSuites.calendar.prettifyAll = function () { + var elements = document.querySelectorAll(".prettydate"); + for (var i = 0; i < elements.length; i++) { + if (elements[i].getAttribute("data-date")) { + elements[i].innerHTML = jSuites.calendar.prettify( + elements[i].getAttribute("data-date") + ); + } else { + if (elements[i].innerHTML) { + elements[i].setAttribute("title", elements[i].innerHTML); + elements[i].setAttribute("data-date", elements[i].innerHTML); + elements[i].innerHTML = jSuites.calendar.prettify( + elements[i].innerHTML + ); + } + } + } + }; + + jSuites.calendar.now = function (date, dateOnly) { + if (Array.isArray(date)) { + var y = date[0]; + var m = date[1]; + var d = date[2]; + var h = date[3]; + var i = date[4]; + var s = date[5]; + } else { + if (!date) { + var date = new Date(); + } + var y = date.getFullYear(); + var m = date.getMonth() + 1; + var d = date.getDate(); + var h = date.getHours(); + var i = date.getMinutes(); + var s = date.getSeconds(); + } + + if (dateOnly == true) { + return jSuites.two(y) + "-" + jSuites.two(m) + "-" + jSuites.two(d); + } else { + return ( + jSuites.two(y) + + "-" + + jSuites.two(m) + + "-" + + jSuites.two(d) + + " " + + jSuites.two(h) + + ":" + + jSuites.two(i) + + ":" + + jSuites.two(s) + ); + } + }; + + jSuites.calendar.toArray = function (value) { + var date = value.split(value.indexOf("T") !== -1 ? "T" : " "); + var time = date[1]; + var date = date[0].split("-"); + var y = parseInt(date[0]); + var m = parseInt(date[1]); + var d = parseInt(date[2]); + + if (time) { + var time = time.split(":"); + var h = parseInt(time[0]); + var i = parseInt(time[1]); + } else { + var h = 0; + var i = 0; + } + return [y, m, d, h, i, 0]; + }; + + // Helper to extract date from a string + jSuites.calendar.extractDateFromString = function (date, format) { + if (date > 0 && Number(date) == date) { + var d = new Date(Math.round((date - 25569) * 86400 * 1000)); + return ( + d.getFullYear() + + "-" + + jSuites.two(d.getMonth()) + + "-" + + jSuites.two(d.getDate()) + + " 00:00:00" + ); + } + + var o = jSuites.mask(date, { mask: format }, true); + if (o.date[0] && o.date[1]) { + if (!o.date[2]) { + o.date[2] = 1; + } + + return ( + o.date[0] + + "-" + + jSuites.two(o.date[1]) + + "-" + + jSuites.two(o.date[2]) + + " " + + jSuites.two(o.date[3]) + + ":" + + jSuites.two(o.date[4]) + + ":" + + jSuites.two(o.date[5]) + ); + } + return ""; + }; + + var excelInitialTime = Date.UTC(1900, 0, 0); + var excelLeapYearBug = Date.UTC(1900, 1, 29); + var millisecondsPerDay = 86400000; + + /** + * Date to number + */ + jSuites.calendar.dateToNum = function (jsDate) { + if (typeof jsDate === "string") { + jsDate = new Date(jsDate + " GMT+0"); + } + var jsDateInMilliseconds = jsDate.getTime(); + + if (jsDateInMilliseconds >= excelLeapYearBug) { + jsDateInMilliseconds += millisecondsPerDay; + } + + jsDateInMilliseconds -= excelInitialTime; + + return jsDateInMilliseconds / millisecondsPerDay; + }; + + /** + * Number to date + */ + // !IMPORTANT! + // Excel incorrectly considers 1900 to be a leap year + jSuites.calendar.numToDate = function (excelSerialNumber) { + var jsDateInMilliseconds = + excelInitialTime + excelSerialNumber * millisecondsPerDay; + + if (jsDateInMilliseconds >= excelLeapYearBug) { + jsDateInMilliseconds -= millisecondsPerDay; + } + + const d = new Date(jsDateInMilliseconds); + + var date = [ + d.getUTCFullYear(), + d.getUTCMonth() + 1, + d.getUTCDate(), + d.getUTCHours(), + d.getUTCMinutes(), + d.getUTCSeconds(), + ]; + + return jSuites.calendar.now(date); + }; + + // Helper to convert date into string + jSuites.calendar.getDateString = function (value, options) { + if (!options) { + var options = {}; + } + + // Labels + if (options && typeof options == "object") { + var format = options.format; + } else { + var format = options; + } + + if (!format) { + format = "YYYY-MM-DD"; + } + + // Convert to number of hours + if (typeof value == "number" && format.indexOf("[h]") >= 0) { + var result = parseFloat(24 * Number(value)); + if (format.indexOf("mm") >= 0) { + var h = ("" + result).split("."); + if (h[1]) { + var d = 60 * parseFloat("0." + h[1]); + d = parseFloat(d.toFixed(2)); + } else { + var d = 0; + } + result = parseInt(h[0]) + ":" + jSuites.two(d); + } + return result; + } + + // Date instance + if (value instanceof Date) { + value = jSuites.calendar.now(value); + } else if (value && jSuites.isNumeric(value)) { + value = jSuites.calendar.numToDate(value); + } + + // Tokens + var tokens = [ + "DAY", + "WD", + "DDDD", + "DDD", + "DD", + "D", + "Q", + "HH24", + "HH12", + "HH", + "H", + "AM/PM", + "MI", + "SS", + "MS", + "YYYY", + "YYY", + "YY", + "Y", + "MONTH", + "MON", + "MMMMM", + "MMMM", + "MMM", + "MM", + "M", + ".", + ]; + + // Expression to extract all tokens from the string + var e = new RegExp(tokens.join("|"), "gi"); + // Extract + var t = format.match(e); + + // Compatibility with excel + for (var i = 0; i < t.length; i++) { + if (t[i].toUpperCase() == "MM") { + // Not a month, correct to minutes + if (t[i - 1] && t[i - 1].toUpperCase().indexOf("H") >= 0) { + t[i] = "mi"; + } else if (t[i - 2] && t[i - 2].toUpperCase().indexOf("H") >= 0) { + t[i] = "mi"; + } else if (t[i + 1] && t[i + 1].toUpperCase().indexOf("S") >= 0) { + t[i] = "mi"; + } else if (t[i + 2] && t[i + 2].toUpperCase().indexOf("S") >= 0) { + t[i] = "mi"; + } + } + } + + // Object + var o = { + tokens: t, + }; + + // Value + if (value) { + var d = "" + value; + var splitStr = d.indexOf("T") !== -1 ? "T" : " "; + d = d.split(splitStr); + + var h = 0; + var m = 0; + var s = 0; + + if (d[1]) { + h = d[1].split(":"); + m = h[1] ? h[1] : 0; + s = h[2] ? h[2] : 0; + h = h[0] ? h[0] : 0; + } + + d = d[0].split("-"); + + if ( + d[0] && + d[1] && + d[2] && + d[0] > 0 && + d[1] > 0 && + d[1] < 13 && + d[2] > 0 && + d[2] < 32 + ) { + // Data + o.data = [d[0], d[1], d[2], h, m, s]; + + // Value + o.value = []; + + // Calendar instance + var calendar = new Date( + o.data[0], + o.data[1] - 1, + o.data[2], + o.data[3], + o.data[4], + o.data[5] + ); + + // Get method + var get = function (i) { + // Token + var t = this.tokens[i]; + // Case token + var s = t.toUpperCase(); + var v = null; + + if (s === "YYYY") { + v = this.data[0]; + } else if (s === "YYY") { + v = this.data[0].substring(1, 4); + } else if (s === "YY") { + v = this.data[0].substring(2, 4); + } else if (s === "Y") { + v = this.data[0].substring(3, 4); + } else if (t === "MON") { + v = jSuites.calendar.months[calendar.getMonth()] + .substr(0, 3) + .toUpperCase(); + } else if (t === "mon") { + v = jSuites.calendar.months[calendar.getMonth()] + .substr(0, 3) + .toLowerCase(); + } else if (t === "MONTH") { + v = jSuites.calendar.months[calendar.getMonth()].toUpperCase(); + } else if (t === "month") { + v = jSuites.calendar.months[calendar.getMonth()].toLowerCase(); + } else if (s === "MMMMM") { + v = jSuites.calendar.months[calendar.getMonth()].substr(0, 1); + } else if (s === "MMMM" || t === "Month") { + v = jSuites.calendar.months[calendar.getMonth()]; + } else if (s === "MMM" || t == "Mon") { + v = jSuites.calendar.months[calendar.getMonth()].substr(0, 3); + } else if (s === "MM") { + v = jSuites.two(this.data[1]); + } else if (s === "M") { + v = calendar.getMonth() + 1; + } else if (t === "DAY") { + v = jSuites.calendar.weekdays[calendar.getDay()].toUpperCase(); + } else if (t === "day") { + v = jSuites.calendar.weekdays[calendar.getDay()].toLowerCase(); + } else if (s === "DDDD" || t == "Day") { + v = jSuites.calendar.weekdays[calendar.getDay()]; + } else if (s === "DDD") { + v = jSuites.calendar.weekdays[calendar.getDay()].substr(0, 3); + } else if (s === "DD") { + v = jSuites.two(this.data[2]); + } else if (s === "D") { + v = this.data[2]; + } else if (s === "Q") { + v = Math.floor((calendar.getMonth() + 3) / 3); + } else if (s === "HH24" || s === "HH") { + v = jSuites.two(this.data[3]); + } else if (s === "HH12") { + if (this.data[3] > 12) { + v = jSuites.two(this.data[3] - 12); + } else { + v = jSuites.two(this.data[3]); + } + } else if (s === "H") { + v = this.data[3]; + } else if (s === "MI") { + v = jSuites.two(this.data[4]); + } else if (s === "SS") { + v = jSuites.two(this.data[5]); + } else if (s === "MS") { + v = calendar.getMilliseconds(); + } else if (s === "AM/PM") { + if (this.data[3] >= 12) { + v = "PM"; + } else { + v = "AM"; + } + } else if (s === "WD") { + v = jSuites.calendar.weekdays[calendar.getDay()]; + } + + if (v === null) { + this.value[i] = this.tokens[i]; + } else { + this.value[i] = v; + } + }; + + for (var i = 0; i < o.tokens.length; i++) { + get.call(o, i); + } + // Put pieces together + value = o.value.join(""); + } else { + value = ""; + } + } + + return value; + }; + + // Jsuites calendar labels + jSuites.calendar.weekdays = [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + ]; + jSuites.calendar.months = [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ]; + jSuites.calendar.weekdaysShort = [ + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", + ]; + jSuites.calendar.monthsShort = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ]; + + jSuites.color = function (el, options) { + // Already created, update options + if (el.color) { + return el.color.setOptions(options, true); + } + + // New instance + var obj = { type: "color" }; + obj.options = {}; + + var container = null; + var backdrop = null; + var content = null; + var resetButton = null; + var closeButton = null; + var tabs = null; + var jsuitesTabs = null; + + /** + * Update options + */ + obj.setOptions = function (options, reset) { + /** + * @typedef {Object} defaults + * @property {(string|Array)} value - Initial value of the compontent + * @property {string} placeholder - The default instruction text on the element + * @property {requestCallback} onchange - Method to be execute after any changes on the element + * @property {requestCallback} onclose - Method to be execute when the element is closed + * @property {string} doneLabel - Label for button done + * @property {string} resetLabel - Label for button reset + * @property {string} resetValue - Value for button reset + * @property {Bool} showResetButton - Active or note for button reset - default false + */ + var defaults = { + placeholder: "", + value: null, + onopen: null, + onclose: null, + onchange: null, + closeOnChange: true, + palette: null, + position: null, + doneLabel: "Done", + resetLabel: "Reset", + fullscreen: false, + opened: false, + }; + + if (!options) { + options = {}; + } + + if (options && !options.palette) { + // Default pallete + options.palette = jSuites.palette(); + } + + // Loop through our object + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + if (typeof obj.options[property] == "undefined" || reset === true) { + obj.options[property] = defaults[property]; + } + } + } + + // Update the text of the controls, if they have already been created + if (resetButton) { + resetButton.innerHTML = obj.options.resetLabel; + } + if (closeButton) { + closeButton.innerHTML = obj.options.doneLabel; + } + + // Update the pallete + if (obj.options.palette && jsuitesTabs) { + jsuitesTabs.updateContent(0, table()); + } + + // Value + if (typeof obj.options.value === "string") { + el.value = obj.options.value; + if (el.tagName === "INPUT") { + el.style.color = el.value; + el.style.backgroundColor = el.value; + } + } + + // Placeholder + if (obj.options.placeholder) { + el.setAttribute("placeholder", obj.options.placeholder); + } else { + if (el.getAttribute("placeholder")) { + el.removeAttribute("placeholder"); + } + } + + return obj; + }; + + obj.select = function (color) { + // Remove current selected mark + var selected = container.querySelector(".jcolor-selected"); + if (selected) { + selected.classList.remove("jcolor-selected"); + } + + // Mark cell as selected + if (obj.values[color]) { + obj.values[color].classList.add("jcolor-selected"); + } + + obj.options.value = color; + }; + + /** + * Open color pallete + */ + obj.open = function () { + if (!container.classList.contains("jcolor-focus")) { + // Start tracking + jSuites.tracking(obj, true); + + // Show color picker + container.classList.add("jcolor-focus"); + + // Select current color + if (obj.options.value) { + obj.select(obj.options.value); + } + + // Reset margin + content.style.marginTop = ""; + content.style.marginLeft = ""; + + var rectContent = content.getBoundingClientRect(); + var availableWidth = jSuites.getWindowWidth(); + var availableHeight = jSuites.getWindowHeight(); + + if (availableWidth < 800 || obj.options.fullscreen == true) { + content.classList.add("jcolor-fullscreen"); + jSuites.animation.slideBottom(content, 1); + backdrop.style.display = "block"; + } else { + if (content.classList.contains("jcolor-fullscreen")) { + content.classList.remove("jcolor-fullscreen"); + backdrop.style.display = ""; + } + + if (obj.options.position) { + content.style.position = "fixed"; + } else { + content.style.position = ""; + } + + if (rectContent.left + rectContent.width > availableWidth) { + content.style.marginLeft = + -1 * + (rectContent.left + rectContent.width - (availableWidth - 20)) + + "px"; + } + if (rectContent.top + rectContent.height > availableHeight) { + content.style.marginTop = + -1 * + (rectContent.top + + rectContent.height - + (availableHeight - 20)) + + "px"; + } + } + + if (typeof obj.options.onopen == "function") { + obj.options.onopen(el); + } + + jsuitesTabs.setBorder(jsuitesTabs.getActive()); + + // Update sliders + if (obj.options.value) { + var rgb = HexToRgb(obj.options.value); + + rgbInputs.forEach(function (rgbInput, index) { + rgbInput.value = rgb[index]; + rgbInput.dispatchEvent(new Event("input")); + }); + } + } + }; + + /** + * Close color pallete + */ + obj.close = function (ignoreEvents) { + if (container.classList.contains("jcolor-focus")) { + // Remove focus + container.classList.remove("jcolor-focus"); + // Make sure backdrop is hidden + backdrop.style.display = ""; + // Call related events + if (!ignoreEvents && typeof obj.options.onclose == "function") { + obj.options.onclose(el); + } + // Stop the object + jSuites.tracking(obj, false); + } + + return obj.options.value; + }; + + /** + * Set value + */ + obj.setValue = function (color) { + if (!color) { + color = ""; + } + + if (color != obj.options.value) { + obj.options.value = color; + slidersResult = color; + + // Remove current selecded mark + obj.select(color); + + // Onchange + if (typeof obj.options.onchange == "function") { + obj.options.onchange(el, color); + } + + // Changes + if (el.value != obj.options.value) { + // Set input value + el.value = obj.options.value; + if (el.tagName === "INPUT") { + el.style.color = el.value; + el.style.backgroundColor = el.value; + } + + // Element onchange native + if (typeof el.oninput == "function") { + el.oninput({ + type: "input", + target: el, + value: el.value, + }); + } + } + + if (obj.options.closeOnChange == true) { + obj.close(); + } + } + }; + + /** + * Get value + */ + obj.getValue = function () { + return obj.options.value; + }; + + var backdropClickControl = false; + + // Converts a number in decimal to hexadecimal + var decToHex = function (num) { + var hex = num.toString(16); + return hex.length === 1 ? "0" + hex : hex; + }; + + // Converts a color in rgb to hexadecimal + var rgbToHex = function (r, g, b) { + return "#" + decToHex(r) + decToHex(g) + decToHex(b); + }; + + // Converts a number in hexadecimal to decimal + var hexToDec = function (hex) { + return parseInt("0x" + hex); + }; + + // Converts a color in hexadecimal to rgb + var HexToRgb = function (hex) { + return [ + hexToDec(hex.substr(1, 2)), + hexToDec(hex.substr(3, 2)), + hexToDec(hex.substr(5, 2)), + ]; + }; + + var table = function () { + // Content of the first tab + var tableContainer = document.createElement("div"); + tableContainer.className = "jcolor-grid"; + + // Cells + obj.values = []; + + // Table pallete + var t = document.createElement("table"); + t.setAttribute("cellpadding", "7"); + t.setAttribute("cellspacing", "0"); + + for (var j = 0; j < obj.options.palette.length; j++) { + var tr = document.createElement("tr"); + for (var i = 0; i < obj.options.palette[j].length; i++) { + var td = document.createElement("td"); + var color = obj.options.palette[j][i]; + if (color.length < 7 && color.substr(0, 1) !== "#") { + color = "#" + color; + } + td.style.backgroundColor = color; + td.setAttribute("data-value", color); + td.innerHTML = ""; + tr.appendChild(td); + + // Selected color + if (obj.options.value == color) { + td.classList.add("jcolor-selected"); + } + + // Possible values + obj.values[color] = td; + } + t.appendChild(tr); + } + + // Append to the table + tableContainer.appendChild(t); + + return tableContainer; + }; + + // Canvas where the image will be rendered + var canvas = document.createElement("canvas"); + canvas.width = 200; + canvas.height = 160; + var context = canvas.getContext("2d"); + + var resizeCanvas = function () { + // Specifications necessary to correctly obtain colors later in certain positions + var m = tabs.firstChild.getBoundingClientRect(); + canvas.width = m.width - 14; + gradient(); + }; + + var gradient = function () { + var g = context.createLinearGradient(0, 0, canvas.width, 0); + // Create color gradient + g.addColorStop(0, "rgb(255,0,0)"); + g.addColorStop(0.15, "rgb(255,0,255)"); + g.addColorStop(0.33, "rgb(0,0,255)"); + g.addColorStop(0.49, "rgb(0,255,255)"); + g.addColorStop(0.67, "rgb(0,255,0)"); + g.addColorStop(0.84, "rgb(255,255,0)"); + g.addColorStop(1, "rgb(255,0,0)"); + context.fillStyle = g; + context.fillRect(0, 0, canvas.width, canvas.height); + g = context.createLinearGradient(0, 0, 0, canvas.height); + g.addColorStop(0, "rgba(255,255,255,1)"); + g.addColorStop(0.5, "rgba(255,255,255,0)"); + g.addColorStop(0.5, "rgba(0,0,0,0)"); + g.addColorStop(1, "rgba(0,0,0,1)"); + context.fillStyle = g; + context.fillRect(0, 0, canvas.width, canvas.height); + }; + + var hsl = function () { + var element = document.createElement("div"); + element.className = "jcolor-hsl"; + + var point = document.createElement("div"); + point.className = "jcolor-point"; + + var div = document.createElement("div"); + div.appendChild(canvas); + div.appendChild(point); + element.appendChild(div); + + // Moves the marquee point to the specified position + var update = function (buttons, x, y) { + if (buttons === 1) { + var rect = element.getBoundingClientRect(); + var left = x - rect.left; + var top = y - rect.top; + if (left < 0) { + left = 0; + } + if (top < 0) { + top = 0; + } + if (left > rect.width) { + left = rect.width; + } + if (top > rect.height) { + top = rect.height; + } + point.style.left = left + "px"; + point.style.top = top + "px"; + var pixel = context.getImageData(left, top, 1, 1).data; + slidersResult = rgbToHex(pixel[0], pixel[1], pixel[2]); + } + }; + + // Applies the point's motion function to the div that contains it + element.addEventListener("mousedown", function (e) { + update(e.buttons, e.clientX, e.clientY); + }); + + element.addEventListener("mousemove", function (e) { + update(e.buttons, e.clientX, e.clientY); + }); + + element.addEventListener("touchmove", function (e) { + update(1, e.changedTouches[0].clientX, e.changedTouches[0].clientY); + }); + + return element; + }; + + var slidersResult = ""; + + var rgbInputs = []; + + var changeInputColors = function () { + if (slidersResult !== "") { + for (var j = 0; j < rgbInputs.length; j++) { + var currentColor = HexToRgb(slidersResult); + + currentColor[j] = 0; + + var newGradient = "linear-gradient(90deg, rgb("; + newGradient += currentColor.join(", "); + newGradient += "), rgb("; + + currentColor[j] = 255; + + newGradient += currentColor.join(", "); + newGradient += "))"; + + rgbInputs[j].style.backgroundImage = newGradient; + } + } + }; + + var sliders = function () { + // Content of the third tab + var slidersElement = document.createElement("div"); + slidersElement.className = "jcolor-sliders"; + + var slidersBody = document.createElement("div"); + + // Creates a range-type input with the specified name + var createSliderInput = function (name) { + var inputContainer = document.createElement("div"); + inputContainer.className = "jcolor-sliders-input-container"; + + var label = document.createElement("label"); + label.innerText = name; + + var subContainer = document.createElement("div"); + subContainer.className = "jcolor-sliders-input-subcontainer"; + + var input = document.createElement("input"); + input.type = "range"; + input.min = 0; + input.max = 255; + input.value = 0; + + inputContainer.appendChild(label); + subContainer.appendChild(input); + + var value = document.createElement("div"); + value.innerText = input.value; + + input.addEventListener("input", function () { + value.innerText = input.value; + }); + + subContainer.appendChild(value); + inputContainer.appendChild(subContainer); + + slidersBody.appendChild(inputContainer); + + return input; + }; + + // Creates red, green and blue inputs + rgbInputs = [ + createSliderInput("Red"), + createSliderInput("Green"), + createSliderInput("Blue"), + ]; + + slidersElement.appendChild(slidersBody); + + // Element that prints the current color + var slidersResultColor = document.createElement("div"); + slidersResultColor.className = "jcolor-sliders-final-color"; + + var resultElement = document.createElement("div"); + resultElement.style.visibility = "hidden"; + resultElement.innerText = "a"; + slidersResultColor.appendChild(resultElement); + + // Update the element that prints the current color + var updateResult = function () { + var resultColor = rgbToHex( + parseInt(rgbInputs[0].value), + parseInt(rgbInputs[1].value), + parseInt(rgbInputs[2].value) + ); + + resultElement.innerText = resultColor; + resultElement.style.color = resultColor; + resultElement.style.removeProperty("visibility"); + + slidersResult = resultColor; + }; + + // Apply the update function to color inputs + rgbInputs.forEach(function (rgbInput) { + rgbInput.addEventListener("input", function () { + updateResult(); + changeInputColors(); + }); + }); + + slidersElement.appendChild(slidersResultColor); + + return slidersElement; + }; + + var init = function () { + // Initial options + obj.setOptions(options); + + // Add a proper input tag when the element is an input + if (el.tagName == "INPUT") { + el.classList.add("jcolor-input"); + el.readOnly = true; + } + + // Table container + container = document.createElement("div"); + container.className = "jcolor"; + + // Table container + backdrop = document.createElement("div"); + backdrop.className = "jcolor-backdrop"; + container.appendChild(backdrop); + + // Content + content = document.createElement("div"); + content.className = "jcolor-content"; + + // Controls + var controls = document.createElement("div"); + controls.className = "jcolor-controls"; + content.appendChild(controls); + + // Reset button + resetButton = document.createElement("div"); + resetButton.className = "jcolor-reset"; + resetButton.innerHTML = obj.options.resetLabel; + controls.appendChild(resetButton); + + // Close button + closeButton = document.createElement("div"); + closeButton.className = "jcolor-close"; + closeButton.innerHTML = obj.options.doneLabel; + controls.appendChild(closeButton); + + // Element that will be used to create the tabs + tabs = document.createElement("div"); + content.appendChild(tabs); + + // Starts the jSuites tabs component + jsuitesTabs = jSuites.tabs(tabs, { + animation: true, + data: [ + { + title: "Grid", + contentElement: table(), + }, + { + title: "Spectrum", + contentElement: hsl(), + }, + { + title: "Sliders", + contentElement: sliders(), + }, + ], + onchange: function (element, instance, index) { + if (index === 1) { + resizeCanvas(); + } else { + var color = slidersResult !== "" ? slidersResult : obj.getValue(); + + if (index === 2 && color) { + var rgb = HexToRgb(color); + + rgbInputs.forEach(function (rgbInput, index) { + rgbInput.value = rgb[index]; + rgbInput.dispatchEvent(new Event("input")); + }); + } + } + }, + palette: "modern", + }); + + container.appendChild(content); + + // Insert picker after the element + if (el.tagName == "INPUT") { + el.parentNode.insertBefore(container, el.nextSibling); + } else { + el.appendChild(container); + } + + container.addEventListener("click", function (e) { + if (e.target.tagName == "TD") { + var value = e.target.getAttribute("data-value"); + if (value) { + obj.setValue(value); + } + } else if (e.target.classList.contains("jcolor-reset")) { + obj.setValue(""); + obj.close(); + } else if (e.target.classList.contains("jcolor-close")) { + if (jsuitesTabs.getActive() > 0) { + obj.setValue(slidersResult); + } + obj.close(); + } else if (e.target.classList.contains("jcolor-backdrop")) { + obj.close(); + } else { + obj.open(); + } + }); + + /** + * If element is focus open the picker + */ + el.addEventListener("mouseup", function (e) { + obj.open(); + }); + + // If the picker is open on the spectrum tab, it changes the canvas size when the window size is changed + window.addEventListener("resize", function () { + if ( + container.classList.contains("jcolor-focus") && + jsuitesTabs.getActive() == 1 + ) { + resizeCanvas(); + } + }); + + // Default opened + if (obj.options.opened == true) { + obj.open(); + } + + // Change + el.change = obj.setValue; + + // Global generic value handler + el.val = function (val) { + if (val === undefined) { + return obj.getValue(); + } else { + obj.setValue(val); + } + }; + + // Keep object available from the node + el.color = obj; + + // Container shortcut + container.color = obj; + }; + + obj.toHex = function (rgb) { + var hex = function (x) { + return ("0" + parseInt(x).toString(16)).slice(-2); + }; + if (/^#[0-9A-F]{6}$/i.test(rgb)) { + return rgb; + } else { + rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); + return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]); + } + }; + + init(); + + return obj; + }; + + jSuites.contextmenu = function (el, options) { + // New instance + var obj = { type: "contextmenu" }; + obj.options = {}; + + // Default configuration + var defaults = { + items: null, + onclick: null, + }; + + // Loop through our object + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + obj.options[property] = defaults[property]; + } + } + + // Class definition + el.classList.add("jcontextmenu"); + + /** + * Open contextmenu + */ + obj.open = function (e, items) { + if (items) { + // Update content + obj.options.items = items; + // Create items + obj.create(items); + } + + // Close current contextmenu + if (jSuites.contextmenu.current) { + jSuites.contextmenu.current.close(); + } + + // Add to the opened components monitor + jSuites.tracking(obj, true); + + // Show context menu + el.classList.add("jcontextmenu-focus"); + + // Current + jSuites.contextmenu.current = obj; + + // Coordinates + if ( + (obj.options.items && obj.options.items.length > 0) || + el.children.length + ) { + if (e.target) { + if (e.changedTouches && e.changedTouches[0]) { + x = e.changedTouches[0].clientX; + y = e.changedTouches[0].clientY; + } else { + var x = e.clientX; + var y = e.clientY; + } + } else { + var x = e.x; + var y = e.y; + } + + var rect = el.getBoundingClientRect(); + + if (window.innerHeight < y + rect.height) { + var h = y - rect.height; + if (h < 0) { + h = 0; + } + el.style.top = h + "px"; + } else { + el.style.top = y + "px"; + } + + if (window.innerWidth < x + rect.width) { + if (x - rect.width > 0) { + el.style.left = x - rect.width + "px"; + } else { + el.style.left = "10px"; + } + } else { + el.style.left = x + "px"; + } + } + }; + + obj.isOpened = function () { + return el.classList.contains("jcontextmenu-focus") ? true : false; + }; + + /** + * Close menu + */ + obj.close = function () { + if (el.classList.contains("jcontextmenu-focus")) { + el.classList.remove("jcontextmenu-focus"); + } + jSuites.tracking(obj, false); + }; + + /** + * Create items based on the declared objectd + * @param {object} items - List of object + */ + obj.create = function (items) { + // Update content + el.innerHTML = ""; + + // Add header contextmenu + var itemHeader = createHeader(); + el.appendChild(itemHeader); + + // Append items + for (var i = 0; i < items.length; i++) { + var itemContainer = createItemElement(items[i]); + el.appendChild(itemContainer); + } + }; + + /** + * createHeader for context menu + * @private + * @returns {HTMLElement} + */ + function createHeader() { + var header = document.createElement("div"); + header.classList.add("header"); + header.addEventListener("click", function (e) { + e.preventDefault(); + e.stopPropagation(); + }); + var title = document.createElement("a"); + title.classList.add("title"); + title.innerHTML = jSuites.translate("Menu"); + + header.appendChild(title); + + var closeButton = document.createElement("a"); + closeButton.classList.add("close"); + closeButton.innerHTML = jSuites.translate("close"); + closeButton.addEventListener("click", function (e) { + obj.close(); + }); + + header.appendChild(closeButton); + + return header; + } + + /** + * Private function for create a new Item element + * @param {type} item + * @returns {jsuitesL#15.jSuites.contextmenu.createItemElement.itemContainer} + */ + function createItemElement(item) { + if (item.type && (item.type == "line" || item.type == "divisor")) { + var itemContainer = document.createElement("hr"); + } else { + var itemContainer = document.createElement("div"); + var itemText = document.createElement("a"); + itemText.innerHTML = item.title; + + if (item.tooltip) { + itemContainer.setAttribute("title", item.tooltip); + } + + if (item.icon) { + itemContainer.setAttribute("data-icon", item.icon); + } + + if (item.id) { + itemContainer.id = item.id; + } + + if (item.disabled) { + itemContainer.className = "jcontextmenu-disabled"; + } else if (item.onclick) { + itemContainer.method = item.onclick; + itemContainer.addEventListener("mousedown", function (e) { + e.preventDefault(); + }); + itemContainer.addEventListener("mouseup", function (e) { + // Execute method + this.method(this, e); + }); + } + itemContainer.appendChild(itemText); + + if (item.submenu) { + var itemIconSubmenu = document.createElement("span"); + itemIconSubmenu.innerHTML = "►"; + itemContainer.appendChild(itemIconSubmenu); + itemContainer.classList.add("jcontexthassubmenu"); + var el_submenu = document.createElement("div"); + // Class definition + el_submenu.classList.add("jcontextmenu"); + // Focusable + el_submenu.setAttribute("tabindex", "900"); + + // Append items + var submenu = item.submenu; + for (var i = 0; i < submenu.length; i++) { + var itemContainerSubMenu = createItemElement(submenu[i]); + el_submenu.appendChild(itemContainerSubMenu); + } + + itemContainer.appendChild(el_submenu); + } else if (item.shortcut) { + var itemShortCut = document.createElement("span"); + itemShortCut.innerHTML = item.shortcut; + itemContainer.appendChild(itemShortCut); + } + } + return itemContainer; + } + + if (typeof obj.options.onclick == "function") { + el.addEventListener("click", function (e) { + obj.options.onclick(obj, e); + }); + } + + // Create items + if (obj.options.items) { + obj.create(obj.options.items); + } + + window.addEventListener("mousewheel", function () { + obj.close(); + }); + + el.contextmenu = obj; + + return obj; + }; + + jSuites.dropdown = function (el, options) { + // Already created, update options + if (el.dropdown) { + return el.dropdown.setOptions(options, true); + } + + // New instance + var obj = { type: "dropdown" }; + obj.options = {}; + + // Success + var success = function (data, val) { + // Set data + if (data && data.length) { + // Sort + if (obj.options.sortResults !== false) { + if (typeof obj.options.sortResults == "function") { + data.sort(obj.options.sortResults); + } else { + data.sort(sortData); + } + } + + obj.setData(data); + } + + // Onload method + if (typeof obj.options.onload == "function") { + obj.options.onload(el, obj, data, val); + } + + // Set value + if (val) { + applyValue(val); + } + + // Component value + if (val === undefined || val === null) { + obj.options.value = ""; + } + el.value = obj.options.value; + + // Open dropdown + if (obj.options.opened == true) { + obj.open(); + } + }; + + // Default sort + var sortData = function (itemA, itemB) { + var testA, testB; + if (typeof itemA == "string") { + testA = itemA; + } else { + if (itemA.text) { + testA = itemA.text; + } else if (itemA.name) { + testA = itemA.name; + } + } + + if (typeof itemB == "string") { + testB = itemB; + } else { + if (itemB.text) { + testB = itemB.text; + } else if (itemB.name) { + testB = itemB.name; + } + } + + if (typeof testA == "string" || typeof testB == "string") { + if (typeof testA != "string") { + testA = "" + testA; + } + if (typeof testB != "string") { + testB = "" + testB; + } + return testA.localeCompare(testB); + } else { + return testA - testB; + } + }; + + /** + * Reset the options for the dropdown + */ + var resetValue = function () { + // Reset value container + obj.value = {}; + // Remove selected + for (var i = 0; i < obj.items.length; i++) { + if (obj.items[i].selected == true) { + if (obj.items[i].element) { + obj.items[i].element.classList.remove("jdropdown-selected"); + } + obj.items[i].selected = null; + } + } + // Reset options + obj.options.value = ""; + }; + + /** + * Apply values to the dropdown + */ + var applyValue = function (values) { + // Reset the current values + resetValue(); + + // Read values + if (values !== null) { + if (!values) { + if (typeof obj.value[""] !== "undefined") { + obj.value[""] = ""; + } + } else { + if (!Array.isArray(values)) { + values = ("" + values).split(";"); + } + for (var i = 0; i < values.length; i++) { + obj.value[values[i]] = ""; + } + } + } + + // Update the DOM + for (var i = 0; i < obj.items.length; i++) { + if (typeof obj.value[Value(i)] !== "undefined") { + if (obj.items[i].element) { + obj.items[i].element.classList.add("jdropdown-selected"); + } + obj.items[i].selected = true; + + // Keep label + obj.value[Value(i)] = Text(i); + } + } + + // Global value + obj.options.value = Object.keys(obj.value).join(";"); + + // Update labels + obj.header.value = obj.getText(); + }; + + // Get the value of one item + var Value = function (k, v) { + // Legacy purposes + if (!obj.options.format) { + var property = "value"; + } else { + var property = "id"; + } + + if (obj.items[k]) { + if (v !== undefined) { + return (obj.items[k].data[property] = v); + } else { + return obj.items[k].data[property]; + } + } + + return ""; + }; + + // Get the label of one item + var Text = function (k, v) { + // Legacy purposes + if (!obj.options.format) { + var property = "text"; + } else { + var property = "name"; + } + + if (obj.items[k]) { + if (v !== undefined) { + return (obj.items[k].data[property] = v); + } else { + return obj.items[k].data[property]; + } + } + + return ""; + }; + + var getValue = function () { + return Object.keys(obj.value); + }; + + var getText = function () { + var data = []; + var k = Object.keys(obj.value); + for (var i = 0; i < k.length; i++) { + data.push(obj.value[k[i]]); + } + return data; + }; + + obj.setOptions = function (options, reset) { + if (!options) { + options = {}; + } + + // Default configuration + var defaults = { + url: null, + data: [], + format: 0, + multiple: false, + autocomplete: false, + remoteSearch: false, + lazyLoading: false, + type: null, + width: null, + maxWidth: null, + opened: false, + value: null, + placeholder: "", + newOptions: false, + position: false, + onchange: null, + onload: null, + onopen: null, + onclose: null, + onfocus: null, + onblur: null, + oninsert: null, + onbeforeinsert: null, + sortResults: false, + autofocus: false, + }; + + // Loop through our object + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + if (typeof obj.options[property] == "undefined" || reset === true) { + obj.options[property] = defaults[property]; + } + } + } + + // Force autocomplete search + if ( + obj.options.remoteSearch == true || + obj.options.type === "searchbar" + ) { + obj.options.autocomplete = true; + } + + // New options + if (obj.options.newOptions == true) { + obj.header.classList.add("jdropdown-add"); + } else { + obj.header.classList.remove("jdropdown-add"); + } + + // Autocomplete + if (obj.options.autocomplete == true) { + obj.header.removeAttribute("readonly"); + } else { + obj.header.setAttribute("readonly", "readonly"); + } + + // Place holder + if (obj.options.placeholder) { + obj.header.setAttribute("placeholder", obj.options.placeholder); + } else { + obj.header.removeAttribute("placeholder"); + } + + // Remove specific dropdown typing to add again + el.classList.remove("jdropdown-searchbar"); + el.classList.remove("jdropdown-picker"); + el.classList.remove("jdropdown-list"); + + if (obj.options.type == "searchbar") { + el.classList.add("jdropdown-searchbar"); + } else if (obj.options.type == "list") { + el.classList.add("jdropdown-list"); + } else if (obj.options.type == "picker") { + el.classList.add("jdropdown-picker"); + } else { + if (jSuites.getWindowWidth() < 800) { + if (obj.options.autocomplete) { + el.classList.add("jdropdown-searchbar"); + obj.options.type = "searchbar"; + } else { + el.classList.add("jdropdown-picker"); + obj.options.type = "picker"; + } + } else { + if (obj.options.width) { + el.style.width = obj.options.width; + el.style.minWidth = obj.options.width; + } else { + el.style.removeProperty("width"); + el.style.removeProperty("min-width"); + } + + el.classList.add("jdropdown-default"); + obj.options.type = "default"; + } + } + + // Close button + if (obj.options.type == "searchbar") { + containerHeader.appendChild(closeButton); + } else { + container.insertBefore(closeButton, container.firstChild); + } + + // Load the content + if (obj.options.url && !options.data) { + jSuites.ajax({ + url: obj.options.url, + method: "GET", + dataType: "json", + success: function (data) { + if (data) { + success(data, obj.options.value); + } + }, + }); + } else { + success(obj.options.data, obj.options.value); + } + + // Return the instance + return obj; + }; + + // Helpers + var containerHeader = null; + var container = null; + var content = null; + var closeButton = null; + var resetButton = null; + var backdrop = null; + + var keyTimer = null; + + /** + * Init dropdown + */ + var init = function () { + // Do not accept null + if (!options) { + options = {}; + } + + // If the element is a SELECT tag, create a configuration object + if (el.tagName == "SELECT") { + var ret = jSuites.dropdown.extractFromDom(el, options); + el = ret.el; + options = ret.options; + } + + // Place holder + if (!options.placeholder && el.getAttribute("placeholder")) { + options.placeholder = el.getAttribute("placeholder"); + } + + // Value container + obj.value = {}; + // Containers + obj.items = []; + obj.groups = []; + // Search options + obj.search = ""; + obj.results = null; + + // Create dropdown + el.classList.add("jdropdown"); + + // Header container + containerHeader = document.createElement("div"); + containerHeader.className = "jdropdown-container-header"; + + // Header + obj.header = document.createElement("input"); + obj.header.className = "jdropdown-header"; + obj.header.type = "text"; + obj.header.setAttribute("autocomplete", "off"); + obj.header.onfocus = function () { + if (typeof obj.options.onfocus == "function") { + obj.options.onfocus(el); + } + }; + + obj.header.onblur = function () { + if (typeof obj.options.onblur == "function") { + obj.options.onblur(el); + } + }; + + obj.header.onkeyup = function (e) { + if (obj.options.autocomplete == true && !keyTimer) { + if (obj.search != obj.header.value.trim()) { + keyTimer = setTimeout(function () { + obj.find(obj.header.value.trim()); + keyTimer = null; + }, 400); + } + + if (!el.classList.contains("jdropdown-focus")) { + obj.open(); + } + } else { + if (!obj.options.autocomplete) { + obj.next(e.key); + } + } + }; + + // Global controls + if (!jSuites.dropdown.hasEvents) { + // Execute only one time + jSuites.dropdown.hasEvents = true; + // Enter and Esc + document.addEventListener("keydown", jSuites.dropdown.keydown); + } + + // Container + container = document.createElement("div"); + container.className = "jdropdown-container"; + + // Dropdown content + content = document.createElement("div"); + content.className = "jdropdown-content"; + + // Close button + closeButton = document.createElement("div"); + closeButton.className = "jdropdown-close"; + closeButton.innerHTML = "Done"; + + // Reset button + resetButton = document.createElement("div"); + resetButton.className = "jdropdown-reset"; + resetButton.innerHTML = "x"; + resetButton.onclick = function () { + obj.reset(); + obj.close(); + }; + + // Create backdrop + backdrop = document.createElement("div"); + backdrop.className = "jdropdown-backdrop"; + + // Append elements + containerHeader.appendChild(obj.header); + + container.appendChild(content); + el.appendChild(containerHeader); + el.appendChild(container); + el.appendChild(backdrop); + + // Set the otiptions + obj.setOptions(options); + + if ("ontouchsend" in document.documentElement === true) { + el.addEventListener("touchsend", jSuites.dropdown.mouseup); + } else { + el.addEventListener("mouseup", jSuites.dropdown.mouseup); + } + + // Lazyloading + if (obj.options.lazyLoading == true) { + jSuites.lazyLoading(content, { + loadUp: obj.loadUp, + loadDown: obj.loadDown, + }); + } + + content.onwheel = function (e) { + e.stopPropagation(); + }; + + // Change method + el.change = obj.setValue; + + // Global generic value handler + el.val = function (val) { + if (val === undefined) { + return obj.getValue(obj.options.multiple ? true : false); + } else { + obj.setValue(val); + } + }; + + // Keep object available from the node + el.dropdown = obj; + }; + + /** + * Get the current remote source of data URL + */ + obj.getUrl = function () { + return obj.options.url; + }; + + /** + * Set the new data from a remote source + * @param {string} url - url from the remote source + * @param {function} callback - callback when the data is loaded + */ + obj.setUrl = function (url, callback) { + obj.options.url = url; + + jSuites.ajax({ + url: obj.options.url, + method: "GET", + dataType: "json", + success: function (data) { + obj.setData(data); + // Callback + if (typeof callback == "function") { + callback(obj); + } + }, + }); + }; + + /** + * Set ID for one item + */ + obj.setId = function (item, v) { + // Legacy purposes + if (!obj.options.format) { + var property = "value"; + } else { + var property = "id"; + } + + if (typeof item == "object") { + item[property] = v; + } else { + obj.items[item].data[property] = v; + } + }; + + /** + * Add a new item + * @param {string} title - title of the new item + * @param {string} id - value/id of the new item + */ + obj.add = function (title, id) { + if (!title) { + var current = obj.options.autocomplete == true ? obj.header.value : ""; + var title = prompt(jSuites.translate("Add A New Option"), current); + if (!title) { + return false; + } + } + + // Id + if (!id) { + id = jSuites.guid(); + } + + // Create new item + if (!obj.options.format) { + var item = { + value: id, + text: title, + }; + } else { + var item = { + id: id, + name: title, + }; + } + + // Callback + if (typeof obj.options.onbeforeinsert == "function") { + var ret = obj.options.onbeforeinsert(obj, item); + if (ret === false) { + return false; + } else if (ret) { + item = ret; + } + } + + // Add item to the main list + obj.options.data.push(item); + + // Create DOM + var newItem = obj.createItem(item); + + // Append DOM to the list + content.appendChild(newItem.element); + + // Callback + if (typeof obj.options.oninsert == "function") { + obj.options.oninsert(obj, item, newItem); + } + + // Show content + if (content.style.display == "none") { + content.style.display = ""; + } + + // Search? + if (obj.results) { + obj.results.push(newItem); + } + + return item; + }; + + /** + * Create a new item + */ + obj.createItem = function (data, group, groupName) { + // Keep the correct source of data + if (!obj.options.format) { + if (!data.value && data.id !== undefined) { + data.value = data.id; + //delete data.id; + } + if (!data.text && data.name !== undefined) { + data.text = data.name; + //delete data.name; + } + } else { + if (!data.id && data.value !== undefined) { + data.id = data.value; + //delete data.value; + } + if (!data.name && data.text !== undefined) { + data.name = data.text; + //delete data.text; + } + } + + // Create item + var item = {}; + item.element = document.createElement("div"); + item.element.className = "jdropdown-item"; + item.element.indexValue = obj.items.length; + item.data = data; + + // Groupd DOM + if (group) { + item.group = group; + } + + // Id + if (data.id) { + item.element.setAttribute("id", data.id); + } + + // Disabled + if (data.disabled == true) { + item.element.setAttribute("data-disabled", true); + } + + // Tooltip + if (data.tooltip) { + item.element.setAttribute("title", data.tooltip); + } + + // Image + if (data.image) { + var image = document.createElement("img"); + image.className = "jdropdown-image"; + image.src = data.image; + if (!data.title) { + image.classList.add("jdropdown-image-small"); + } + item.element.appendChild(image); + } else if (data.icon) { + var icon = document.createElement("span"); + icon.className = "jdropdown-icon material-icons"; + icon.innerText = data.icon; + if (!data.title) { + icon.classList.add("jdropdown-icon-small"); + } + if (data.color) { + icon.style.color = data.color; + } + item.element.appendChild(icon); + } else if (data.color) { + var color = document.createElement("div"); + color.className = "jdropdown-color"; + color.style.backgroundColor = data.color; + item.element.appendChild(color); + } + + // Set content + if (!obj.options.format) { + var text = data.text; + } else { + var text = data.name; + } + + var node = document.createElement("div"); + node.className = "jdropdown-description"; + node.innerHTML = text || " "; + + // Title + if (data.title) { + var title = document.createElement("div"); + title.className = "jdropdown-title"; + title.innerText = data.title; + node.appendChild(title); + } + + // Set content + if (!obj.options.format) { + var val = data.value; + } else { + var val = data.id; + } + + // Value + if (obj.value[val]) { + item.element.classList.add("jdropdown-selected"); + item.selected = true; + } + + // Keep DOM accessible + obj.items.push(item); + + // Add node to item + item.element.appendChild(node); + + return item; + }; + + obj.appendData = function (data) { + // Create elements + if (data.length) { + // Helpers + var items = []; + var groups = []; + + // Prepare data + for (var i = 0; i < data.length; i++) { + // Process groups + if (data[i].group) { + if (!groups[data[i].group]) { + groups[data[i].group] = []; + } + groups[data[i].group].push(i); + } else { + items.push(i); + } + } + + // Number of items counter + var counter = 0; + + // Groups + var groupNames = Object.keys(groups); + + // Append groups in case exists + if (groupNames.length > 0) { + for (var i = 0; i < groupNames.length; i++) { + // Group container + var group = document.createElement("div"); + group.className = "jdropdown-group"; + // Group name + var groupName = document.createElement("div"); + groupName.className = "jdropdown-group-name"; + groupName.innerHTML = groupNames[i]; + // Group arrow + var groupArrow = document.createElement("i"); + groupArrow.className = + "jdropdown-group-arrow jdropdown-group-arrow-down"; + groupName.appendChild(groupArrow); + // Group items + var groupContent = document.createElement("div"); + groupContent.className = "jdropdown-group-items"; + for (var j = 0; j < groups[groupNames[i]].length; j++) { + var item = obj.createItem( + data[groups[groupNames[i]][j]], + group, + groupNames[i] + ); + + if (obj.options.lazyLoading == false || counter < 200) { + groupContent.appendChild(item.element); + counter++; + } + } + // Group itens + group.appendChild(groupName); + group.appendChild(groupContent); + // Keep group DOM + obj.groups.push(group); + // Only add to the screen if children on the group + if (groupContent.children.length > 0) { + // Add DOM to the content + content.appendChild(group); + } + } + } + + if (items.length) { + for (var i = 0; i < items.length; i++) { + var item = obj.createItem(data[items[i]]); + if (obj.options.lazyLoading == false || counter < 200) { + content.appendChild(item.element); + counter++; + } + } + } + } + }; + + obj.setData = function (data) { + // Reset current value + resetValue(); + + // Make sure the content container is blank + content.innerHTML = ""; + + // Reset + obj.header.value = ""; + + // Reset items and values + obj.items = []; + + // Prepare data + if (data && data.length) { + for (var i = 0; i < data.length; i++) { + // Compatibility + if (typeof data[i] != "object") { + // Correct format + if (!obj.options.format) { + data[i] = { + value: data[i], + text: data[i], + }; + } else { + data[i] = { + id: data[i], + name: data[i], + }; + } + } + } + + // Append data + obj.appendData(data); + + // Update data + obj.options.data = data; + } else { + // Update data + obj.options.data = []; + } + + obj.close(); + }; + + obj.getData = function () { + return obj.options.data; + }; + + /** + * Get position of the item + */ + obj.getPosition = function (val) { + for (var i = 0; i < obj.items.length; i++) { + if (Value(i) == val) { + return i; + } + } + return false; + }; + + /** + * Get dropdown current text + */ + obj.getText = function (asArray) { + // Get value + var v = getText(); + // Return value + if (asArray) { + return v; + } else { + return v.join("; "); + } + }; + + /** + * Get dropdown current value + */ + obj.getValue = function (asArray) { + // Get value + var v = getValue(); + // Return value + if (asArray) { + return v; + } else { + return v.join(";"); + } + }; + + /** + * Change event + */ + var change = function (oldValue) { + // Lemonade JS + if (el.value != obj.options.value) { + el.value = obj.options.value; + if (typeof el.oninput == "function") { + el.oninput({ + type: "input", + target: el, + value: el.value, + }); + } + } + + // Events + if (typeof obj.options.onchange == "function") { + obj.options.onchange(el, obj, oldValue, obj.options.value); + } + }; + + /** + * Set value + */ + obj.setValue = function (newValue) { + // Current value + var oldValue = obj.getValue(); + // New value + if (Array.isArray(newValue)) { + newValue = newValue.join(";"); + } + + if (oldValue !== newValue) { + // Set value + applyValue(newValue); + + // Change + change(oldValue); + } + }; + + obj.resetSelected = function () { + obj.setValue(null); + }; + + obj.selectIndex = function (index, force) { + // Make sure is a number + var index = parseInt(index); + + // Only select those existing elements + if ( + obj.items && + obj.items[index] && + (force === true || obj.items[index].data.disabled !== true) + ) { + // Reset cursor to a new position + obj.setCursor(index, false); + + // Behaviour + if (!obj.options.multiple) { + // Update value + if (obj.items[index].selected) { + obj.setValue(null); + } else { + obj.setValue(Value(index)); + } + + // Close component + obj.close(); + } else { + // Old value + var oldValue = obj.options.value; + + // Toggle option + if (obj.items[index].selected) { + obj.items[index].element.classList.remove("jdropdown-selected"); + obj.items[index].selected = false; + + delete obj.value[Value(index)]; + } else { + // Select element + obj.items[index].element.classList.add("jdropdown-selected"); + obj.items[index].selected = true; + + // Set value + obj.value[Value(index)] = Text(index); + } + + // Global value + obj.options.value = Object.keys(obj.value).join(";"); + + // Update labels for multiple dropdown + if (obj.options.autocomplete == false) { + obj.header.value = getText().join("; "); + } + + // Events + change(oldValue); + } + } + }; + + obj.selectItem = function (item) { + obj.selectIndex(item.indexValue); + }; + + var exists = function (k, result) { + for (var j = 0; j < result.length; j++) { + if (!obj.options.format) { + if (result[j].value == k) { + return true; + } + } else { + if (result[j].id == k) { + return true; + } + } + } + return false; + }; + + obj.find = function (str) { + if (obj.search == str.trim()) { + return false; + } + + // Search term + obj.search = str; + + // Reset index + obj.setCursor(); + + // Remove nodes from all groups + if (obj.groups.length) { + for (var i = 0; i < obj.groups.length; i++) { + obj.groups[i].lastChild.innerHTML = ""; + } + } + + // Remove all nodes + content.innerHTML = ""; + + // Remove current items in the remote search + if (obj.options.remoteSearch == true) { + // Reset results + obj.results = null; + // URL + var url = + obj.options.url + + (obj.options.url.indexOf("?") > 0 ? "&" : "?") + + "q=" + + str; + // Remote search + jSuites.ajax({ + url: url, + method: "GET", + dataType: "json", + success: function (result) { + // Reset items + obj.items = []; + + // Add the current selected items to the results in case they are not there + var current = Object.keys(obj.value); + if (current.length) { + for (var i = 0; i < current.length; i++) { + if (!exists(current[i], result)) { + if (!obj.options.format) { + result.unshift({ + value: current[i], + text: obj.value[current[i]], + }); + } else { + result.unshift({ + id: current[i], + name: obj.value[current[i]], + }); + } + } + } + } + // Append data + obj.appendData(result); + // Show or hide results + if (!result.length) { + content.style.display = "none"; + } else { + content.style.display = ""; + } + }, + }); + } else { + // Search terms + str = new RegExp(str, "gi"); + + // Reset search + var results = []; + + // Append options + for (var i = 0; i < obj.items.length; i++) { + // Item label + var label = Text(i); + // Item title + var title = obj.items[i].data.title || ""; + // Group name + var groupName = obj.items[i].data.group || ""; + // Synonym + var synonym = obj.items[i].data.synonym || ""; + if (synonym) { + synonym = synonym.join(" "); + } + + if ( + str == null || + obj.items[i].selected == true || + label.match(str) || + title.match(str) || + groupName.match(str) || + synonym.match(str) + ) { + results.push(obj.items[i]); + } + } + + if (!results.length) { + content.style.display = "none"; + + // Results + obj.results = null; + } else { + content.style.display = ""; + + // Results + obj.results = results; + + // Show 200 items at once + var number = results.length || 0; + + // Lazyloading + if (obj.options.lazyLoading == true && number > 200) { + number = 200; + } + + for (var i = 0; i < number; i++) { + if (obj.results[i].group) { + if (!obj.results[i].group.parentNode) { + content.appendChild(obj.results[i].group); + } + obj.results[i].group.lastChild.appendChild( + obj.results[i].element + ); + } else { + content.appendChild(obj.results[i].element); + } + } + } + } + + // Auto focus + if (obj.options.autofocus == true) { + obj.first(); + } + }; + + obj.open = function () { + // Focus + if (!el.classList.contains("jdropdown-focus")) { + // Current dropdown + jSuites.dropdown.current = obj; + + // Start tracking + jSuites.tracking(obj, true); + + // Add focus + el.classList.add("jdropdown-focus"); + + // Animation + if (jSuites.getWindowWidth() < 800) { + if (obj.options.type == null || obj.options.type == "picker") { + jSuites.animation.slideBottom(container, 1); + } + } + + // Filter + if (obj.options.autocomplete == true) { + obj.header.value = obj.search; + obj.header.focus(); + } + + // Set cursor for the first or first selected element + var k = getValue(); + if (k[0]) { + var cursor = obj.getPosition(k[0]); + if (cursor !== false) { + obj.setCursor(cursor); + } + } + + // Container Size + if (!obj.options.type || obj.options.type == "default") { + var rect = el.getBoundingClientRect(); + var rectContainer = container.getBoundingClientRect(); + + if (obj.options.position) { + container.style.position = "fixed"; + if (window.innerHeight < rect.bottom + rectContainer.height) { + container.style.top = ""; + container.style.bottom = window.innerHeight - rect.top + 1 + "px"; + } else { + container.style.top = rect.bottom + "px"; + container.style.bottom = ""; + } + container.style.left = rect.left + "px"; + } else { + if (window.innerHeight < rect.bottom + rectContainer.height) { + container.style.top = ""; + container.style.bottom = rect.height + 1 + "px"; + } else { + container.style.top = ""; + container.style.bottom = ""; + } + } + + container.style.minWidth = rect.width + "px"; + + if (obj.options.maxWidth) { + container.style.maxWidth = obj.options.maxWidth; + } + + if (!obj.items.length && obj.options.autocomplete == true) { + content.style.display = "none"; + } else { + content.style.display = ""; + } + } + } + + // Events + if (typeof obj.options.onopen == "function") { + obj.options.onopen(el); + } + }; + + obj.close = function (ignoreEvents) { + if (el.classList.contains("jdropdown-focus")) { + // Update labels + obj.header.value = obj.getText(); + // Remove cursor + obj.setCursor(); + // Events + if (!ignoreEvents && typeof obj.options.onclose == "function") { + obj.options.onclose(el); + } + // Blur + if (obj.header.blur) { + obj.header.blur(); + } + // Remove focus + el.classList.remove("jdropdown-focus"); + // Start tracking + jSuites.tracking(obj, false); + // Current dropdown + jSuites.dropdown.current = null; + } + + return obj.getValue(); + }; + + /** + * Set cursor + */ + obj.setCursor = function (index, setPosition) { + // Remove current cursor + if (obj.currentIndex != null) { + // Remove visual cursor + if (obj.items && obj.items[obj.currentIndex]) { + obj.items[obj.currentIndex].element.classList.remove( + "jdropdown-cursor" + ); + } + } + + if (index == undefined) { + obj.currentIndex = null; + } else { + index = parseInt(index); + + // Cursor only for visible items + if (obj.items[index].element.parentNode) { + obj.items[index].element.classList.add("jdropdown-cursor"); + obj.currentIndex = index; + + // Update scroll to the cursor element + if (setPosition !== false && obj.items[obj.currentIndex].element) { + var container = content.scrollTop; + var element = obj.items[obj.currentIndex].element; + content.scrollTop = + element.offsetTop - element.scrollTop + element.clientTop - 95; + } + } + } + }; + + // Compatibility + obj.resetCursor = obj.setCursor; + obj.updateCursor = obj.setCursor; + + /** + * Reset cursor and selected items + */ + obj.reset = function () { + // Reset cursor + obj.setCursor(); + + // Reset selected + obj.setValue(null); + }; + + /** + * First available item + */ + obj.first = function () { + if (obj.options.lazyLoading === true) { + obj.loadFirst(); + } + + var items = content.querySelectorAll(".jdropdown-item"); + if (items.length) { + var newIndex = items[0].indexValue; + obj.setCursor(newIndex); + } + }; + + /** + * Last available item + */ + obj.last = function () { + if (obj.options.lazyLoading === true) { + obj.loadLast(); + } + + var items = content.querySelectorAll(".jdropdown-item"); + if (items.length) { + var newIndex = items[items.length - 1].indexValue; + obj.setCursor(newIndex); + } + }; + + obj.next = function (letter) { + var newIndex = null; + + if (letter) { + if (letter.length == 1) { + // Current index + var current = obj.currentIndex || -1; + // Letter + letter = letter.toLowerCase(); + + var e = null; + var l = null; + var items = content.querySelectorAll(".jdropdown-item"); + if (items.length) { + for (var i = 0; i < items.length; i++) { + if (items[i].indexValue > current) { + if ((e = obj.items[items[i].indexValue])) { + if ((l = e.element.innerText[0])) { + l = l.toLowerCase(); + if (letter == l) { + newIndex = items[i].indexValue; + break; + } + } + } + } + } + obj.setCursor(newIndex); + } + } + } else { + if (obj.currentIndex == undefined || obj.currentIndex == null) { + obj.first(); + } else { + var element = obj.items[obj.currentIndex].element; + + var next = element.nextElementSibling; + if (next) { + if (next.classList.contains("jdropdown-group")) { + next = next.lastChild.firstChild; + } + newIndex = next.indexValue; + } else { + if ( + element.parentNode.classList.contains("jdropdown-group-items") + ) { + if ((next = element.parentNode.parentNode.nextElementSibling)) { + if (next.classList.contains("jdropdown-group")) { + next = next.lastChild.firstChild; + } else if (next.classList.contains("jdropdown-item")) { + newIndex = next.indexValue; + } else { + next = null; + } + } + + if (next) { + newIndex = next.indexValue; + } + } + } + + if (newIndex !== null) { + obj.setCursor(newIndex); + } + } + } + }; + + obj.prev = function () { + var newIndex = null; + + if (obj.currentIndex === null) { + obj.first(); + } else { + var element = obj.items[obj.currentIndex].element; + + var prev = element.previousElementSibling; + if (prev) { + if (prev.classList.contains("jdropdown-group")) { + prev = prev.lastChild.lastChild; + } + newIndex = prev.indexValue; + } else { + if (element.parentNode.classList.contains("jdropdown-group-items")) { + if ((prev = element.parentNode.parentNode.previousElementSibling)) { + if (prev.classList.contains("jdropdown-group")) { + prev = prev.lastChild.lastChild; + } else if (prev.classList.contains("jdropdown-item")) { + newIndex = prev.indexValue; + } else { + prev = null; + } + } + + if (prev) { + newIndex = prev.indexValue; + } + } + } + } + + if (newIndex !== null) { + obj.setCursor(newIndex); + } + }; + + obj.loadFirst = function () { + // Search + if (obj.results) { + var results = obj.results; + } else { + var results = obj.items; + } + + // Show 200 items at once + var number = results.length || 0; + + // Lazyloading + if (obj.options.lazyLoading == true && number > 200) { + number = 200; + } + + // Reset container + content.innerHTML = ""; + + // First 200 items + for (var i = 0; i < number; i++) { + if (results[i].group) { + if (!results[i].group.parentNode) { + content.appendChild(results[i].group); + } + results[i].group.lastChild.appendChild(results[i].element); + } else { + content.appendChild(results[i].element); + } + } + + // Scroll go to the begin + content.scrollTop = 0; + }; + + obj.loadLast = function () { + // Search + if (obj.results) { + var results = obj.results; + } else { + var results = obj.items; + } + + // Show first page + var number = results.length; + + // Max 200 items + if (number > 200) { + number = number - 200; + + // Reset container + content.innerHTML = ""; + + // First 200 items + for (var i = number; i < results.length; i++) { + if (results[i].group) { + if (!results[i].group.parentNode) { + content.appendChild(results[i].group); + } + results[i].group.lastChild.appendChild(results[i].element); + } else { + content.appendChild(results[i].element); + } + } + + // Scroll go to the begin + content.scrollTop = content.scrollHeight; + } + }; + + obj.loadUp = function () { + var test = false; + + // Search + if (obj.results) { + var results = obj.results; + } else { + var results = obj.items; + } + + var items = content.querySelectorAll(".jdropdown-item"); + var fistItem = items[0].indexValue; + fistItem = obj.items[fistItem]; + var index = results.indexOf(fistItem) - 1; + + if (index > 0) { + var number = 0; + + while (index > 0 && results[index] && number < 200) { + if (results[index].group) { + if (!results[index].group.parentNode) { + content.insertBefore(results[index].group, content.firstChild); + } + results[index].group.lastChild.insertBefore( + results[index].element, + results[index].group.lastChild.firstChild + ); + } else { + content.insertBefore(results[index].element, content.firstChild); + } + + index--; + number++; + } + + // New item added + test = true; + } + + return test; + }; + + obj.loadDown = function () { + var test = false; + + // Search + if (obj.results) { + var results = obj.results; + } else { + var results = obj.items; + } + + var items = content.querySelectorAll(".jdropdown-item"); + var lastItem = items[items.length - 1].indexValue; + lastItem = obj.items[lastItem]; + var index = results.indexOf(lastItem) + 1; + + if (index < results.length) { + var number = 0; + while (index < results.length && results[index] && number < 200) { + if (results[index].group) { + if (!results[index].group.parentNode) { + content.appendChild(results[index].group); + } + results[index].group.lastChild.appendChild(results[index].element); + } else { + content.appendChild(results[index].element); + } + + index++; + number++; + } + + // New item added + test = true; + } + + return test; + }; + + init(); + + return obj; + }; + + jSuites.dropdown.keydown = function (e) { + var dropdown = null; + if ((dropdown = jSuites.dropdown.current)) { + if (e.which == 13 || e.which == 9) { + // enter or tab + if ( + dropdown.header.value && + dropdown.currentIndex == null && + dropdown.options.newOptions + ) { + // if they typed something in, but it matched nothing, and newOptions are allowed, start that flow + dropdown.add(); + } else { + // Quick Select/Filter + if ( + dropdown.currentIndex == null && + dropdown.options.autocomplete == true && + dropdown.header.value != "" + ) { + dropdown.find(dropdown.header.value); + } + dropdown.selectIndex(dropdown.currentIndex); + } + } else if (e.which == 38) { + // up arrow + if (dropdown.currentIndex == null) { + dropdown.first(); + } else if (dropdown.currentIndex > 0) { + dropdown.prev(); + } + e.preventDefault(); + } else if (e.which == 40) { + // down arrow + if (dropdown.currentIndex == null) { + dropdown.first(); + } else if (dropdown.currentIndex + 1 < dropdown.items.length) { + dropdown.next(); + } + e.preventDefault(); + } else if (e.which == 36) { + dropdown.first(); + if (!e.target.classList.contains("jdropdown-header")) { + e.preventDefault(); + } + } else if (e.which == 35) { + dropdown.last(); + if (!e.target.classList.contains("jdropdown-header")) { + e.preventDefault(); + } + } else if (e.which == 27) { + dropdown.close(); + } else if (e.which == 33) { + // page up + if (dropdown.currentIndex == null) { + dropdown.first(); + } else if (dropdown.currentIndex > 0) { + for (var i = 0; i < 7; i++) { + dropdown.prev(); + } + } + e.preventDefault(); + } else if (e.which == 34) { + // page down + if (dropdown.currentIndex == null) { + dropdown.first(); + } else if (dropdown.currentIndex + 1 < dropdown.items.length) { + for (var i = 0; i < 7; i++) { + dropdown.next(); + } + } + e.preventDefault(); + } + } + }; + + jSuites.dropdown.mouseup = function (e) { + var element = jSuites.findElement(e.target, "jdropdown"); + if (element) { + var dropdown = element.dropdown; + if (e.target.classList.contains("jdropdown-header")) { + if ( + element.classList.contains("jdropdown-focus") && + element.classList.contains("jdropdown-default") + ) { + var rect = element.getBoundingClientRect(); + + if (e.changedTouches && e.changedTouches[0]) { + var x = e.changedTouches[0].clientX; + var y = e.changedTouches[0].clientY; + } else { + var x = e.clientX; + var y = e.clientY; + } + + if (rect.width - (x - rect.left) < 30) { + if (e.target.classList.contains("jdropdown-add")) { + dropdown.add(); + } else { + dropdown.close(); + } + } else { + if (dropdown.options.autocomplete == false) { + dropdown.close(); + } + } + } else { + dropdown.open(); + } + } else if (e.target.classList.contains("jdropdown-group-name")) { + var items = e.target.nextSibling.children; + if (e.target.nextSibling.style.display != "none") { + for (var i = 0; i < items.length; i++) { + if (items[i].style.display != "none") { + dropdown.selectItem(items[i]); + } + } + } + } else if (e.target.classList.contains("jdropdown-group-arrow")) { + if (e.target.classList.contains("jdropdown-group-arrow-down")) { + e.target.classList.remove("jdropdown-group-arrow-down"); + e.target.classList.add("jdropdown-group-arrow-up"); + e.target.parentNode.nextSibling.style.display = "none"; + } else { + e.target.classList.remove("jdropdown-group-arrow-up"); + e.target.classList.add("jdropdown-group-arrow-down"); + e.target.parentNode.nextSibling.style.display = ""; + } + } else if (e.target.classList.contains("jdropdown-item")) { + dropdown.selectItem(e.target); + } else if (e.target.classList.contains("jdropdown-image")) { + dropdown.selectItem(e.target.parentNode); + } else if (e.target.classList.contains("jdropdown-description")) { + dropdown.selectItem(e.target.parentNode); + } else if (e.target.classList.contains("jdropdown-title")) { + dropdown.selectItem(e.target.parentNode.parentNode); + } else if ( + e.target.classList.contains("jdropdown-close") || + e.target.classList.contains("jdropdown-backdrop") + ) { + dropdown.close(); + } + } + }; + + jSuites.dropdown.extractFromDom = function (el, options) { + // Keep reference + var select = el; + if (!options) { + options = {}; + } + // Prepare configuration + if ( + el.getAttribute("multiple") && + (!options || options.multiple == undefined) + ) { + options.multiple = true; + } + if ( + el.getAttribute("placeholder") && + (!options || options.placeholder == undefined) + ) { + options.placeholder = el.getAttribute("placeholder"); + } + if ( + el.getAttribute("data-autocomplete") && + (!options || options.autocomplete == undefined) + ) { + options.autocomplete = true; + } + if (!options || options.width == undefined) { + options.width = el.offsetWidth; + } + if (el.value && (!options || options.value == undefined)) { + options.value = el.value; + } + if (!options || options.data == undefined) { + options.data = []; + for (var j = 0; j < el.children.length; j++) { + if (el.children[j].tagName == "OPTGROUP") { + for (var i = 0; i < el.children[j].children.length; i++) { + options.data.push({ + value: el.children[j].children[i].value, + text: el.children[j].children[i].innerHTML, + group: el.children[j].getAttribute("label"), + }); + } + } else { + options.data.push({ + value: el.children[j].value, + text: el.children[j].innerHTML, + }); + } + } + } + if (!options || options.onchange == undefined) { + options.onchange = function (a, b, c, d) { + if (options.multiple == true) { + if (obj.items[b].classList.contains("jdropdown-selected")) { + select.options[b].setAttribute("selected", "selected"); + } else { + select.options[b].removeAttribute("selected"); + } + } else { + select.value = d; + } + }; + } + // Create DIV + var div = document.createElement("div"); + el.parentNode.insertBefore(div, el); + el.style.display = "none"; + el = div; + + return { el: el, options: options }; + }; + + jSuites.editor = function (el, options) { + // New instance + var obj = { type: "editor" }; + obj.options = {}; + + // Default configuration + var defaults = { + // Initial HTML content + value: null, + // Initial snippet + snippet: null, + // Add toolbar + toolbar: null, + // Website parser is to read websites and images from cross domain + remoteParser: null, + // Placeholder + placeholder: null, + // Parse URL + parseURL: false, + filterPaste: true, + // Accept drop files + dropZone: false, + dropAsSnippet: false, + acceptImages: false, + acceptFiles: false, + maxFileSize: 5000000, + allowImageResize: true, + // Style + border: true, + padding: true, + maxHeight: null, + height: null, + focus: false, + // Events + onclick: null, + onfocus: null, + onblur: null, + onload: null, + onkeyup: null, + onkeydown: null, + onchange: null, + userSearch: null, + }; + + // Loop through our object + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + obj.options[property] = defaults[property]; + } + } + + // Private controllers + var imageResize = 0; + var editorTimer = null; + var editorAction = null; + var files = []; + + // Make sure element is empty + el.innerHTML = ""; + + // Keep the reference for the container + obj.el = el; + + if (typeof obj.options.onclick == "function") { + el.onclick = function (e) { + obj.options.onclick(el, obj, e); + }; + } + + // Prepare container + el.classList.add("jeditor-container"); + + // Padding + if (obj.options.padding == true) { + el.classList.add("jeditor-padding"); + } + + // Border + if (obj.options.border == false) { + el.style.border = "0px"; + } + + // Snippet + var snippet = document.createElement("div"); + snippet.className = "jsnippet"; + snippet.setAttribute("contenteditable", false); + + // Toolbar + var toolbar = document.createElement("div"); + toolbar.className = "jeditor-toolbar"; + + // Create editor + var editor = document.createElement("div"); + editor.setAttribute("contenteditable", true); + editor.setAttribute("spellcheck", false); + editor.className = "jeditor"; + + // Placeholder + if (obj.options.placeholder) { + editor.setAttribute("data-placeholder", obj.options.placeholder); + } + + // Max height + if (obj.options.maxHeight || obj.options.height) { + editor.style.overflowY = "auto"; + + if (obj.options.maxHeight) { + editor.style.maxHeight = obj.options.maxHeight; + } + if (obj.options.height) { + editor.style.height = obj.options.height; + } + } + + // Set editor initial value + if (obj.options.value) { + var value = obj.options.value; + } else { + var value = el.innerHTML ? el.innerHTML : ""; + } + + if (!value) { + var value = ""; + } + + /** + * Onchange event controllers + */ + var change = function (e) { + if (typeof obj.options.onchange == "function") { + obj.options.onchange(el, obj, e); + } + + // Update value + obj.options.value = obj.getData(); + + // Lemonade JS + if (el.value != obj.options.value) { + el.value = obj.options.value; + if (typeof el.oninput == "function") { + el.oninput({ + type: "input", + target: el, + value: el.value, + }); + } + } + }; + + // Create node + var createUserSearchNode = function () { + // Get coordinates from caret + var sel = window.getSelection + ? window.getSelection() + : document.selection; + var range = sel.getRangeAt(0); + range.deleteContents(); + // Append text node + var input = document.createElement("a"); + input.innerText = "@"; + input.searchable = true; + range.insertNode(input); + var node = range.getBoundingClientRect(); + range.collapse(false); + // Position + userSearch.style.position = "fixed"; + userSearch.style.top = node.top + node.height + 10 + "px"; + userSearch.style.left = node.left + 2 + "px"; + }; + + /** + * Extract images from a HTML string + */ + var extractImageFromHtml = function (html) { + // Create temp element + var div = document.createElement("div"); + div.innerHTML = html; + + // Extract images + var img = div.querySelectorAll("img"); + + if (img.length) { + for (var i = 0; i < img.length; i++) { + obj.addImage(img[i].src); + } + } + }; + + /** + * Insert node at caret + */ + var insertNodeAtCaret = function (newNode) { + var sel, range; + + if (window.getSelection) { + sel = window.getSelection(); + if (sel.rangeCount) { + range = sel.getRangeAt(0); + var selectedText = range.toString(); + range.deleteContents(); + range.insertNode(newNode); + // move the cursor after element + range.setStartAfter(newNode); + range.setEndAfter(newNode); + sel.removeAllRanges(); + sel.addRange(range); + } + } + }; + + var updateTotalImages = function () { + var o = null; + if ((o = snippet.children[0])) { + // Make sure is a grid + if (!o.classList.contains("jslider-grid")) { + o.classList.add("jslider-grid"); + } + // Quantify of images + var number = o.children.length; + // Set the configuration of the grid + o.setAttribute("data-number", number > 4 ? 4 : number); + // Total of images inside the grid + if (number > 4) { + o.setAttribute("data-total", number - 4); + } else { + o.removeAttribute("data-total"); + } + } + }; + + /** + * Append image to the snippet + */ + var appendImage = function (image) { + if (!snippet.innerHTML) { + appendElement({}); + } + snippet.children[0].appendChild(image); + updateTotalImages(); + }; + + /** + * Append snippet + * @Param object data + */ + var appendElement = function (data) { + // Reset snippet + snippet.innerHTML = ""; + + // Attributes + var a = ["image", "title", "description", "host", "url"]; + + for (var i = 0; i < a.length; i++) { + var div = document.createElement("div"); + div.className = "jsnippet-" + a[i]; + div.setAttribute("data-k", a[i]); + snippet.appendChild(div); + if (data[a[i]]) { + if (a[i] == "image") { + if (!Array.isArray(data.image)) { + data.image = [data.image]; + } + for (var j = 0; j < data.image.length; j++) { + var img = document.createElement("img"); + img.src = data.image[j]; + div.appendChild(img); + } + } else { + div.innerHTML = data[a[i]]; + } + } + } + + editor.appendChild(document.createElement("br")); + editor.appendChild(snippet); + }; + + var verifyEditor = function () { + clearTimeout(editorTimer); + editorTimer = setTimeout(function () { + var snippet = editor.querySelector(".jsnippet"); + if (!snippet) { + var html = editor.innerHTML.replace(/\n/g, " "); + var container = document.createElement("div"); + container.innerHTML = html; + var text = container.innerText; + var url = jSuites.editor.detectUrl(text); + + if (url) { + if ( + url[0].substr(-3) == "jpg" || + url[0].substr(-3) == "png" || + url[0].substr(-3) == "gif" + ) { + obj.addImage(url[0], true); + } else { + var id = jSuites.editor.youtubeParser(url[0]); + obj.parseWebsite(url[0], id); + } + } + } + }, 1000); + }; + + obj.parseContent = function () { + verifyEditor(); + }; + + obj.parseWebsite = function (url, youtubeId) { + if (!obj.options.remoteParser) { + console.log("The remoteParser is not defined"); + } else { + // Youtube definitions + if (youtubeId) { + var url = "https://www.youtube.com/watch?v=" + youtubeId; + } + + var p = { + title: "", + description: "", + image: "", + host: url.split("/")[2], + url: url, + }; + + jSuites.ajax({ + url: obj.options.remoteParser + encodeURI(url.trim()), + method: "GET", + dataType: "json", + success: function (result) { + // Get title + if (result.title) { + p.title = result.title; + } + // Description + if (result.description) { + p.description = result.description; + } + // Host + if (result.host) { + p.host = result.host; + } + // Url + if (result.url) { + p.url = result.url; + } + // Append snippet + appendElement(p); + // Add image + if (result.image) { + obj.addImage(result.image, true); + } else if (result["og:image"]) { + obj.addImage(result["og:image"], true); + } + }, + }); + } + }; + + /** + * Set editor value + */ + obj.setData = function (o) { + if (typeof o == "object") { + editor.innerHTML = o.content; + } else { + editor.innerHTML = o; + } + + if (obj.options.focus) { + jSuites.editor.setCursor(editor, true); + } + + // Reset files container + files = []; + }; + + obj.getFiles = function () { + var f = editor.querySelectorAll(".jfile"); + var d = []; + for (var i = 0; i < f.length; i++) { + if (files[f[i].src]) { + d.push(files[f[i].src]); + } + } + return d; + }; + + obj.getText = function () { + return editor.innerText; + }; + + /** + * Get editor data + */ + obj.getData = function (json) { + if (!json) { + var data = editor.innerHTML; + } else { + var data = { + content: "", + }; + + // Get snippet + if (snippet.innerHTML) { + var index = 0; + data.snippet = {}; + for (var i = 0; i < snippet.children.length; i++) { + // Get key from element + var key = snippet.children[i].getAttribute("data-k"); + if (key) { + if (key == "image") { + if (!data.snippet.image) { + data.snippet.image = []; + } + // Get all images + for (var j = 0; j < snippet.children[i].children.length; j++) { + data.snippet.image.push( + snippet.children[i].children[j].getAttribute("src") + ); + } + } else { + data.snippet[key] = snippet.children[i].innerHTML; + } + } + } + } + + // Get files + var f = Object.keys(files); + if (f.length) { + data.files = []; + for (var i = 0; i < f.length; i++) { + data.files.push(files[f[i]]); + } + } + + // Users + if (userSearch) { + // Get tag users + var tagged = editor.querySelectorAll("a[data-user]"); + if (tagged.length) { + data.users = []; + for (var i = 0; i < tagged.length; i++) { + var userId = tagged[i].getAttribute("data-user"); + if (userId) { + data.users.push(userId); + } + } + data.users = data.users.join(","); + } + } + + // Get content + var d = document.createElement("div"); + d.innerHTML = editor.innerHTML; + var s = d.querySelector(".jsnippet"); + if (s) { + s.remove(); + } + + var text = d.innerHTML; + text = text.replace(/
/g, "\n"); + text = text.replace(/<\/div>/g, "\n"); + text = text.replace(/<(?:.|\n)*?>/gm, ""); + data.content = text.trim(); + } + + return data; + }; + + // Reset + obj.reset = function () { + editor.innerHTML = ""; + snippet.innerHTML = ""; + files = []; + }; + + obj.addPdf = function (data) { + if (data.result.substr(0, 4) != "data") { + console.error("Invalid source"); + } else { + var canvas = document.createElement("canvas"); + canvas.width = 60; + canvas.height = 60; + + var img = new Image(); + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); + + canvas.toBlob(function (blob) { + var newImage = document.createElement("img"); + newImage.src = window.URL.createObjectURL(blob); + newImage.title = data.name; + newImage.className = "jfile pdf"; + + files[newImage.src] = { + file: newImage.src, + extension: "pdf", + content: data.result, + }; + + insertNodeAtCaret(newImage); + }); + } + }; + + obj.addImage = function (src, asSnippet) { + if (!src) { + src = ""; + } + + if (src.substr(0, 4) != "data" && !obj.options.remoteParser) { + console.error("remoteParser not defined in your initialization"); + } else { + // This is to process cross domain images + if (src.substr(0, 4) == "data") { + var extension = src.split(";"); + extension = extension[0].split("/"); + extension = extension[1]; + } else { + var extension = src.substr(src.lastIndexOf(".") + 1); + // Work for cross browsers + src = obj.options.remoteParser + src; + } + + var img = new Image(); + + img.onload = function onload() { + var canvas = document.createElement("canvas"); + canvas.width = img.width; + canvas.height = img.height; + + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); + + canvas.toBlob(function (blob) { + var newImage = document.createElement("img"); + newImage.src = window.URL.createObjectURL(blob); + newImage.classList.add("jfile"); + newImage.setAttribute("tabindex", "900"); + files[newImage.src] = { + file: newImage.src, + extension: extension, + content: canvas.toDataURL(), + }; + + if (obj.options.dropAsSnippet || asSnippet) { + appendImage(newImage); + // Just to understand the attachment is part of a snippet + files[newImage.src].snippet = true; + } else { + insertNodeAtCaret(newImage); + } + + change(); + }); + }; + + img.src = src; + } + }; + + obj.addFile = function (files) { + var reader = []; + + for (var i = 0; i < files.length; i++) { + if (files[i].size > obj.options.maxFileSize) { + alert("The file is too big"); + } else { + // Only PDF or Images + var type = files[i].type.split("/"); + + if (type[0] == "image") { + type = 1; + } else if (type[1] == "pdf") { + type = 2; + } else { + type = 0; + } + + if (type) { + // Create file + reader[i] = new FileReader(); + reader[i].index = i; + reader[i].type = type; + reader[i].name = files[i].name; + reader[i].date = files[i].lastModified; + reader[i].size = files[i].size; + reader[i].addEventListener( + "load", + function (data) { + // Get result + if (data.target.type == 2) { + if (obj.options.acceptFiles == true) { + obj.addPdf(data.target); + } + } else { + obj.addImage(data.target.result); + } + }, + false + ); + + reader[i].readAsDataURL(files[i]); + } else { + alert("The extension is not allowed"); + } + } + } + }; + + // Destroy + obj.destroy = function () { + editor.removeEventListener("mouseup", editorMouseUp); + editor.removeEventListener("mousedown", editorMouseDown); + editor.removeEventListener("mousemove", editorMouseMove); + editor.removeEventListener("keyup", editorKeyUp); + editor.removeEventListener("keydown", editorKeyDown); + editor.removeEventListener("dragstart", editorDragStart); + editor.removeEventListener("dragenter", editorDragEnter); + editor.removeEventListener("dragover", editorDragOver); + editor.removeEventListener("drop", editorDrop); + editor.removeEventListener("paste", editorPaste); + editor.removeEventListener("blur", editorBlur); + editor.removeEventListener("focus", editorFocus); + + el.editor = null; + el.classList.remove("jeditor-container"); + + toolbar.remove(); + snippet.remove(); + editor.remove(); + }; + + var isLetter = function (str) { + var regex = + /([\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]+)/g; + return str.match(regex) ? 1 : 0; + }; + + // Event handlers + var editorMouseUp = function (e) { + if (editorAction && editorAction.e) { + editorAction.e.classList.remove("resizing"); + } + + editorAction = false; + }; + + var editorMouseDown = function (e) { + var close = function (snippet) { + var rect = snippet.getBoundingClientRect(); + if ( + rect.width - (e.clientX - rect.left) < 40 && + e.clientY - rect.top < 40 + ) { + snippet.innerHTML = ""; + snippet.remove(); + } + }; + + if (e.target.tagName == "IMG") { + if (e.target.style.cursor) { + var rect = e.target.getBoundingClientRect(); + editorAction = { + e: e.target, + x: e.clientX, + y: e.clientY, + w: rect.width, + h: rect.height, + d: e.target.style.cursor, + }; + + if (!e.target.width) { + e.target.width = rect.width + "px"; + } + + if (!e.target.height) { + e.target.height = rect.height + "px"; + } + + var s = window.getSelection(); + if (s.rangeCount) { + for (var i = 0; i < s.rangeCount; i++) { + s.removeRange(s.getRangeAt(i)); + } + } + + e.target.classList.add("resizing"); + } else { + editorAction = true; + } + } else { + if (e.target.classList.contains("jsnippet")) { + close(e.target); + } else if (e.target.parentNode.classList.contains("jsnippet")) { + close(e.target.parentNode); + } + + editorAction = true; + } + }; + + var editorMouseMove = function (e) { + if ( + e.target.tagName == "IMG" && + !e.target.parentNode.classList.contains("jsnippet-image") && + obj.options.allowImageResize == true + ) { + if (e.target.getAttribute("tabindex")) { + var rect = e.target.getBoundingClientRect(); + if (e.clientY - rect.top < 5) { + if (rect.width - (e.clientX - rect.left) < 5) { + e.target.style.cursor = "ne-resize"; + } else if (e.clientX - rect.left < 5) { + e.target.style.cursor = "nw-resize"; + } else { + e.target.style.cursor = "n-resize"; + } + } else if (rect.height - (e.clientY - rect.top) < 5) { + if (rect.width - (e.clientX - rect.left) < 5) { + e.target.style.cursor = "se-resize"; + } else if (e.clientX - rect.left < 5) { + e.target.style.cursor = "sw-resize"; + } else { + e.target.style.cursor = "s-resize"; + } + } else if (rect.width - (e.clientX - rect.left) < 5) { + e.target.style.cursor = "e-resize"; + } else if (e.clientX - rect.left < 5) { + e.target.style.cursor = "w-resize"; + } else { + e.target.style.cursor = ""; + } + } + } + + // Move + if (e.which == 1 && editorAction && editorAction.d) { + if ( + editorAction.d == "e-resize" || + editorAction.d == "ne-resize" || + editorAction.d == "se-resize" + ) { + editorAction.e.width = editorAction.w + (e.clientX - editorAction.x); + + if (e.shiftKey) { + var newHeight = + (e.clientX - editorAction.x) * (editorAction.h / editorAction.w); + editorAction.e.height = editorAction.h + newHeight; + } else { + var newHeight = null; + } + } + + if (!newHeight) { + if ( + editorAction.d == "s-resize" || + editorAction.d == "se-resize" || + editorAction.d == "sw-resize" + ) { + if (!e.shiftKey) { + editorAction.e.height = + editorAction.h + (e.clientY - editorAction.y); + } + } + } + } + }; + + var editorKeyUp = function (e) { + if (!editor.innerHTML) { + editor.innerHTML = "

"; + } + + if (userSearch) { + var t = jSuites.getNode(); + if (t) { + if (t.searchable === true) { + if (t.innerText && t.innerText.substr(0, 1) == "@") { + userSearchInstance(t.innerText.substr(1)); + } + } else if (t.searchable === false) { + if (t.innerText !== t.getAttribute("data-label")) { + t.searchable = true; + t.removeAttribute("href"); + } + } + } + } + + if (typeof obj.options.onkeyup == "function") { + obj.options.onkeyup(el, obj, e); + } + }; + + var editorKeyDown = function (e) { + // Check for URL + if (obj.options.parseURL == true) { + verifyEditor(); + } + + if (userSearch) { + if (e.key == "@") { + createUserSearchNode(editor); + e.preventDefault(); + } else { + if (userSearchInstance.isOpened()) { + userSearchInstance.keydown(e); + } + } + } + + if (typeof obj.options.onkeydown == "function") { + obj.options.onkeydown(el, obj, e); + } + + if (e.key == "Delete") { + if ( + e.target.tagName == "IMG" && + e.target.parentNode.classList.contains("jsnippet-image") + ) { + e.target.remove(); + updateTotalImages(); + } + } + }; + + // Elements to be removed + var remove = [ + HTMLUnknownElement, + HTMLAudioElement, + HTMLEmbedElement, + HTMLIFrameElement, + HTMLTextAreaElement, + HTMLInputElement, + HTMLScriptElement, + ]; + + // Valid properties + var validProperty = [ + "width", + "height", + "align", + "border", + "src", + "tabindex", + ]; + + // Valid CSS attributes + var validStyle = [ + "color", + "font-weight", + "font-size", + "background", + "background-color", + "margin", + ]; + + var parse = function (element) { + // Remove attributes + if (element.attributes && element.attributes.length) { + var image = null; + var style = null; + // Process style attribute + var elementStyle = element.getAttribute("style"); + if (elementStyle) { + style = []; + var t = elementStyle.split(";"); + for (var j = 0; j < t.length; j++) { + var v = t[j].trim().split(":"); + if (validStyle.indexOf(v[0].trim()) >= 0) { + var k = v.shift(); + var v = v.join(":"); + style.push(k + ":" + v); + } + } + } + // Process image + if (element.tagName.toUpperCase() == "IMG") { + if (!obj.options.acceptImages || !element.src) { + element.parentNode.removeChild(element); + } else { + // Check if is data + element.setAttribute("tabindex", "900"); + // Check attributes for persistance + obj.addImage(element.src); + } + } + // Remove attributes + var attr = []; + var numAttributes = element.attributes.length - 1; + if (numAttributes > 0) { + for (var i = numAttributes; i >= 0; i--) { + attr.push(element.attributes[i].name); + } + attr.forEach(function (v) { + if (validProperty.indexOf(v) == -1) { + element.removeAttribute(v); + } + }); + } + element.style = ""; + // Add valid style + if (style && style.length) { + element.setAttribute("style", style.join(";")); + } + } + // Parse children + if (element.children.length) { + for (var i = 0; i < element.children.length; i++) { + parse(element.children[i]); + } + } + + if (remove.indexOf(element.constructor) >= 0) { + element.remove(); + } + }; + + var filter = function (data) { + if (data) { + data = data.replace(new RegExp("", "gsi"), ""); + } + var parser = new DOMParser(); + var d = parser.parseFromString(data, "text/html"); + parse(d); + var span = document.createElement("span"); + span.innerHTML = d.firstChild.innerHTML; + return span; + }; + + var editorPaste = function (e) { + if (obj.options.filterPaste == true) { + if (e.clipboardData || e.originalEvent.clipboardData) { + var html = (e.originalEvent || e).clipboardData.getData("text/html"); + var text = (e.originalEvent || e).clipboardData.getData("text/plain"); + var file = (e.originalEvent || e).clipboardData.files; + } else if (window.clipboardData) { + var html = window.clipboardData.getData("Html"); + var text = window.clipboardData.getData("Text"); + var file = window.clipboardData.files; + } + + if (file.length) { + // Paste a image from the clipboard + obj.addFile(file); + } else { + if (!html) { + html = text.split("\r\n"); + if (!e.target.innerText) { + html.map(function (v) { + var d = document.createElement("div"); + d.innerText = v; + editor.appendChild(d); + }); + } else { + html = html.map(function (v) { + return "
" + v + "
"; + }); + document.execCommand("insertHtml", false, html.join("")); + } + } else { + var d = filter(html); + // Paste to the editor + //insertNodeAtCaret(d); + document.execCommand("insertHtml", false, d.innerHTML); + } + } + + e.preventDefault(); + } + }; + + var editorDragStart = function (e) { + if (editorAction && editorAction.e) { + e.preventDefault(); + } + }; + + var editorDragEnter = function (e) { + if (editorAction || obj.options.dropZone == false) { + // Do nothing + } else { + el.classList.add("jeditor-dragging"); + e.preventDefault(); + } + }; + + var editorDragOver = function (e) { + if (editorAction || obj.options.dropZone == false) { + // Do nothing + } else { + if (editorTimer) { + clearTimeout(editorTimer); + } + + editorTimer = setTimeout(function () { + el.classList.remove("jeditor-dragging"); + }, 100); + e.preventDefault(); + } + }; + + var editorDrop = function (e) { + if (editorAction || obj.options.dropZone == false) { + // Do nothing + } else { + // Position caret on the drop + var range = null; + if (document.caretRangeFromPoint) { + range = document.caretRangeFromPoint(e.clientX, e.clientY); + } else if (e.rangeParent) { + range = document.createRange(); + range.setStart(e.rangeParent, e.rangeOffset); + } + var sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + sel.anchorNode.parentNode.focus(); + + var html = (e.originalEvent || e).dataTransfer.getData("text/html"); + var text = (e.originalEvent || e).dataTransfer.getData("text/plain"); + var file = (e.originalEvent || e).dataTransfer.files; + + if (file.length) { + obj.addFile(file); + } else if (text) { + extractImageFromHtml(html); + } + + el.classList.remove("jeditor-dragging"); + e.preventDefault(); + } + }; + + var editorBlur = function (e) { + if (userSearch && userSearchInstance.isOpened()) { + userSearchInstance.close(); + } + + // Blur + if (typeof obj.options.onblur == "function") { + obj.options.onblur(el, obj, e); + } + + change(e); + }; + + var editorFocus = function (e) { + // Focus + if (typeof obj.options.onfocus == "function") { + obj.options.onfocus(el, obj, e); + } + }; + + editor.addEventListener("mouseup", editorMouseUp); + editor.addEventListener("mousedown", editorMouseDown); + editor.addEventListener("mousemove", editorMouseMove); + editor.addEventListener("keyup", editorKeyUp); + editor.addEventListener("keydown", editorKeyDown); + editor.addEventListener("dragstart", editorDragStart); + editor.addEventListener("dragenter", editorDragEnter); + editor.addEventListener("dragover", editorDragOver); + editor.addEventListener("drop", editorDrop); + editor.addEventListener("paste", editorPaste); + editor.addEventListener("focus", editorFocus); + editor.addEventListener("blur", editorBlur); + + // Onload + if (typeof obj.options.onload == "function") { + obj.options.onload(el, obj, editor); + } + + // Set value to the editor + editor.innerHTML = value; + + // Append editor to the containre + el.appendChild(editor); + + // Snippet + if (obj.options.snippet) { + appendElement(obj.options.snippet); + } + + // Default toolbar + if (obj.options.toolbar == null) { + obj.options.toolbar = jSuites.editor.getDefaultToolbar(); + } + + // Add toolbar + if (obj.options.toolbar) { + // Append to the DOM + el.appendChild(toolbar); + // Create toolbar + jSuites.toolbar(toolbar, { + container: true, + responsive: true, + items: obj.options.toolbar, + }); + } + + // Add user search + var userSearch = null; + var userSearchInstance = null; + if (obj.options.userSearch) { + userSearch = document.createElement("div"); + el.appendChild(userSearch); + + // Component + userSearchInstance = jSuites.search(userSearch, { + data: obj.options.userSearch, + placeholder: jSuites.translate("Type the name a user"), + onselect: function (a, b, c, d) { + if (userSearchInstance.isOpened()) { + var t = jSuites.getNode(); + if ( + t && + t.searchable == true && + t.innerText.trim() && + t.innerText.substr(1) + ) { + t.innerText = "@" + c; + t.href = "/" + c; + t.setAttribute("data-user", d); + t.setAttribute("data-label", t.innerText); + t.searchable = false; + jSuites.focus(t); + } + } + }, + }); + } + + // Focus to the editor + if (obj.options.focus) { + jSuites.editor.setCursor( + editor, + obj.options.focus == "initial" ? true : false + ); + } + + // Change method + el.change = obj.setData; + + // Global generic value handler + el.val = function (val) { + if (val === undefined) { + // Data type + var o = el.getAttribute("data-html") === "true" ? false : true; + return obj.getData(o); + } else { + obj.setData(val); + } + }; + + el.editor = obj; + + return obj; + }; + + jSuites.editor.setCursor = function (element, first) { + element.focus(); + document.execCommand("selectAll"); + var sel = window.getSelection(); + var range = sel.getRangeAt(0); + if (first == true) { + var node = range.startContainer; + var size = 0; + } else { + var node = range.endContainer; + var size = node.length; + } + range.setStart(node, size); + range.setEnd(node, size); + sel.removeAllRanges(); + sel.addRange(range); + }; + + jSuites.editor.getDomain = function (url) { + return url + .replace("http://", "") + .replace("https://", "") + .replace("www.", "") + .split(/[/?#]/)[0] + .split(/:/g)[0]; + }; + + jSuites.editor.detectUrl = function (text) { + var expression = + /(((https?:\/\/)|(www\.))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]+)/gi; + var links = text.match(expression); + + if (links) { + if (links[0].substr(0, 3) == "www") { + links[0] = "http://" + links[0]; + } + } + + return links; + }; + + jSuites.editor.youtubeParser = function (url) { + var regExp = + /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/; + var match = url.match(regExp); + + return match && match[7].length == 11 ? match[7] : false; + }; + + jSuites.editor.getDefaultToolbar = function () { + return [ + { + content: "undo", + onclick: function () { + document.execCommand("undo"); + }, + }, + { + content: "redo", + onclick: function () { + document.execCommand("redo"); + }, + }, + { + type: "divisor", + }, + { + content: "format_bold", + onclick: function (a, b, c) { + document.execCommand("bold"); + + if (document.queryCommandState("bold")) { + c.classList.add("selected"); + } else { + c.classList.remove("selected"); + } + }, + }, + { + content: "format_italic", + onclick: function (a, b, c) { + document.execCommand("italic"); + + if (document.queryCommandState("italic")) { + c.classList.add("selected"); + } else { + c.classList.remove("selected"); + } + }, + }, + { + content: "format_underline", + onclick: function (a, b, c) { + document.execCommand("underline"); + + if (document.queryCommandState("underline")) { + c.classList.add("selected"); + } else { + c.classList.remove("selected"); + } + }, + }, + { + type: "divisor", + }, + { + content: "format_list_bulleted", + onclick: function (a, b, c) { + document.execCommand("insertUnorderedList"); + + if (document.queryCommandState("insertUnorderedList")) { + c.classList.add("selected"); + } else { + c.classList.remove("selected"); + } + }, + }, + { + content: "format_list_numbered", + onclick: function (a, b, c) { + document.execCommand("insertOrderedList"); + + if (document.queryCommandState("insertOrderedList")) { + c.classList.add("selected"); + } else { + c.classList.remove("selected"); + } + }, + }, + { + content: "format_indent_increase", + onclick: function (a, b, c) { + document.execCommand("indent", true, null); + + if (document.queryCommandState("indent")) { + c.classList.add("selected"); + } else { + c.classList.remove("selected"); + } + }, + }, + { + content: "format_indent_decrease", + onclick: function () { + document.execCommand("outdent"); + + if (document.queryCommandState("outdent")) { + this.classList.add("selected"); + } else { + this.classList.remove("selected"); + } + }, + } /*, + { + icon: ['format_align_left', 'format_align_right', 'format_align_center'], + onclick: function() { + document.execCommand('justifyCenter'); + + if (document.queryCommandState("justifyCenter")) { + this.classList.add('selected'); + } else { + this.classList.remove('selected'); + } + } + } + { + type:'select', + items: ['Verdana','Arial','Courier New'], + onchange: function() { + } + }, + { + type:'select', + items: ['10px','12px','14px','16px','18px','20px','22px'], + onchange: function() { + } + }, + { + icon:'format_align_left', + onclick: function() { + document.execCommand('JustifyLeft'); + + if (document.queryCommandState("JustifyLeft")) { + this.classList.add('selected'); + } else { + this.classList.remove('selected'); + } + } + }, + { + icon:'format_align_center', + onclick: function() { + document.execCommand('justifyCenter'); + + if (document.queryCommandState("justifyCenter")) { + this.classList.add('selected'); + } else { + this.classList.remove('selected'); + } + } + }, + { + icon:'format_align_right', + onclick: function() { + document.execCommand('justifyRight'); + + if (document.queryCommandState("justifyRight")) { + this.classList.add('selected'); + } else { + this.classList.remove('selected'); + } + } + }, + { + icon:'format_align_justify', + onclick: function() { + document.execCommand('justifyFull'); + + if (document.queryCommandState("justifyFull")) { + this.classList.add('selected'); + } else { + this.classList.remove('selected'); + } + } + }, + { + icon:'format_list_bulleted', + onclick: function() { + document.execCommand('insertUnorderedList'); + + if (document.queryCommandState("insertUnorderedList")) { + this.classList.add('selected'); + } else { + this.classList.remove('selected'); + } + } + }*/, + ]; + }; + + jSuites.form = function (el, options) { + var obj = {}; + obj.options = {}; + + // Default configuration + var defaults = { + url: null, + message: "Are you sure? There are unsaved information in your form", + ignore: false, + currentHash: null, + submitButton: null, + validations: null, + onbeforeload: null, + onload: null, + onbeforesave: null, + onsave: null, + onbeforeremove: null, + onremove: null, + onerror: function (el, message) { + jSuites.alert(message); + }, + }; + + // Loop through our object + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + obj.options[property] = defaults[property]; + } + } + + // Validations + if (!obj.options.validations) { + obj.options.validations = {}; + } + + // Submit Button + if (!obj.options.submitButton) { + obj.options.submitButton = el.querySelector("input[type=submit]"); + } + + if (obj.options.submitButton && obj.options.url) { + obj.options.submitButton.onclick = function () { + obj.save(); + }; + } + + if (!obj.options.validations.email) { + obj.options.validations.email = jSuites.validations.email; + } + + if (!obj.options.validations.length) { + obj.options.validations.length = jSuites.validations.length; + } + + if (!obj.options.validations.required) { + obj.options.validations.required = jSuites.validations.required; + } + + obj.setUrl = function (url) { + obj.options.url = url; + }; + + obj.load = function () { + jSuites.ajax({ + url: obj.options.url, + method: "GET", + dataType: "json", + queue: true, + success: function (data) { + // Overwrite values from the backend + if (typeof obj.options.onbeforeload == "function") { + var ret = obj.options.onbeforeload(el, data); + if (ret) { + data = ret; + } + } + // Apply values to the form + jSuites.form.setElements(el, data); + // Onload methods + if (typeof obj.options.onload == "function") { + obj.options.onload(el, data); + } + }, + }); + }; + + obj.save = function () { + var test = obj.validate(); + + if (test) { + obj.options.onerror(el, test); + } else { + var data = jSuites.form.getElements(el, true); + + if (typeof obj.options.onbeforesave == "function") { + var data = obj.options.onbeforesave(el, data); + + if (data === false) { + return; + } + } + + jSuites.ajax({ + url: obj.options.url, + method: "POST", + dataType: "json", + data: data, + success: function (result) { + if (typeof obj.options.onsave == "function") { + obj.options.onsave(el, data, result); + } + }, + }); + } + }; + + obj.remove = function () { + if (typeof obj.options.onbeforeremove == "function") { + var ret = obj.options.onbeforeremove(el, obj); + if (ret === false) { + return false; + } + } + + jSuites.ajax({ + url: obj.options.url, + method: "DELETE", + dataType: "json", + success: function (result) { + if (typeof obj.options.onremove == "function") { + obj.options.onremove(el, obj, result); + } + + obj.reset(); + }, + }); + }; + + var addError = function (element) { + // Add error in the element + element.classList.add("error"); + // Submit button + if (obj.options.submitButton) { + obj.options.submitButton.setAttribute("disabled", true); + } + // Return error message + var error = + element.getAttribute("data-error") || "There is an error in the form"; + element.setAttribute("title", error); + return error; + }; + + var delError = function (element) { + var error = false; + // Remove class from this element + element.classList.remove("error"); + element.removeAttribute("title"); + // Get elements in the form + var elements = el.querySelectorAll("input, select, textarea, div[name]"); + // Run all elements + for (var i = 0; i < elements.length; i++) { + if (elements[i].getAttribute("data-validation")) { + if (elements[i].classList.contains("error")) { + error = true; + } + } + } + + if (obj.options.submitButton) { + if (error) { + obj.options.submitButton.setAttribute("disabled", true); + } else { + obj.options.submitButton.removeAttribute("disabled"); + } + } + }; + + obj.validateElement = function (element) { + // Test results + var test = false; + // Value + var value = jSuites.form.getValue(element); + // Validation + var validation = element.getAttribute("data-validation"); + // Parse + if ( + typeof obj.options.validations[validation] == "function" && + !obj.options.validations[validation](value, element) + ) { + // Not passed in the test + test = addError(element); + } else { + if (element.classList.contains("error")) { + delError(element); + } + } + + return test; + }; + + obj.reset = function () { + // Get elements in the form + var name = null; + var elements = el.querySelectorAll("input, select, textarea, div[name]"); + // Run all elements + for (var i = 0; i < elements.length; i++) { + if ((name = elements[i].getAttribute("name"))) { + if (elements[i].type == "checkbox" || elements[i].type == "radio") { + elements[i].checked = false; + } else { + if (typeof elements[i].val == "function") { + elements[i].val(""); + } else { + elements[i].value = ""; + } + } + } + } + }; + + // Run form validation + obj.validate = function () { + var test = []; + // Get elements in the form + var elements = el.querySelectorAll("input, select, textarea, div[name]"); + // Run all elements + for (var i = 0; i < elements.length; i++) { + // Required + if (elements[i].getAttribute("data-validation")) { + var res = obj.validateElement(elements[i]); + if (res) { + test.push(res); + } + } + } + if (test.length > 0) { + return test.join("
"); + } else { + return false; + } + }; + + // Check the form + obj.getError = function () { + // Validation + return obj.validation() ? true : false; + }; + + // Return the form hash + obj.setHash = function () { + return obj.getHash(jSuites.form.getElements(el)); + }; + + // Get the form hash + obj.getHash = function (str) { + var hash = 0, + i, + chr; + + if (str.length === 0) { + return hash; + } else { + for (i = 0; i < str.length; i++) { + chr = str.charCodeAt(i); + hash = (hash << 5) - hash + chr; + hash |= 0; + } + } + + return hash; + }; + + // Is there any change in the form since start tracking? + obj.isChanged = function () { + var hash = obj.setHash(); + return obj.options.currentHash != hash; + }; + + // Restart tracking + obj.resetTracker = function () { + obj.options.currentHash = obj.setHash(); + obj.options.ignore = false; + }; + + // Ignore flag + obj.setIgnore = function (ignoreFlag) { + obj.options.ignore = ignoreFlag ? true : false; + }; + + // Start tracking in one second + setTimeout(function () { + obj.options.currentHash = obj.setHash(); + }, 1000); + + // Validations + el.addEventListener("keyup", function (e) { + if (e.target.getAttribute("data-validation")) { + obj.validateElement(e.target); + } + }); + + // Alert + if (!jSuites.form.hasEvents) { + window.addEventListener("beforeunload", function (e) { + if (obj.isChanged() && obj.options.ignore == false) { + var confirmationMessage = obj.options.message + ? obj.options.message + : "o/"; + + if (confirmationMessage) { + if (typeof e == "undefined") { + e = window.event; + } + + if (e) { + e.returnValue = confirmationMessage; + } + + return confirmationMessage; + } else { + return void 0; + } + } + }); + + jSuites.form.hasEvents = true; + } + + el.form = obj; + + return obj; + }; + + // Get value from one element + jSuites.form.getValue = function (element) { + var value = null; + if (element.type == "checkbox") { + if (element.checked == true) { + value = element.value || true; + } + } else if (element.type == "radio") { + if (element.checked == true) { + value = element.value; + } + } else if (element.type == "file") { + value = element.files; + } else if (element.tagName == "select" && element.multiple == true) { + value = []; + var options = element.querySelectorAll("options[selected]"); + for (var j = 0; j < options.length; j++) { + value.push(options[j].value); + } + } else if (typeof element.val == "function") { + value = element.val(); + } else { + value = element.value || ""; + } + + return value; + }; + + // Get form elements + jSuites.form.getElements = function (el, asArray) { + var data = {}; + var name = null; + var elements = el.querySelectorAll("input, select, textarea, div[name]"); + + for (var i = 0; i < elements.length; i++) { + if ((name = elements[i].getAttribute("name"))) { + data[name] = jSuites.form.getValue(elements[i]) || ""; + } + } + + return asArray == true ? data : JSON.stringify(data); + }; + + //Get form elements + jSuites.form.setElements = function (el, data) { + var name = null; + var value = null; + var elements = el.querySelectorAll("input, select, textarea, div[name]"); + for (var i = 0; i < elements.length; i++) { + // Attributes + var type = elements[i].getAttribute("type"); + if ((name = elements[i].getAttribute("name"))) { + // Transform variable names in pathname + name = name.replace(new RegExp(/\[(.*?)\]/gi), ".$1"); + value = null; + // Seach for the data in the path + if (name.match(/\./)) { + var tmp = jSuites.path.call(data, name) || ""; + if (typeof tmp !== "undefined") { + value = tmp; + } + } else { + if (typeof data[name] !== "undefined") { + value = data[name]; + } + } + // Set the values + if (value !== null) { + if (type == "checkbox" || type == "radio") { + elements[i].checked = value ? true : false; + } else if (type == "file") { + // Do nothing + } else { + if (typeof elements[i].val == "function") { + elements[i].val(value); + } else { + elements[i].value = value; + } + } + } + } + } + }; + + // Legacy + jSuites.tracker = jSuites.form; + + jSuites.focus = function (el) { + if (el.innerText.length) { + var range = document.createRange(); + var sel = window.getSelection(); + var node = el.childNodes[el.childNodes.length - 1]; + range.setStart(node, node.length); + range.collapse(true); + sel.removeAllRanges(); + sel.addRange(range); + el.scrollLeft = el.scrollWidth; + } + }; + + jSuites.isNumeric = function (num) { + if (typeof num === "string") { + num = num.trim(); + } + return !isNaN(num) && num !== null && num !== ""; + }; + + jSuites.guid = function () { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( + /[xy]/g, + function (c) { + var r = (Math.random() * 16) | 0, + v = c == "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + } + ); + }; + + jSuites.getNode = function () { + var node = document.getSelection().anchorNode; + if (node) { + return node.nodeType == 3 ? node.parentNode : node; + } else { + return null; + } + }; + /** + * Generate hash from a string + */ + jSuites.hash = function (str) { + var hash = 0, + i, + chr; + + if (str.length === 0) { + return hash; + } else { + for (i = 0; i < str.length; i++) { + chr = str.charCodeAt(i); + if (chr > 32) { + hash = (hash << 5) - hash + chr; + hash |= 0; + } + } + } + return hash; + }; + + /** + * Generate a random color + */ + jSuites.randomColor = function (h) { + var lum = -0.25; + var hex = String( + "#" + Math.random().toString(16).slice(2, 8).toUpperCase() + ).replace(/[^0-9a-f]/gi, ""); + if (hex.length < 6) { + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; + } + var rgb = [], + c, + i; + for (i = 0; i < 3; i++) { + c = parseInt(hex.substr(i * 2, 2), 16); + c = Math.round(Math.min(Math.max(0, c + c * lum), 255)).toString(16); + rgb.push(("00" + c).substr(c.length)); + } + + // Return hex + if (h == true) { + return ( + "#" + + jSuites.two(rgb[0].toString(16)) + + jSuites.two(rgb[1].toString(16)) + + jSuites.two(rgb[2].toString(16)) + ); + } + + return rgb; + }; + + jSuites.getWindowWidth = function () { + var w = window, + d = document, + e = d.documentElement, + g = d.getElementsByTagName("body")[0], + x = w.innerWidth || e.clientWidth || g.clientWidth; + return x; + }; + + jSuites.getWindowHeight = function () { + var w = window, + d = document, + e = d.documentElement, + g = d.getElementsByTagName("body")[0], + y = w.innerHeight || e.clientHeight || g.clientHeight; + return y; + }; + + jSuites.getPosition = function (e) { + if (e.changedTouches && e.changedTouches[0]) { + var x = e.changedTouches[0].pageX; + var y = e.changedTouches[0].pageY; + } else { + var x = window.Event + ? e.pageX + : e.clientX + + (document.documentElement.scrollLeft + ? document.documentElement.scrollLeft + : document.body.scrollLeft); + var y = window.Event + ? e.pageY + : e.clientY + + (document.documentElement.scrollTop + ? document.documentElement.scrollTop + : document.body.scrollTop); + } + + return [x, y]; + }; + + jSuites.click = function (el) { + if (el.click) { + el.click(); + } else { + var evt = new MouseEvent("click", { + bubbles: true, + cancelable: true, + view: window, + }); + el.dispatchEvent(evt); + } + }; + + jSuites.findElement = function (element, condition) { + var foundElement = false; + + function path(element) { + if (element && !foundElement) { + if (typeof condition == "function") { + foundElement = condition(element); + } else if (typeof condition == "string") { + if (element.classList && element.classList.contains(condition)) { + foundElement = element; + } + } + } + + if (element.parentNode && !foundElement) { + path(element.parentNode); + } + } + + path(element); + + return foundElement; + }; + + // Two digits + jSuites.two = function (value) { + value = "" + value; + if (value.length == 1) { + value = "0" + value; + } + return value; + }; + + jSuites.sha512 = function (str) { + function int64(msint_32, lsint_32) { + this.highOrder = msint_32; + this.lowOrder = lsint_32; + } + + var H = [ + new int64(0x6a09e667, 0xf3bcc908), + new int64(0xbb67ae85, 0x84caa73b), + new int64(0x3c6ef372, 0xfe94f82b), + new int64(0xa54ff53a, 0x5f1d36f1), + new int64(0x510e527f, 0xade682d1), + new int64(0x9b05688c, 0x2b3e6c1f), + new int64(0x1f83d9ab, 0xfb41bd6b), + new int64(0x5be0cd19, 0x137e2179), + ]; + + var K = [ + new int64(0x428a2f98, 0xd728ae22), + new int64(0x71374491, 0x23ef65cd), + new int64(0xb5c0fbcf, 0xec4d3b2f), + new int64(0xe9b5dba5, 0x8189dbbc), + new int64(0x3956c25b, 0xf348b538), + new int64(0x59f111f1, 0xb605d019), + new int64(0x923f82a4, 0xaf194f9b), + new int64(0xab1c5ed5, 0xda6d8118), + new int64(0xd807aa98, 0xa3030242), + new int64(0x12835b01, 0x45706fbe), + new int64(0x243185be, 0x4ee4b28c), + new int64(0x550c7dc3, 0xd5ffb4e2), + new int64(0x72be5d74, 0xf27b896f), + new int64(0x80deb1fe, 0x3b1696b1), + new int64(0x9bdc06a7, 0x25c71235), + new int64(0xc19bf174, 0xcf692694), + new int64(0xe49b69c1, 0x9ef14ad2), + new int64(0xefbe4786, 0x384f25e3), + new int64(0x0fc19dc6, 0x8b8cd5b5), + new int64(0x240ca1cc, 0x77ac9c65), + new int64(0x2de92c6f, 0x592b0275), + new int64(0x4a7484aa, 0x6ea6e483), + new int64(0x5cb0a9dc, 0xbd41fbd4), + new int64(0x76f988da, 0x831153b5), + new int64(0x983e5152, 0xee66dfab), + new int64(0xa831c66d, 0x2db43210), + new int64(0xb00327c8, 0x98fb213f), + new int64(0xbf597fc7, 0xbeef0ee4), + new int64(0xc6e00bf3, 0x3da88fc2), + new int64(0xd5a79147, 0x930aa725), + new int64(0x06ca6351, 0xe003826f), + new int64(0x14292967, 0x0a0e6e70), + new int64(0x27b70a85, 0x46d22ffc), + new int64(0x2e1b2138, 0x5c26c926), + new int64(0x4d2c6dfc, 0x5ac42aed), + new int64(0x53380d13, 0x9d95b3df), + new int64(0x650a7354, 0x8baf63de), + new int64(0x766a0abb, 0x3c77b2a8), + new int64(0x81c2c92e, 0x47edaee6), + new int64(0x92722c85, 0x1482353b), + new int64(0xa2bfe8a1, 0x4cf10364), + new int64(0xa81a664b, 0xbc423001), + new int64(0xc24b8b70, 0xd0f89791), + new int64(0xc76c51a3, 0x0654be30), + new int64(0xd192e819, 0xd6ef5218), + new int64(0xd6990624, 0x5565a910), + new int64(0xf40e3585, 0x5771202a), + new int64(0x106aa070, 0x32bbd1b8), + new int64(0x19a4c116, 0xb8d2d0c8), + new int64(0x1e376c08, 0x5141ab53), + new int64(0x2748774c, 0xdf8eeb99), + new int64(0x34b0bcb5, 0xe19b48a8), + new int64(0x391c0cb3, 0xc5c95a63), + new int64(0x4ed8aa4a, 0xe3418acb), + new int64(0x5b9cca4f, 0x7763e373), + new int64(0x682e6ff3, 0xd6b2b8a3), + new int64(0x748f82ee, 0x5defb2fc), + new int64(0x78a5636f, 0x43172f60), + new int64(0x84c87814, 0xa1f0ab72), + new int64(0x8cc70208, 0x1a6439ec), + new int64(0x90befffa, 0x23631e28), + new int64(0xa4506ceb, 0xde82bde9), + new int64(0xbef9a3f7, 0xb2c67915), + new int64(0xc67178f2, 0xe372532b), + new int64(0xca273ece, 0xea26619c), + new int64(0xd186b8c7, 0x21c0c207), + new int64(0xeada7dd6, 0xcde0eb1e), + new int64(0xf57d4f7f, 0xee6ed178), + new int64(0x06f067aa, 0x72176fba), + new int64(0x0a637dc5, 0xa2c898a6), + new int64(0x113f9804, 0xbef90dae), + new int64(0x1b710b35, 0x131c471b), + new int64(0x28db77f5, 0x23047d84), + new int64(0x32caab7b, 0x40c72493), + new int64(0x3c9ebe0a, 0x15c9bebc), + new int64(0x431d67c4, 0x9c100d4c), + new int64(0x4cc5d4be, 0xcb3e42b6), + new int64(0x597f299c, 0xfc657e2a), + new int64(0x5fcb6fab, 0x3ad6faec), + new int64(0x6c44198c, 0x4a475817), + ]; + + var W = new Array(64); + var a, b, c, d, e, f, g, h, i, j; + var T1, T2; + var charsize = 8; + + function utf8_encode(str) { + return unescape(encodeURIComponent(str)); + } + + function str2binb(str) { + var bin = []; + var mask = (1 << charsize) - 1; + var len = str.length * charsize; + + for (var i = 0; i < len; i += charsize) { + bin[i >> 5] |= + (str.charCodeAt(i / charsize) & mask) << (32 - charsize - (i % 32)); + } + + return bin; + } + + function binb2hex(binarray) { + var hex_tab = "0123456789abcdef"; + var str = ""; + var length = binarray.length * 4; + var srcByte; + + for (var i = 0; i < length; i += 1) { + srcByte = binarray[i >> 2] >> ((3 - (i % 4)) * 8); + str += + hex_tab.charAt((srcByte >> 4) & 0xf) + hex_tab.charAt(srcByte & 0xf); + } + + return str; + } + + function safe_add_2(x, y) { + var lsw, msw, lowOrder, highOrder; + + lsw = (x.lowOrder & 0xffff) + (y.lowOrder & 0xffff); + msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16); + lowOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); + + lsw = (x.highOrder & 0xffff) + (y.highOrder & 0xffff) + (msw >>> 16); + msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16); + highOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); + + return new int64(highOrder, lowOrder); + } + + function safe_add_4(a, b, c, d) { + var lsw, msw, lowOrder, highOrder; + + lsw = + (a.lowOrder & 0xffff) + + (b.lowOrder & 0xffff) + + (c.lowOrder & 0xffff) + + (d.lowOrder & 0xffff); + msw = + (a.lowOrder >>> 16) + + (b.lowOrder >>> 16) + + (c.lowOrder >>> 16) + + (d.lowOrder >>> 16) + + (lsw >>> 16); + lowOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); + + lsw = + (a.highOrder & 0xffff) + + (b.highOrder & 0xffff) + + (c.highOrder & 0xffff) + + (d.highOrder & 0xffff) + + (msw >>> 16); + msw = + (a.highOrder >>> 16) + + (b.highOrder >>> 16) + + (c.highOrder >>> 16) + + (d.highOrder >>> 16) + + (lsw >>> 16); + highOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); + + return new int64(highOrder, lowOrder); + } + + function safe_add_5(a, b, c, d, e) { + var lsw, msw, lowOrder, highOrder; + + lsw = + (a.lowOrder & 0xffff) + + (b.lowOrder & 0xffff) + + (c.lowOrder & 0xffff) + + (d.lowOrder & 0xffff) + + (e.lowOrder & 0xffff); + msw = + (a.lowOrder >>> 16) + + (b.lowOrder >>> 16) + + (c.lowOrder >>> 16) + + (d.lowOrder >>> 16) + + (e.lowOrder >>> 16) + + (lsw >>> 16); + lowOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); + + lsw = + (a.highOrder & 0xffff) + + (b.highOrder & 0xffff) + + (c.highOrder & 0xffff) + + (d.highOrder & 0xffff) + + (e.highOrder & 0xffff) + + (msw >>> 16); + msw = + (a.highOrder >>> 16) + + (b.highOrder >>> 16) + + (c.highOrder >>> 16) + + (d.highOrder >>> 16) + + (e.highOrder >>> 16) + + (lsw >>> 16); + highOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); + + return new int64(highOrder, lowOrder); + } + + function maj(x, y, z) { + return new int64( + (x.highOrder & y.highOrder) ^ + (x.highOrder & z.highOrder) ^ + (y.highOrder & z.highOrder), + (x.lowOrder & y.lowOrder) ^ + (x.lowOrder & z.lowOrder) ^ + (y.lowOrder & z.lowOrder) + ); + } + + function ch(x, y, z) { + return new int64( + (x.highOrder & y.highOrder) ^ (~x.highOrder & z.highOrder), + (x.lowOrder & y.lowOrder) ^ (~x.lowOrder & z.lowOrder) + ); + } + + function rotr(x, n) { + if (n <= 32) { + return new int64( + (x.highOrder >>> n) | (x.lowOrder << (32 - n)), + (x.lowOrder >>> n) | (x.highOrder << (32 - n)) + ); + } else { + return new int64( + (x.lowOrder >>> n) | (x.highOrder << (32 - n)), + (x.highOrder >>> n) | (x.lowOrder << (32 - n)) + ); + } + } + + function sigma0(x) { + var rotr28 = rotr(x, 28); + var rotr34 = rotr(x, 34); + var rotr39 = rotr(x, 39); + + return new int64( + rotr28.highOrder ^ rotr34.highOrder ^ rotr39.highOrder, + rotr28.lowOrder ^ rotr34.lowOrder ^ rotr39.lowOrder + ); + } + + function sigma1(x) { + var rotr14 = rotr(x, 14); + var rotr18 = rotr(x, 18); + var rotr41 = rotr(x, 41); + + return new int64( + rotr14.highOrder ^ rotr18.highOrder ^ rotr41.highOrder, + rotr14.lowOrder ^ rotr18.lowOrder ^ rotr41.lowOrder + ); + } + + function gamma0(x) { + var rotr1 = rotr(x, 1), + rotr8 = rotr(x, 8), + shr7 = shr(x, 7); + + return new int64( + rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder, + rotr1.lowOrder ^ rotr8.lowOrder ^ shr7.lowOrder + ); + } + + function gamma1(x) { + var rotr19 = rotr(x, 19); + var rotr61 = rotr(x, 61); + var shr6 = shr(x, 6); + + return new int64( + rotr19.highOrder ^ rotr61.highOrder ^ shr6.highOrder, + rotr19.lowOrder ^ rotr61.lowOrder ^ shr6.lowOrder + ); + } + + function shr(x, n) { + if (n <= 32) { + return new int64( + x.highOrder >>> n, + (x.lowOrder >>> n) | (x.highOrder << (32 - n)) + ); + } else { + return new int64(0, x.highOrder << (32 - n)); + } + } + + var str = utf8_encode(str); + var strlen = str.length * charsize; + str = str2binb(str); + + str[strlen >> 5] |= 0x80 << (24 - (strlen % 32)); + str[(((strlen + 128) >> 10) << 5) + 31] = strlen; + + for (var i = 0; i < str.length; i += 32) { + a = H[0]; + b = H[1]; + c = H[2]; + d = H[3]; + e = H[4]; + f = H[5]; + g = H[6]; + h = H[7]; + + for (var j = 0; j < 80; j++) { + if (j < 16) { + W[j] = new int64(str[j * 2 + i], str[j * 2 + i + 1]); + } else { + W[j] = safe_add_4( + gamma1(W[j - 2]), + W[j - 7], + gamma0(W[j - 15]), + W[j - 16] + ); + } + + T1 = safe_add_5(h, sigma1(e), ch(e, f, g), K[j], W[j]); + T2 = safe_add_2(sigma0(a), maj(a, b, c)); + h = g; + g = f; + f = e; + e = safe_add_2(d, T1); + d = c; + c = b; + b = a; + a = safe_add_2(T1, T2); + } + + H[0] = safe_add_2(a, H[0]); + H[1] = safe_add_2(b, H[1]); + H[2] = safe_add_2(c, H[2]); + H[3] = safe_add_2(d, H[3]); + H[4] = safe_add_2(e, H[4]); + H[5] = safe_add_2(f, H[5]); + H[6] = safe_add_2(g, H[6]); + H[7] = safe_add_2(h, H[7]); + } + + var binarray = []; + for (var i = 0; i < H.length; i++) { + binarray.push(H[i].highOrder); + binarray.push(H[i].lowOrder); + } + + return binb2hex(binarray); + }; + + if (!jSuites.login) { + jSuites.login = {}; + jSuites.login.sha512 = jSuites.sha512; + } + + jSuites.image = jSuites.upload = function (el, options) { + var obj = {}; + obj.options = {}; + + // Default configuration + var defaults = { + type: "image", + extension: "*", + input: false, + minWidth: false, + maxWidth: null, + maxHeight: null, + maxJpegSizeBytes: null, // For example, 350Kb would be 350000 + onchange: null, + multiple: false, + remoteParser: null, + text: { + extensionNotAllowed: "The extension is not allowed", + }, + }; + + // Loop through our object + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + obj.options[property] = defaults[property]; + } + } + + // Multiple + if (obj.options.multiple == true) { + el.setAttribute("data-multiple", true); + } + + // Container + el.content = []; + + // Upload icon + el.classList.add("jupload"); + + if (obj.options.input == true) { + el.classList.add("input"); + } + + obj.add = function (data) { + // Reset container for single files + if (obj.options.multiple == false) { + el.content = []; + el.innerText = ""; + } + + // Append to the element + if (obj.options.type == "image") { + var img = document.createElement("img"); + img.setAttribute("src", data.file); + img.setAttribute("tabindex", -1); + if (!el.getAttribute("name")) { + img.className = "jfile"; + img.content = data; + } + el.appendChild(img); + } else { + if (data.name) { + var name = data.name; + } else { + var name = data.file; + } + var div = document.createElement("div"); + div.innerText = name || obj.options.type; + div.classList.add("jupload-item"); + div.setAttribute("tabindex", -1); + el.appendChild(div); + } + + if (data.content) { + data.file = jSuites.guid(); + } + + // Push content + el.content.push(data); + + // Onchange + if (typeof obj.options.onchange == "function") { + obj.options.onchange(el, data); + } + }; + + obj.addFromFile = function (file) { + var type = file.type.split("/"); + if (type[0] == obj.options.type) { + var readFile = new FileReader(); + readFile.addEventListener("load", function (v) { + var data = { + file: v.srcElement.result, + extension: file.name.substr(file.name.lastIndexOf(".") + 1), + name: file.name, + size: file.size, + lastmodified: file.lastModified, + content: v.srcElement.result, + }; + + obj.add(data); + }); + + readFile.readAsDataURL(file); + } else { + alert(obj.options.text.extensionNotAllowed); + } + }; + + obj.addFromUrl = function (src) { + if (src.substr(0, 4) != "data" && !obj.options.remoteParser) { + console.error("remoteParser not defined in your initialization"); + } else { + // This is to process cross domain images + if (src.substr(0, 4) == "data") { + var extension = src.split(";"); + extension = extension[0].split("/"); + var type = extension[0].replace("data:", ""); + if (type == obj.options.type) { + var data = { + file: src, + name: "", + extension: extension[1], + content: src, + }; + obj.add(data); + } else { + alert(obj.options.text.extensionNotAllowed); + } + } else { + var extension = src.substr(src.lastIndexOf(".") + 1); + // Work for cross browsers + src = obj.options.remoteParser + src; + // Get remove content + jSuites.ajax({ + url: src, + type: "GET", + dataType: "blob", + success: function (data) { + //add(extension[0].replace('data:',''), data); + }, + }); + } + } + }; + + var getDataURL = function (canvas, type) { + var compression = 0.92; + var lastContentLength = null; + var content = canvas.toDataURL(type, compression); + while ( + obj.options.maxJpegSizeBytes && + type === "image/jpeg" && + content.length > obj.options.maxJpegSizeBytes && + content.length !== lastContentLength + ) { + // Apply the compression + compression *= 0.9; + lastContentLength = content.length; + content = canvas.toDataURL(type, compression); + } + return content; + }; + + var mime = obj.options.type + "/" + obj.options.extension; + var input = document.createElement("input"); + input.type = "file"; + input.setAttribute("accept", mime); + input.onchange = function () { + for (var i = 0; i < this.files.length; i++) { + obj.addFromFile(this.files[i]); + } + }; + + // Allow multiple files + if (obj.options.multiple == true) { + input.setAttribute("multiple", true); + } + + var current = null; + + el.addEventListener("click", function (e) { + current = null; + if (!el.children.length || e.target === el) { + jSuites.click(input); + } else { + if (e.target.parentNode == el) { + current = e.target; + } + } + }); + + el.addEventListener("dblclick", function (e) { + jSuites.click(input); + }); + + el.addEventListener("dragenter", function (e) { + el.style.border = "1px dashed #000"; + }); + + el.addEventListener("dragleave", function (e) { + el.style.border = "1px solid #eee"; + }); + + el.addEventListener("dragstop", function (e) { + el.style.border = "1px solid #eee"; + }); + + el.addEventListener("dragover", function (e) { + e.preventDefault(); + }); + + el.addEventListener("keydown", function (e) { + if (current && e.which == 46) { + var index = Array.prototype.indexOf.call(el.children, current); + if (index >= 0) { + el.content.splice(index, 1); + current.remove(); + current = null; + } + } + }); + + el.addEventListener("drop", function (e) { + e.preventDefault(); + e.stopPropagation(); + + var html = (e.originalEvent || e).dataTransfer.getData("text/html"); + var file = (e.originalEvent || e).dataTransfer.files; + + if (file.length) { + for (var i = 0; i < e.dataTransfer.files.length; i++) { + obj.addFromFile(e.dataTransfer.files[i]); + } + } else if (html) { + if (obj.options.multiple == false) { + el.innerText = ""; + } + + // Create temp element + var div = document.createElement("div"); + div.innerHTML = html; + + // Extract images + var img = div.querySelectorAll("img"); + + if (img.length) { + for (var i = 0; i < img.length; i++) { + obj.addFromUrl(img[i].src); + } + } + } + + el.style.border = "1px solid #eee"; + + return false; + }); + + el.val = function (val) { + if (val === undefined) { + return el.content && el.content.length ? el.content : null; + } else { + // Reset + el.innerText = ""; + el.content = []; + + if (val) { + if (Array.isArray(val)) { + for (var i = 0; i < val.length; i++) { + if (typeof val[i] == "string") { + obj.add({ file: val[i] }); + } else { + obj.add(val[i]); + } + } + } else if (typeof val == "string") { + obj.add({ file: val }); + } + } + } + }; + + el.upload = el.image = obj; + + return obj; + }; + + jSuites.image.create = function (data) { + var img = document.createElement("img"); + img.setAttribute("src", data.file); + img.className = "jfile"; + img.setAttribute("tabindex", -1); + img.content = data; + + return img; + }; + + jSuites.lazyLoading = function (el, options) { + var obj = {}; + + // Mandatory options + if (!options.loadUp || typeof options.loadUp != "function") { + options.loadUp = function () { + return false; + }; + } + if (!options.loadDown || typeof options.loadDown != "function") { + options.loadDown = function () { + return false; + }; + } + // Timer ms + if (!options.timer) { + options.timer = 100; + } + + // Timer + var timeControlLoading = null; + + // Controls + var scrollControls = function (e) { + if (timeControlLoading == null) { + var event = false; + var scrollTop = el.scrollTop; + if (el.scrollTop + el.clientHeight * 2 >= el.scrollHeight) { + if (options.loadDown()) { + if (scrollTop == el.scrollTop) { + el.scrollTop = el.scrollTop - el.clientHeight; + } + event = true; + } + } else if (el.scrollTop <= el.clientHeight) { + if (options.loadUp()) { + if (scrollTop == el.scrollTop) { + el.scrollTop = el.scrollTop + el.clientHeight; + } + event = true; + } + } + + timeControlLoading = setTimeout(function () { + timeControlLoading = null; + }, options.timer); + + if (event) { + if (typeof options.onupdate == "function") { + options.onupdate(); + } + } + } + }; + + // Onscroll + el.onscroll = function (e) { + scrollControls(e); + }; + + el.onwheel = function (e) { + scrollControls(e); + }; + + return obj; + }; + + jSuites.loading = (function () { + var obj = {}; + + var loading = null; + + obj.show = function () { + if (!loading) { + loading = document.createElement("div"); + loading.className = "jloading"; + } + document.body.appendChild(loading); + }; + + obj.hide = function () { + if (loading && loading.parentNode) { + document.body.removeChild(loading); + } + }; + + return obj; + })(); + + jSuites.mask = (function () { + // Currency + var tokens = { + // Text + text: ["@"], + // Currency tokens + currency: ["#(.{1})##0?(.{1}0+)?( ?;(.*)?)?", "#"], + // Percentage + percentage: ["0{1}(.{1}0+)?%"], + // Number + numeric: ["0{1}(.{1}0+)?"], + // Data tokens + datetime: [ + "YYYY", + "YYY", + "YY", + "MMMMM", + "MMMM", + "MMM", + "MM", + "DDDDD", + "DDDD", + "DDD", + "DD", + "DY", + "DAY", + "WD", + "D", + "Q", + "HH24", + "HH12", + "HH", + "\\[H\\]", + "H", + "AM/PM", + "PM", + "AM", + "MI", + "SS", + "MS", + "MONTH", + "MON", + "Y", + "M", + ], + // Other + general: ["A", "0", "[0-9a-zA-Z$]+", "."], + }; + + var getDate = function () { + if (this.mask.toLowerCase().indexOf("[h]") !== -1) { + var m = 0; + if (this.date[4]) { + m = parseFloat(this.date[4] / 60); + } + var v = parseInt(this.date[3]) + m; + v /= 24; + } else if ( + !(this.date[0] && this.date[1] && this.date[2]) && + (this.date[3] || this.date[4]) + ) { + v = + jSuites.two(this.date[3]) + + ":" + + jSuites.two(this.date[4]) + + ":" + + jSuites.two(this.date[5]); + } else { + if (this.date[0] && this.date[1] && !this.date[2]) { + this.date[2] = 1; + } + v = + jSuites.two(this.date[0]) + + "-" + + jSuites.two(this.date[1]) + + "-" + + jSuites.two(this.date[2]); + + if (this.date[3] || this.date[4] || this.date[5]) { + v += + " " + + jSuites.two(this.date[3]) + + ":" + + jSuites.two(this.date[4]) + + ":" + + jSuites.two(this.date[5]); + } + } + + return v; + }; + + var isBlank = function (v) { + return v === null || v === "" || v === undefined ? true : false; + }; + + var isFormula = function (value) { + return ("" + value).chartAt(0) == "="; + }; + + var isNumeric = function (t) { + return t === "currency" || t === "percentage" || t === "numeric" + ? true + : false; + }; + /** + * Get the decimal defined in the mask configuration + */ + var getDecimal = function (v) { + if (v && Number(v) == v) { + return "."; + } else { + if (this.options.decimal) { + return this.options.decimal; + } else { + if (this.locale) { + var t = Intl.NumberFormat(this.locale).format(1.1); + return (this.options.decimal = t[1]); + } else { + if (!v) { + v = this.mask; + } + var e = new RegExp("0{1}(.{1})0+", "ig"); + var t = e.exec(v); + if (t && t[1] && t[1].length == 1) { + // Save decimal + this.options.decimal = t[1]; + // Return decimal + return t[1]; + } else { + // Did not find any decimal last resort the default + var e = new RegExp("#{1}(.{1})#+", "ig"); + var t = e.exec(v); + if (t && t[1] && t[1].length == 1) { + if (t[1] === ",") { + this.options.decimal = "."; + } else { + this.options.decimal = ","; + } + } else { + this.options.decimal = "1.1".toLocaleString().substring(1, 2); + } + } + } + } + } + + if (this.options.decimal) { + return this.options.decimal; + } else { + return null; + } + }; + + var ParseValue = function (v, decimal) { + if (v == "") { + return ""; + } + + // Get decimal + if (!decimal) { + decimal = getDecimal.call(this); + } + + // New value + v = ("" + v).split(decimal); + + // Signal + var signal = v[0].match(/[-]+/g); + if (signal && signal.length) { + signal = true; + } else { + signal = false; + } + + v[0] = v[0].match(/[0-9]+/g); + + if (v[0]) { + if (signal) { + v[0].unshift("-"); + } + v[0] = v[0].join(""); + } else { + if (signal) { + v[0] = "-"; + } + } + + if (v[0] || v[1]) { + if (v[1] !== undefined) { + v[1] = v[1].match(/[0-9]+/g); + if (v[1]) { + v[1] = v[1].join(""); + } else { + v[1] = ""; + } + } + } else { + return ""; + } + return v; + }; + + var FormatValue = function (v, event) { + if (v == "") { + return ""; + } + // Get decimal + var d = getDecimal.call(this); + // Convert value + var o = this.options; + // Parse value + v = ParseValue.call(this, v); + if (v == "") { + return ""; + } + // Temporary value + if (v[0]) { + var t = parseFloat(v[0] + ".1"); + if (o.style == "percent") { + t /= 100; + } + } else { + var t = null; + } + + if ( + (v[0] == "-" || v[0] == "-00") && + !v[1] && + event && + event.inputType == "deleteContentBackward" + ) { + return ""; + } + + var n = new Intl.NumberFormat(this.locale, o).format(t); + n = n.split(d); + if (typeof n[1] !== "undefined") { + var s = n[1].replace(/[0-9]*/g, ""); + if (s) { + n[2] = s; + } + } + + if (v[1] !== undefined) { + n[1] = d + v[1]; + } else { + n[1] = ""; + } + + return n.join(""); + }; + + var Format = function (e, event) { + var v = Value.call(e); + if (!v) { + return; + } + + // Get decimal + var d = getDecimal.call(this); + var n = FormatValue.call(this, v, event); + var t = n.length - v.length; + var index = Caret.call(e) + t; + // Set value and update caret + Value.call(e, n, index, true); + }; + + var Extract = function (v) { + // Keep the raw value + var current = ParseValue.call(this, v); + if (current) { + // Negative values + if (current[0] === "-") { + current[0] = "-0"; + } + return parseFloat(current.join(".")); + } + return null; + }; + + /** + * Caret getter and setter methods + */ + var Caret = function (index, adjustNumeric) { + if (index === undefined) { + if (this.tagName == "DIV") { + var pos = 0; + var s = window.getSelection(); + if (s) { + if (s.rangeCount !== 0) { + var r = s.getRangeAt(0); + var p = r.cloneRange(); + p.selectNodeContents(this); + p.setEnd(r.endContainer, r.endOffset); + pos = p.toString().length; + } + } + return pos; + } else { + return this.selectionStart; + } + } else { + // Get the current value + var n = Value.call(this); + + // Review the position + if (adjustNumeric) { + var p = null; + for (var i = 0; i < n.length; i++) { + if (n[i].match(/[\-0-9]/g) || n[i] == "." || n[i] == ",") { + p = i; + } + } + + // If the string has no numbers + if (p === null) { + p = n.indexOf(" "); + } + + if (index >= p) { + index = p + 1; + } + } + + // Do not update caret + if (index > n.length) { + index = n.length; + } + + if (index) { + // Set caret + if (this.tagName == "DIV") { + var s = window.getSelection(); + var r = document.createRange(); + + if (this.childNodes[0]) { + r.setStart(this.childNodes[0], index); + s.removeAllRanges(); + s.addRange(r); + } + } else { + this.selectionStart = index; + this.selectionEnd = index; + } + } + } + }; + + /** + * Value getter and setter method + */ + var Value = function (v, updateCaret, adjustNumeric) { + if (this.tagName == "DIV") { + if (v === undefined) { + var v = this.innerText; + if (this.value && this.value.length > v.length) { + v = this.value; + } + return v; + } else { + if (this.innerText !== v) { + this.innerText = v; + + if (updateCaret) { + Caret.call(this, updateCaret, adjustNumeric); + } + } + } + } else { + if (v === undefined) { + return this.value; + } else { + if (this.value !== v) { + this.value = v; + if (updateCaret) { + Caret.call(this, updateCaret, adjustNumeric); + } + } + } + } + }; + + // Labels + var weekDaysFull = jSuites.calendar.weekdays; + var weekDays = jSuites.calendar.weekdaysShort; + var monthsFull = jSuites.calendar.months; + var months = jSuites.calendar.monthsShort; + + var parser = { + YEAR: function (v, s) { + var y = "" + new Date().getFullYear(); + + if (typeof this.values[this.index] === "undefined") { + this.values[this.index] = ""; + } + if (parseInt(v) >= 0 && parseInt(v) <= 10) { + if (this.values[this.index].length < s) { + this.values[this.index] += v; + } + } + if (this.values[this.index].length == s) { + if (s == 2) { + var y = y.substr(0, 2) + this.values[this.index]; + } else if (s == 3) { + var y = y.substr(0, 1) + this.values[this.index]; + } else if (s == 4) { + var y = this.values[this.index]; + } + this.date[0] = y; + this.index++; + } + }, + YYYY: function (v) { + parser.YEAR.call(this, v, 4); + }, + YYY: function (v) { + parser.YEAR.call(this, v, 3); + }, + YY: function (v) { + parser.YEAR.call(this, v, 2); + }, + FIND: function (v, a) { + if (isBlank(this.values[this.index])) { + this.values[this.index] = ""; + } + var pos = 0; + var count = 0; + var value = (this.values[this.index] + v).toLowerCase(); + for (var i = 0; i < a.length; i++) { + if (a[i].toLowerCase().indexOf(value) == 0) { + pos = i; + count++; + } + } + if (count > 1) { + this.values[this.index] += v; + } else if (count == 1) { + // Jump number of chars + var t = a[pos].length - this.values[this.index].length - 1; + this.position += t; + + this.values[this.index] = a[pos]; + this.index++; + return pos; + } + }, + MMM: function (v) { + var ret = parser.FIND.call(this, v, months); + if (ret !== undefined) { + this.date[1] = ret + 1; + } + }, + MMMM: function (v) { + var ret = parser.FIND.call(this, v, monthsFull); + if (ret !== undefined) { + this.date[1] = ret + 1; + } + }, + MMMMM: function (v) { + if (isBlank(this.values[this.index])) { + this.values[this.index] = ""; + } + var pos = 0; + var count = 0; + var value = (this.values[this.index] + v).toLowerCase(); + for (var i = 0; i < monthsFull.length; i++) { + if (monthsFull[i][0].toLowerCase().indexOf(value) == 0) { + this.values[this.index] = monthsFull[i][0]; + this.date[1] = i + 1; + this.index++; + break; + } + } + }, + MM: function (v) { + if (isBlank(this.values[this.index])) { + if (parseInt(v) > 1 && parseInt(v) < 10) { + this.date[1] = this.values[this.index] = "0" + v; + this.index++; + } else if (parseInt(v) < 2) { + this.values[this.index] = v; + } + } else { + if (this.values[this.index] == 1 && parseInt(v) < 3) { + this.date[1] = this.values[this.index] += v; + this.index++; + } else if ( + this.values[this.index] == 0 && + parseInt(v) > 0 && + parseInt(v) < 10 + ) { + this.date[1] = this.values[this.index] += v; + this.index++; + } + } + }, + M: function (v) { + var test = false; + if (parseInt(v) >= 0 && parseInt(v) < 10) { + if (isBlank(this.values[this.index])) { + this.values[this.index] = v; + if (v > 1) { + this.date[1] = this.values[this.index]; + this.index++; + } + } else { + if (this.values[this.index] == 1 && parseInt(v) < 3) { + this.date[1] = this.values[this.index] += v; + this.index++; + } else if (this.values[this.index] == 0 && parseInt(v) > 0) { + this.date[1] = this.values[this.index] += v; + this.index++; + } else { + var test = true; + } + } + } else { + var test = true; + } + + // Re-test + if (test == true) { + var t = parseInt(this.values[this.index]); + if (t > 0 && t < 12) { + this.date[2] = this.values[this.index]; + this.index++; + // Repeat the character + this.position--; + } + } + }, + D: function (v) { + var test = false; + if (parseInt(v) >= 0 && parseInt(v) < 10) { + if (isBlank(this.values[this.index])) { + this.values[this.index] = v; + if (parseInt(v) > 3) { + this.date[2] = this.values[this.index]; + this.index++; + } + } else { + if (this.values[this.index] == 3 && parseInt(v) < 2) { + this.date[2] = this.values[this.index] += v; + this.index++; + } else if ( + this.values[this.index] == 1 || + this.values[this.index] == 2 + ) { + this.date[2] = this.values[this.index] += v; + this.index++; + } else if (this.values[this.index] == 0 && parseInt(v) > 0) { + this.date[2] = this.values[this.index] += v; + this.index++; + } else { + var test = true; + } + } + } else { + var test = true; + } + + // Re-test + if (test == true) { + var t = parseInt(this.values[this.index]); + if (t > 0 && t < 32) { + this.date[2] = this.values[this.index]; + this.index++; + // Repeat the character + this.position--; + } + } + }, + DD: function (v) { + if (isBlank(this.values[this.index])) { + if (parseInt(v) > 3 && parseInt(v) < 10) { + this.date[2] = this.values[this.index] = "0" + v; + this.index++; + } else if (parseInt(v) < 10) { + this.values[this.index] = v; + } + } else { + if (this.values[this.index] == 3 && parseInt(v) < 2) { + this.date[2] = this.values[this.index] += v; + this.index++; + } else if ( + (this.values[this.index] == 1 || this.values[this.index] == 2) && + parseInt(v) < 10 + ) { + this.date[2] = this.values[this.index] += v; + this.index++; + } else if ( + this.values[this.index] == 0 && + parseInt(v) > 0 && + parseInt(v) < 10 + ) { + this.date[2] = this.values[this.index] += v; + this.index++; + } + } + }, + DDD: function (v) { + parser.FIND.call(this, v, weekDays); + }, + DDDD: function (v) { + parser.FIND.call(this, v, weekDaysFull); + }, + HH12: function (v, two) { + if (isBlank(this.values[this.index])) { + if (parseInt(v) > 1 && parseInt(v) < 10) { + if (two) { + v = 0 + v; + } + this.date[3] = this.values[this.index] = v; + this.index++; + } else if (parseInt(v) < 10) { + this.values[this.index] = v; + } + } else { + if (this.values[this.index] == 1 && parseInt(v) < 3) { + this.date[3] = this.values[this.index] += v; + this.index++; + } else if (this.values[this.index] < 1 && parseInt(v) < 10) { + this.date[3] = this.values[this.index] += v; + this.index++; + } + } + }, + HH24: function (v, two) { + var test = false; + if (parseInt(v) >= 0 && parseInt(v) < 10) { + if ( + this.values[this.index] == null || + this.values[this.index] == "" + ) { + if (parseInt(v) > 2 && parseInt(v) < 10) { + if (two) { + v = 0 + v; + } + this.date[3] = this.values[this.index] = v; + this.index++; + } else if (parseInt(v) < 10) { + this.values[this.index] = v; + } + } else { + if (this.values[this.index] == 2 && parseInt(v) < 4) { + this.date[3] = this.values[this.index] += v; + this.index++; + } else if (this.values[this.index] < 2 && parseInt(v) < 10) { + this.date[3] = this.values[this.index] += v; + this.index++; + } + } + } + }, + HH: function (v) { + parser["HH24"].call(this, v, 1); + }, + H: function (v) { + parser["HH24"].call(this, v, 0); + }, + "\\[H\\]": function (v) { + if (this.values[this.index] == undefined) { + this.values[this.index] = ""; + } + if (v.match(/[0-9]/g)) { + this.date[3] = this.values[this.index] += v; + } else { + if (this.values[this.index].match(/[0-9]/g)) { + this.date[3] = this.values[this.index]; + this.index++; + // Repeat the character + this.position--; + } + } + }, + N60: function (v, i) { + if (this.values[this.index] == null || this.values[this.index] == "") { + if (parseInt(v) > 5 && parseInt(v) < 10) { + this.date[i] = this.values[this.index] = "0" + v; + this.index++; + } else if (parseInt(v) < 10) { + this.values[this.index] = v; + } + } else { + if (parseInt(v) < 10) { + this.date[i] = this.values[this.index] += v; + this.index++; + } + } + }, + MI: function (v) { + parser.N60.call(this, v, 4); + }, + SS: function (v) { + parser.N60.call(this, v, 5); + }, + "AM/PM": function (v) { + this.values[this.index] = ""; + if (v) { + if (this.date[3] > 12) { + this.values[this.index] = "PM"; + } else { + this.values[this.index] = "AM"; + } + } + this.index++; + }, + WD: function (v) { + if (typeof this.values[this.index] === "undefined") { + this.values[this.index] = ""; + } + if (parseInt(v) >= 0 && parseInt(v) < 7) { + this.values[this.index] = v; + } + if (this.value[this.index].length == 1) { + this.index++; + } + }, + "0{1}(.{1}0+)?": function (v) { + // Get decimal + var decimal = getDecimal.call(this); + // Negative number + var neg = false; + // Create if is blank + if (isBlank(this.values[this.index])) { + this.values[this.index] = ""; + } else { + if (this.values[this.index] == "-") { + neg = true; + } + } + var current = ParseValue.call(this, this.values[this.index], decimal); + if (current) { + this.values[this.index] = current.join(decimal); + } + // New entry + if (parseInt(v) >= 0 && parseInt(v) < 10) { + // Replace the zero for a number + if (this.values[this.index] == "0" && v > 0) { + this.values[this.index] = ""; + } else if (this.values[this.index] == "-0" && v > 0) { + this.values[this.index] = "-"; + } + // Don't add up zeros because does not mean anything here + if ( + (this.values[this.index] != "0" && + this.values[this.index] != "-0") || + v == decimal + ) { + this.values[this.index] += v; + } + } else if (decimal && v == decimal) { + if (this.values[this.index].indexOf(decimal) == -1) { + if (!this.values[this.index]) { + this.values[this.index] = "0"; + } + this.values[this.index] += v; + } + } else if (v == "-") { + // Negative signed + neg = true; + } + + if (neg === true && this.values[this.index][0] !== "-") { + this.values[this.index] = "-" + this.values[this.index]; + } + }, + "0{1}(.{1}0+)?%": function (v) { + parser["0{1}(.{1}0+)?"].call(this, v); + + if (this.values[this.index].match(/[\-0-9]/g)) { + if ( + this.values[this.index] && + this.values[this.index].indexOf("%") == -1 + ) { + this.values[this.index] += "%"; + } + } else { + this.values[this.index] = ""; + } + }, + "#(.{1})##0?(.{1}0+)?( ?;(.*)?)?": function (v) { + // Parse number + parser["0{1}(.{1}0+)?"].call(this, v); + // Get decimal + var decimal = getDecimal.call(this); + // Get separator + var separator = this.tokens[this.index].substr(1, 1); + // Negative + var negative = this.values[this.index][0] === "-" ? true : false; + // Current value + var current = ParseValue.call(this, this.values[this.index], decimal); + + // Get main and decimal parts + if (current !== "") { + // Format number + var n = current[0].match(/[0-9]/g); + if (n) { + // Format + n = n.join(""); + var t = []; + var s = 0; + for (var j = n.length - 1; j >= 0; j--) { + t.push(n[j]); + s++; + if (!(s % 3)) { + t.push(separator); + } + } + t = t.reverse(); + current[0] = t.join(""); + if (current[0].substr(0, 1) == separator) { + current[0] = current[0].substr(1); + } + } else { + current[0] = ""; + } + + // Value + this.values[this.index] = current.join(decimal); + + // Negative + if (negative) { + this.values[this.index] = "-" + this.values[this.index]; + } + } + }, + 0: function (v) { + if (v.match(/[0-9]/g)) { + this.values[this.index] = v; + this.index++; + } + }, + "[0-9a-zA-Z$]+": function (v) { + if (isBlank(this.values[this.index])) { + this.values[this.index] = ""; + } + var t = this.tokens[this.index]; + var s = this.values[this.index]; + var i = s.length; + + if (t[i] == v) { + this.values[this.index] += v; + + if (this.values[this.index] == t) { + this.index++; + } + } else { + this.values[this.index] = t; + this.index++; + + if (v.match(/[\-0-9]/g)) { + // Repeat the character + this.position--; + } + } + }, + A: function (v) { + if (v.match(/[a-zA-Z]/gi)) { + this.values[this.index] = v; + this.index++; + } + }, + ".": function (v) { + parser["[0-9a-zA-Z$]+"].call(this, v); + }, + "@": function (v) { + if (isBlank(this.values[this.index])) { + this.values[this.index] = ""; + } + this.values[this.index] += v; + }, + }; + + /** + * Get the tokens in the mask string + */ + var getTokens = function (str) { + if (this.type == "general") { + var t = [].concat(tokens.general); + } else { + var t = [].concat( + tokens.currency, + tokens.datetime, + tokens.percentage, + tokens.numeric, + tokens.text, + tokens.general + ); + } + // Expression to extract all tokens from the string + var e = new RegExp(t.join("|"), "gi"); + // Extract + return str.match(e); + }; + + /** + * Get the method of one given token + */ + var getMethod = function (str) { + if (!this.type) { + var types = Object.keys(tokens); + } else if (this.type == "text") { + var types = ["text"]; + } else if (this.type == "general") { + var types = ["general"]; + } else if (this.type == "datetime") { + var types = ["numeric", "datetime", "general"]; + } else { + var types = ["currency", "percentage", "numeric", "general"]; + } + + // Found + for (var i = 0; i < types.length; i++) { + var type = types[i]; + for (var j = 0; j < tokens[type].length; j++) { + var e = new RegExp(tokens[type][j], "gi"); + var r = str.match(e); + if (r) { + return { type: type, method: tokens[type][j] }; + } + } + } + }; + + /** + * Identify each method for each token + */ + var getMethods = function (t) { + var result = []; + for (var i = 0; i < t.length; i++) { + var m = getMethod.call(this, t[i]); + if (m) { + result.push(m.method); + } else { + result.push(null); + } + } + + // Compatibility with excel + for (var i = 0; i < result.length; i++) { + if (result[i] == "MM") { + // Not a month, correct to minutes + if (result[i - 1] && result[i - 1].indexOf("H") >= 0) { + result[i] = "MI"; + } else if (result[i - 2] && result[i - 2].indexOf("H") >= 0) { + result[i] = "MI"; + } else if (result[i + 1] && result[i + 1].indexOf("S") >= 0) { + result[i] = "MI"; + } else if (result[i + 2] && result[i + 2].indexOf("S") >= 0) { + result[i] = "MI"; + } + } + } + + return result; + }; + + /** + * Get the type for one given token + */ + var getType = function (str) { + var m = getMethod.call(this, str); + if (m) { + var type = m.type; + } + + if (type) { + var numeric = 0; + // Make sure the correct type + var t = getTokens.call(this, str); + for (var i = 0; i < t.length; i++) { + m = getMethod.call(this, t[i]); + if (m && isNumeric(m.type)) { + numeric++; + } + } + if (numeric > 1) { + type = "general"; + } + } + + return type; + }; + + /** + * Parse character per character using the detected tokens in the mask + */ + var parse = function () { + // Parser method for this position + if (typeof parser[this.methods[this.index]] == "function") { + parser[this.methods[this.index]].call(this, this.value[this.position]); + this.position++; + } else { + this.values[this.index] = this.tokens[this.index]; + this.index++; + } + }; + + var isFormula = function (value) { + var v = ("" + value)[0]; + return v == "=" ? true : false; + }; + + var toPlainString = function (num) { + return ("" + +num).replace( + /(-?)(\d*)\.?(\d*)e([+-]\d+)/, + function (a, b, c, d, e) { + return e < 0 + ? b + "0." + Array(1 - e - c.length).join(0) + c + d + : b + c + d + Array(e - d.length + 1).join(0); + } + ); + }; + + /** + * Mask function + * @param {mixed|string} JS input or a string to be parsed + * @param {object|string} When the first param is a string, the second is the mask or object with the mask options + */ + var obj = function (e, config, returnObject) { + // Options + var r = null; + var t = null; + var o = { + // Element + input: null, + // Current value + value: null, + // Mask options + options: {}, + // New values for each token found + values: [], + // Token position + index: 0, + // Character position + position: 0, + // Date raw values + date: [0, 0, 0, 0, 0, 0], + // Raw number for the numeric values + number: 0, + }; + + // This is a JavaScript Event + if (typeof e == "object") { + // Element + o.input = e.target; + // Current value + o.value = Value.call(e.target); + // Current caret position + o.caret = Caret.call(e.target); + // Mask + if ((t = e.target.getAttribute("data-mask"))) { + o.mask = t; + } + // Type + if ((t = e.target.getAttribute("data-type"))) { + o.type = t; + } + // Options + if (e.target.mask) { + if (e.target.mask.options) { + o.options = e.target.mask.options; + } + if (e.target.mask.locale) { + o.locale = e.target.mask.locale; + } + } else { + // Locale + if ((t = e.target.getAttribute("data-locale"))) { + o.locale = t; + if (o.mask) { + o.options.style = o.mask; + } + } + } + // Extra configuration + if (e.target.attributes && e.target.attributes.length) { + for (var i = 0; i < e.target.attributes.length; i++) { + var k = e.target.attributes[i].name; + var v = e.target.attributes[i].value; + if (k.substr(0, 4) == "data") { + o.options[k.substr(5)] = v; + } + } + } + } else { + // Options + if (typeof config == "string") { + // Mask + o.mask = config; + } else { + // Mask + var k = Object.keys(config); + for (var i = 0; i < k.length; i++) { + o[k[i]] = config[k[i]]; + } + } + + if (typeof e === "number") { + // Get decimal + getDecimal.call(o, o.mask); + // Replace to the correct decimal + e = ("" + e).replace(".", o.options.decimal); + } + + // Current + o.value = e; + + if (o.input) { + // Value + Value.call(o.input, e); + // Focus + jSuites.focus(o.input); + // Caret + o.caret = Caret.call(o.input); + } + } + + // Mask detected start the process + if (!isFormula(o.value) && (o.mask || o.locale)) { + // Compatibility fixes + if (o.mask) { + // Remove [] + o.mask = o.mask.replace(new RegExp(/\[h]/), "|h|"); + o.mask = o.mask.replace(new RegExp(/\[.*?\]/), ""); + o.mask = o.mask.replace(new RegExp(/\|h\|/), "[h]"); + if (o.mask.indexOf(";") !== -1) { + var t = o.mask.split(";"); + o.mask = t[0]; + } + // Excel mask TODO: Improve + if (o.mask.indexOf("##") !== -1) { + var d = o.mask.split(";"); + if (d[0]) { + d[0] = d[0].replace("*", "\t"); + d[0] = d[0].replace(new RegExp(/_-/g), " "); + d[0] = d[0].replace(new RegExp(/_/g), ""); + d[0] = d[0].replace("##0.###", "##0.000"); + d[0] = d[0].replace("##0.##", "##0.00"); + d[0] = d[0].replace("##0.#", "##0.0"); + d[0] = d[0].replace("##0,###", "##0,000"); + d[0] = d[0].replace("##0,##", "##0,00"); + d[0] = d[0].replace("##0,#", "##0,0"); + } + o.mask = d[0]; + } + // Get type + if (!o.type) { + o.type = getType.call(o, o.mask); + } + // Get tokens + o.tokens = getTokens.call(o, o.mask); + } + // On new input + if ( + typeof e !== "object" || + !e.inputType || + !e.inputType.indexOf("insert") || + !e.inputType.indexOf("delete") + ) { + // Start transformation + if (o.locale) { + if (o.input) { + Format.call(o, o.input, e); + } else { + var newValue = FormatValue.call(o, o.value); + } + } else { + // Get tokens + o.methods = getMethods.call(o, o.tokens); + // Go through all tokes + while ( + o.position < o.value.length && + typeof o.tokens[o.index] !== "undefined" + ) { + // Get the appropriate parser + parse.call(o); + } + + // New value + var newValue = o.values.join(""); + + // Add tokens to the end of string only if string is not empty + if (isNumeric(o.type) && newValue !== "") { + // Complement things in the end of the mask + while (typeof o.tokens[o.index] !== "undefined") { + var t = getMethod.call(o, o.tokens[o.index]); + if (t && t.type == "general") { + o.values[o.index] = o.tokens[o.index]; + } + o.index++; + } + + var adjustNumeric = true; + } else { + var adjustNumeric = false; + } + + // New value + newValue = o.values.join(""); + + // Reset value + if (o.input) { + t = newValue.length - o.value.length; + if (t > 0) { + var caret = o.caret + t; + } else { + var caret = o.caret; + } + Value.call(o.input, newValue, caret, adjustNumeric); + } + } + } + + // Update raw data + if (o.input) { + var label = null; + if (isNumeric(o.type)) { + // Extract the number + o.number = Extract.call(o, Value.call(o.input)); + // Keep the raw data as a property of the tag + if (o.type == "percentage") { + label = o.number / 100; + } else { + label = o.number; + } + } else if (o.type == "datetime") { + label = getDate.call(o); + + if (o.date[0] && o.date[1] && o.date[2]) { + o.input.setAttribute("data-completed", true); + } + } + + if (label) { + o.input.setAttribute("data-value", label); + } + } + + if (newValue !== undefined) { + if (returnObject) { + return o; + } else { + return newValue; + } + } + } + }; + + // Get the type of the mask + obj.getType = getType; + + // Extract the tokens from a mask + obj.prepare = function (str, o) { + if (!o) { + o = {}; + } + return getTokens.call(o, str); + }; + + /** + * Apply the mask to a element (legacy) + */ + obj.apply = function (e) { + var v = Value.call(e.target); + if (e.key.length == 1) { + v += e.key; + } + Value.call(e.target, obj(v, e.target.getAttribute("data-mask"))); + }; + + /** + * Legacy support + */ + obj.run = function (value, mask, decimal) { + return obj(value, { mask: mask, decimal: decimal }); + }; + + /** + * Extract number from masked string + */ + obj.extract = function (v, options, returnObject) { + if (isBlank(v)) { + return v; + } + if (typeof options != "object") { + return value; + } else { + options = Object.assign({}, options); + + if (!options.options) { + options.options = {}; + } + } + + // Compatibility + if (!options.mask && options.format) { + options.mask = options.format; + } + + // Remove [] + if (options.mask) { + if (options.mask.indexOf(";") !== -1) { + var t = options.mask.split(";"); + options.mask = t[0]; + } + options.mask = options.mask.replace(new RegExp(/\[.*?\]/), ""); + } + + // Get decimal + getDecimal.call(options, options.mask); + + var type = null; + if (options.type == "percent" || options.options.style == "percent") { + type = "percentage"; + } else if (options.mask) { + type = getType.call(options, options.mask); + } + + if (type === "general") { + var o = obj(v, options, true); + + value = v; + } else if (type === "datetime") { + if (v instanceof Date) { + var t = jSuites.calendar.getDateString(value, options.mask); + } + + var o = obj(v, options, true); + + if (jSuites.isNumeric(v)) { + value = v; + } else { + var value = getDate.call(o); + var t = jSuites.calendar.now(o.date); + value = jSuites.calendar.dateToNum(t); + } + } else { + var value = Extract.call(options, v); + // Percentage + if (type == "percentage") { + value /= 100; + } + var o = options; + } + + o.value = value; + + if (!o.type && type) { + o.type = type; + } + + if (returnObject) { + return o; + } else { + return value; + } + }; + + /** + * Render + */ + obj.render = function (value, options, fullMask) { + if (isBlank(value)) { + return value; + } + + if (typeof options != "object") { + return value; + } else { + options = Object.assign({}, options); + + if (!options.options) { + options.options = {}; + } + } + + // Compatibility + if (!options.mask && options.format) { + options.mask = options.format; + } + + // Remove [] + if (options.mask) { + if (options.mask.indexOf(";") !== -1) { + var t = options.mask.split(";"); + options.mask = t[0]; + } + options.mask = options.mask.replace(new RegExp(/\[h]/), "|h|"); + options.mask = options.mask.replace(new RegExp(/\[.*?\]/), ""); + options.mask = options.mask.replace(new RegExp(/\|h\|/), "[h]"); + } + + var type = null; + if (options.type == "percent" || options.options.style == "percent") { + type = "percentage"; + } else if (options.mask) { + type = getType.call(options, options.mask); + } else if (value instanceof Date) { + type = "datetime"; + } + + // Fill with blanks + var fillWithBlanks = false; + + if (type == "datetime" || options.type == "calendar") { + var t = jSuites.calendar.getDateString(value, options.mask); + if (t) { + value = t; + } + + if (options.mask && fullMask) { + fillWithBlanks = true; + } + } else { + // Percentage + if (type == "percentage") { + value *= 100; + } + // Number of decimal places + if (typeof value === "number") { + var t = null; + if (options.mask && fullMask) { + var d = getDecimal.call(options, options.mask); + if (options.mask.indexOf(d) !== -1) { + d = options.mask.split(d); + d = "" + d[1].match(/[0-9]+/g); + d = d.length; + t = value.toFixed(d); + } else { + t = value.toFixed(0); + } + } else if (options.locale && fullMask) { + // Append zeros + var d = ("" + value).split("."); + if (options.options) { + if (typeof d[1] === "undefined") { + d[1] = ""; + } + var len = d[1].length; + if (options.options.minimumFractionDigits > len) { + for ( + var i = 0; + i < options.options.minimumFractionDigits - len; + i++ + ) { + d[1] += "0"; + } + } + } + if (!d[1].length) { + t = d[0]; + } else { + t = d.join("."); + } + var len = d[1].length; + if ( + options.options && + options.options.maximumFractionDigits < len + ) { + t = parseFloat(t).toFixed(options.options.maximumFractionDigits); + } + } else { + t = toPlainString(value); + } + + if (t !== null) { + value = t; + // Get decimal + getDecimal.call(options, options.mask); + // Replace to the correct decimal + if (options.options.decimal) { + value = value.replace(".", options.options.decimal); + } + } + } else { + if (options.mask && fullMask) { + fillWithBlanks = true; + } + } + } + + if (fillWithBlanks) { + var s = options.mask.length - value.length; + if (s > 0) { + for (var i = 0; i < s; i++) { + value += " "; + } + } + } + + value = obj(value, options); + + // Numeric mask, number of zeros + if (fullMask && type === "numeric") { + var maskZeros = options.mask.match(new RegExp(/^[0]+$/gm)); + if (maskZeros && maskZeros.length === 1) { + var maskLength = maskZeros[0].length; + if (maskLength > 3) { + value = "" + value; + while (value.length < maskLength) { + value = "0" + value; + } + } + } + } + + return value; + }; + + obj.set = function (e, m) { + if (m) { + e.setAttribute("data-mask", m); + // Reset the value + var event = new Event("input", { + bubbles: true, + cancelable: true, + }); + e.dispatchEvent(event); + } + }; + + if (typeof document !== "undefined") { + document.addEventListener("input", function (e) { + if (e.target.getAttribute("data-mask") || e.target.mask) { + obj(e); + } + }); + } + + return obj; + })(); + + jSuites.modal = function (el, options) { + var obj = {}; + obj.options = {}; + + // Default configuration + var defaults = { + url: null, + onopen: null, + onclose: null, + closed: false, + width: null, + height: null, + title: null, + padding: null, + backdrop: true, + }; + + // Loop through our object + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + obj.options[property] = defaults[property]; + } + } + + // Title + if (!obj.options.title && el.getAttribute("title")) { + obj.options.title = el.getAttribute("title"); + } + + var temp = document.createElement("div"); + while (el.children[0]) { + temp.appendChild(el.children[0]); + } + + obj.content = document.createElement("div"); + obj.content.className = "jmodal_content"; + obj.content.innerHTML = el.innerHTML; + + while (temp.children[0]) { + obj.content.appendChild(temp.children[0]); + } + + obj.container = document.createElement("div"); + obj.container.className = "jmodal"; + obj.container.appendChild(obj.content); + + if (obj.options.padding) { + obj.content.style.padding = obj.options.padding; + } + if (obj.options.width) { + obj.container.style.width = obj.options.width; + } + if (obj.options.height) { + obj.container.style.height = obj.options.height; + } + if (obj.options.title) { + obj.container.setAttribute("title", obj.options.title); + } else { + obj.container.classList.add("no-title"); + } + el.innerHTML = ""; + el.style.display = "none"; + el.appendChild(obj.container); + + // Backdrop + if (obj.options.backdrop) { + var backdrop = document.createElement("div"); + backdrop.className = "jmodal_backdrop"; + backdrop.onclick = function () { + obj.close(); + }; + el.appendChild(backdrop); + } + + obj.open = function () { + el.style.display = "block"; + // Fullscreen + var rect = obj.container.getBoundingClientRect(); + if (jSuites.getWindowWidth() < rect.width) { + obj.container.style.top = ""; + obj.container.style.left = ""; + obj.container.classList.add("jmodal_fullscreen"); + jSuites.animation.slideBottom(obj.container, 1); + } else { + if (obj.options.backdrop) { + backdrop.style.display = "block"; + } + } + // Event + if (typeof obj.options.onopen == "function") { + obj.options.onopen(el, obj); + } + }; + + obj.resetPosition = function () { + obj.container.style.top = ""; + obj.container.style.left = ""; + }; + + obj.isOpen = function () { + return el.style.display != "none" ? true : false; + }; + + obj.close = function () { + if (obj.isOpen()) { + el.style.display = "none"; + if (obj.options.backdrop) { + // Backdrop + backdrop.style.display = ""; + } + // Remove fullscreen class + obj.container.classList.remove("jmodal_fullscreen"); + // Event + if (typeof obj.options.onclose == "function") { + obj.options.onclose(el, obj); + } + } + }; + + if (!jSuites.modal.hasEvents) { + // Position + var tracker = null; + + document.addEventListener("keydown", function (e) { + if (e.which == 27) { + var modals = document.querySelectorAll(".jmodal"); + for (var i = 0; i < modals.length; i++) { + modals[i].parentNode.modal.close(); + } + } + }); + + document.addEventListener("mouseup", function (e) { + var item = jSuites.findElement(e.target, "jmodal"); + if (item) { + // Get target info + var rect = item.getBoundingClientRect(); + + if (e.changedTouches && e.changedTouches[0]) { + var x = e.changedTouches[0].clientX; + var y = e.changedTouches[0].clientY; + } else { + var x = e.clientX; + var y = e.clientY; + } + + if (rect.width - (x - rect.left) < 50 && y - rect.top < 50) { + item.parentNode.modal.close(); + } + } + + if (tracker) { + tracker.element.style.cursor = "auto"; + tracker = null; + } + }); + + document.addEventListener("mousedown", function (e) { + var item = jSuites.findElement(e.target, "jmodal"); + if (item) { + // Get target info + var rect = item.getBoundingClientRect(); + + if (e.changedTouches && e.changedTouches[0]) { + var x = e.changedTouches[0].clientX; + var y = e.changedTouches[0].clientY; + } else { + var x = e.clientX; + var y = e.clientY; + } + + if (rect.width - (x - rect.left) < 50 && y - rect.top < 50) { + // Do nothing + } else { + if (e.target.getAttribute("title") && y - rect.top < 50) { + if (document.selection) { + document.selection.empty(); + } else if (window.getSelection) { + window.getSelection().removeAllRanges(); + } + + tracker = { + left: rect.left, + top: rect.top, + x: e.clientX, + y: e.clientY, + width: rect.width, + height: rect.height, + element: item, + }; + } + } + } + }); + + document.addEventListener("mousemove", function (e) { + if (tracker) { + e = e || window.event; + if (e.buttons) { + var mouseButton = e.buttons; + } else if (e.button) { + var mouseButton = e.button; + } else { + var mouseButton = e.which; + } + + if (mouseButton) { + tracker.element.style.top = + tracker.top + (e.clientY - tracker.y) + tracker.height / 2 + "px"; + tracker.element.style.left = + tracker.left + (e.clientX - tracker.x) + tracker.width / 2 + "px"; + tracker.element.style.cursor = "move"; + } else { + tracker.element.style.cursor = "auto"; + } + } + }); + + jSuites.modal.hasEvents = true; + } + + if (obj.options.url) { + jSuites.ajax({ + url: obj.options.url, + method: "GET", + dataType: "text/html", + success: function (data) { + obj.content.innerHTML = data; + + if (!obj.options.closed) { + obj.open(); + } + }, + }); + } else { + if (!obj.options.closed) { + obj.open(); + } + } + + // Keep object available from the node + el.modal = obj; + + return obj; + }; + + jSuites.notification = function (options) { + var obj = {}; + obj.options = {}; + + // Default configuration + var defaults = { + icon: null, + name: "Notification", + date: null, + error: null, + title: null, + message: null, + timeout: 4000, + autoHide: true, + closeable: true, + }; + + // Loop through our object + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + obj.options[property] = defaults[property]; + } + } + + var notification = document.createElement("div"); + notification.className = "jnotification"; + + if (obj.options.error) { + notification.classList.add("jnotification-error"); + } + + var notificationContainer = document.createElement("div"); + notificationContainer.className = "jnotification-container"; + notification.appendChild(notificationContainer); + + var notificationHeader = document.createElement("div"); + notificationHeader.className = "jnotification-header"; + notificationContainer.appendChild(notificationHeader); + + var notificationImage = document.createElement("div"); + notificationImage.className = "jnotification-image"; + notificationHeader.appendChild(notificationImage); + + if (obj.options.icon) { + var notificationIcon = document.createElement("img"); + notificationIcon.src = obj.options.icon; + notificationImage.appendChild(notificationIcon); + } + + var notificationName = document.createElement("div"); + notificationName.className = "jnotification-name"; + notificationName.innerHTML = obj.options.name; + notificationHeader.appendChild(notificationName); + + if (obj.options.closeable == true) { + var notificationClose = document.createElement("div"); + notificationClose.className = "jnotification-close"; + notificationClose.onclick = function () { + obj.hide(); + }; + notificationHeader.appendChild(notificationClose); + } + + var notificationDate = document.createElement("div"); + notificationDate.className = "jnotification-date"; + notificationHeader.appendChild(notificationDate); + + var notificationContent = document.createElement("div"); + notificationContent.className = "jnotification-content"; + notificationContainer.appendChild(notificationContent); + + if (obj.options.title) { + var notificationTitle = document.createElement("div"); + notificationTitle.className = "jnotification-title"; + notificationTitle.innerHTML = obj.options.title; + notificationContent.appendChild(notificationTitle); + } + + var notificationMessage = document.createElement("div"); + notificationMessage.className = "jnotification-message"; + notificationMessage.innerHTML = obj.options.message; + notificationContent.appendChild(notificationMessage); + + obj.show = function () { + document.body.appendChild(notification); + if (jSuites.getWindowWidth() > 800) { + jSuites.animation.fadeIn(notification); + } else { + jSuites.animation.slideTop(notification, 1); + } + }; + + obj.hide = function () { + if (jSuites.getWindowWidth() > 800) { + jSuites.animation.fadeOut(notification, function () { + if (notification.parentNode) { + notification.parentNode.removeChild(notification); + if (notificationTimeout) { + clearTimeout(notificationTimeout); + } + } + }); + } else { + jSuites.animation.slideTop(notification, 0, function () { + if (notification.parentNode) { + notification.parentNode.removeChild(notification); + if (notificationTimeout) { + clearTimeout(notificationTimeout); + } + } + }); + } + }; + + obj.show(); + + if (obj.options.autoHide == true) { + var notificationTimeout = setTimeout(function () { + obj.hide(); + }, obj.options.timeout); + } + + if (jSuites.getWindowWidth() < 800) { + notification.addEventListener("swipeup", function (e) { + obj.hide(); + e.preventDefault(); + e.stopPropagation(); + }); + } + + return obj; + }; + + jSuites.notification.isVisible = function () { + var j = document.querySelector(".jnotification"); + return j && j.parentNode ? true : false; + }; + + // More palettes https://coolors.co/ or https://gka.github.io/palettes/#/10|s|003790,005647,ffffe0|ffffe0,ff005e,93003a|1|1 + jSuites.palette = (function () { + /** + * Available palettes + */ + var palette = { + material: [ + [ + "#ffebee", + "#fce4ec", + "#f3e5f5", + "#e8eaf6", + "#e3f2fd", + "#e0f7fa", + "#e0f2f1", + "#e8f5e9", + "#f1f8e9", + "#f9fbe7", + "#fffde7", + "#fff8e1", + "#fff3e0", + "#fbe9e7", + "#efebe9", + "#fafafa", + "#eceff1", + ], + [ + "#ffcdd2", + "#f8bbd0", + "#e1bee7", + "#c5cae9", + "#bbdefb", + "#b2ebf2", + "#b2dfdb", + "#c8e6c9", + "#dcedc8", + "#f0f4c3", + "#fff9c4", + "#ffecb3", + "#ffe0b2", + "#ffccbc", + "#d7ccc8", + "#f5f5f5", + "#cfd8dc", + ], + [ + "#ef9a9a", + "#f48fb1", + "#ce93d8", + "#9fa8da", + "#90caf9", + "#80deea", + "#80cbc4", + "#a5d6a7", + "#c5e1a5", + "#e6ee9c", + "#fff59d", + "#ffe082", + "#ffcc80", + "#ffab91", + "#bcaaa4", + "#eeeeee", + "#b0bec5", + ], + [ + "#e57373", + "#f06292", + "#ba68c8", + "#7986cb", + "#64b5f6", + "#4dd0e1", + "#4db6ac", + "#81c784", + "#aed581", + "#dce775", + "#fff176", + "#ffd54f", + "#ffb74d", + "#ff8a65", + "#a1887f", + "#e0e0e0", + "#90a4ae", + ], + [ + "#ef5350", + "#ec407a", + "#ab47bc", + "#5c6bc0", + "#42a5f5", + "#26c6da", + "#26a69a", + "#66bb6a", + "#9ccc65", + "#d4e157", + "#ffee58", + "#ffca28", + "#ffa726", + "#ff7043", + "#8d6e63", + "#bdbdbd", + "#78909c", + ], + [ + "#f44336", + "#e91e63", + "#9c27b0", + "#3f51b5", + "#2196f3", + "#00bcd4", + "#009688", + "#4caf50", + "#8bc34a", + "#cddc39", + "#ffeb3b", + "#ffc107", + "#ff9800", + "#ff5722", + "#795548", + "#9e9e9e", + "#607d8b", + ], + [ + "#e53935", + "#d81b60", + "#8e24aa", + "#3949ab", + "#1e88e5", + "#00acc1", + "#00897b", + "#43a047", + "#7cb342", + "#c0ca33", + "#fdd835", + "#ffb300", + "#fb8c00", + "#f4511e", + "#6d4c41", + "#757575", + "#546e7a", + ], + [ + "#d32f2f", + "#c2185b", + "#7b1fa2", + "#303f9f", + "#1976d2", + "#0097a7", + "#00796b", + "#388e3c", + "#689f38", + "#afb42b", + "#fbc02d", + "#ffa000", + "#f57c00", + "#e64a19", + "#5d4037", + "#616161", + "#455a64", + ], + [ + "#c62828", + "#ad1457", + "#6a1b9a", + "#283593", + "#1565c0", + "#00838f", + "#00695c", + "#2e7d32", + "#558b2f", + "#9e9d24", + "#f9a825", + "#ff8f00", + "#ef6c00", + "#d84315", + "#4e342e", + "#424242", + "#37474f", + ], + [ + "#b71c1c", + "#880e4f", + "#4a148c", + "#1a237e", + "#0d47a1", + "#006064", + "#004d40", + "#1b5e20", + "#33691e", + "#827717", + "#f57f17", + "#ff6f00", + "#e65100", + "#bf360c", + "#3e2723", + "#212121", + "#263238", + ], + ], + fire: [ + [ + "0b1a6d", + "840f38", + "b60718", + "de030b", + "ff0c0c", + "fd491c", + "fc7521", + "faa331", + "fbb535", + "ffc73a", + ], + [ + "071147", + "5f0b28", + "930513", + "be0309", + "ef0000", + "fa3403", + "fb670b", + "f9991b", + "faad1e", + "ffc123", + ], + [ + "03071e", + "370617", + "6a040f", + "9d0208", + "d00000", + "dc2f02", + "e85d04", + "f48c06", + "faa307", + "ffba08", + ], + [ + "020619", + "320615", + "61040d", + "8c0207", + "bc0000", + "c82a02", + "d05203", + "db7f06", + "e19405", + "efab00", + ], + [ + "020515", + "2d0513", + "58040c", + "7f0206", + "aa0000", + "b62602", + "b94903", + "c57205", + "ca8504", + "d89b00", + ], + ], + baby: [ + [ + "eddcd2", + "fff1e6", + "fde2e4", + "fad2e1", + "c5dedd", + "dbe7e4", + "f0efeb", + "d6e2e9", + "bcd4e6", + "99c1de", + ], + [ + "e1c4b3", + "ffd5b5", + "fab6ba", + "f5a8c4", + "aacecd", + "bfd5cf", + "dbd9d0", + "baceda", + "9dc0db", + "7eb1d5", + ], + [ + "daa990", + "ffb787", + "f88e95", + "f282a9", + "8fc4c3", + "a3c8be", + "cec9b3", + "9dbcce", + "82acd2", + "649dcb", + ], + [ + "d69070", + "ff9c5e", + "f66770", + "f05f8f", + "74bbb9", + "87bfae", + "c5b993", + "83aac3", + "699bca", + "4d89c2", + ], + [ + "c97d5d", + "f58443", + "eb4d57", + "e54a7b", + "66a9a7", + "78ae9c", + "b5a67e", + "7599b1", + "5c88b7", + "4978aa", + ], + ], + chart: [ + [ + "#C1D37F", + "#4C5454", + "#FFD275", + "#66586F", + "#D05D5B", + "#C96480", + "#95BF8F", + "#6EA240", + "#0F0F0E", + "#EB8258", + "#95A3B3", + "#995D81", + ], + ], + }; + + /** + * Get a pallete + */ + var component = function (o) { + // Otherwise get palette value + if (palette[o]) { + return palette[o]; + } else { + return palette.material; + } + }; + + component.get = function (o) { + // Otherwise get palette value + if (palette[o]) { + return palette[o]; + } else { + return palette; + } + }; + + component.set = function (o, v) { + palette[o] = v; + }; + + return component; + })(); + + jSuites.picker = function (el, options) { + // Already created, update options + if (el.picker) { + return el.picker.setOptions(options, true); + } + + // New instance + var obj = { type: "picker" }; + obj.options = {}; + + var dropdownHeader = null; + var dropdownContent = null; + + /** + * Create the content options + */ + var createContent = function () { + dropdownContent.innerHTML = ""; + + // Create items + var keys = Object.keys(obj.options.data); + + // Go though all options + for (var i = 0; i < keys.length; i++) { + // Item + var dropdownItem = document.createElement("div"); + dropdownItem.classList.add("jpicker-item"); + dropdownItem.k = keys[i]; + dropdownItem.v = obj.options.data[keys[i]]; + // Label + dropdownItem.innerHTML = obj.getLabel(keys[i]); + // Append + dropdownContent.appendChild(dropdownItem); + } + }; + + /** + * Set or reset the options for the picker + */ + obj.setOptions = function (options, reset) { + // Default configuration + var defaults = { + value: 0, + data: null, + render: null, + onchange: null, + onselect: null, + onopen: null, + onclose: null, + onload: null, + width: null, + header: true, + right: false, + content: false, + columns: null, + height: null, + }; + + // Legacy purpose only + if (options && options.options) { + options.data = options.options; + } + + // Loop through the initial configuration + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + if (typeof obj.options[property] == "undefined" || reset === true) { + obj.options[property] = defaults[property]; + } + } + } + + // Start using the options + if (obj.options.header === false) { + dropdownHeader.style.display = "none"; + } else { + dropdownHeader.style.display = ""; + } + + // Width + if (obj.options.width) { + dropdownHeader.style.width = parseInt(obj.options.width) + "px"; + } else { + dropdownHeader.style.width = ""; + } + + // Height + if (obj.options.height) { + dropdownContent.style.maxHeight = obj.options.height + "px"; + dropdownContent.style.overflow = "scroll"; + } else { + dropdownContent.style.overflow = ""; + } + + if (obj.options.columns > 0) { + dropdownContent.classList.add("jpicker-columns"); + dropdownContent.style.width = obj.options.width + ? obj.options.width + : 36 * obj.options.columns + "px"; + } + + if (isNaN(obj.options.value)) { + obj.options.value = "0"; + } + + // Create list from data + createContent(); + + // Set value + obj.setValue(obj.options.value); + + // Set options all returns the own instance + return obj; + }; + + obj.getValue = function () { + return obj.options.value; + }; + + obj.setValue = function (v) { + // Set label + obj.setLabel(v); + + // Update value + obj.options.value = String(v); + + // Lemonade JS + if (el.value != obj.options.value) { + el.value = obj.options.value; + if (typeof el.oninput == "function") { + el.oninput({ + type: "input", + target: el, + value: el.value, + }); + } + } + + if (dropdownContent.children[v].getAttribute("type") !== "generic") { + obj.close(); + } + }; + + obj.getLabel = function (v) { + var label = obj.options.data[v] || null; + if (typeof obj.options.render == "function") { + label = obj.options.render(label); + } + return label; + }; + + obj.setLabel = function (v) { + if (obj.options.content) { + var label = '' + obj.options.content + ""; + } else { + var label = obj.getLabel(v); + } + + dropdownHeader.innerHTML = label; + }; + + obj.open = function () { + if (!el.classList.contains("jpicker-focus")) { + // Start tracking the element + jSuites.tracking(obj, true); + + // Open picker + el.classList.add("jpicker-focus"); + el.focus(); + + var top = 0; + var left = 0; + + dropdownContent.style.marginLeft = ""; + + var rectHeader = dropdownHeader.getBoundingClientRect(); + var rectContent = dropdownContent.getBoundingClientRect(); + + if (window.innerHeight < rectHeader.bottom + rectContent.height) { + top = -1 * (rectContent.height + 4); + } else { + top = rectHeader.height + 4; + } + + if (obj.options.right === true) { + left = -1 * rectContent.width + rectHeader.width; + } + + if (rectContent.left + left < 0) { + left = left + rectContent.left + 10; + } + if (rectContent.left + rectContent.width > window.innerWidth) { + left = + -1 * + (10 + rectContent.left + rectContent.width - window.innerWidth); + } + + dropdownContent.style.marginTop = parseInt(top) + "px"; + dropdownContent.style.marginLeft = parseInt(left) + "px"; + + //dropdownContent.style.marginTop + if (typeof obj.options.onopen == "function") { + obj.options.onopen(el, obj); + } + } + }; + + obj.close = function () { + if (el.classList.contains("jpicker-focus")) { + el.classList.remove("jpicker-focus"); + + // Start tracking the element + jSuites.tracking(obj, false); + + if (typeof obj.options.onclose == "function") { + obj.options.onclose(el, obj); + } + } + }; + + /** + * Create floating picker + */ + var init = function () { + // Class + el.classList.add("jpicker"); + el.setAttribute("tabindex", "900"); + el.onmousedown = function (e) { + if (!el.classList.contains("jpicker-focus")) { + obj.open(); + } + }; + + // Dropdown Header + dropdownHeader = document.createElement("div"); + dropdownHeader.classList.add("jpicker-header"); + + // Dropdown content + dropdownContent = document.createElement("div"); + dropdownContent.classList.add("jpicker-content"); + dropdownContent.onclick = function (e) { + var item = jSuites.findElement(e.target, "jpicker-item"); + if (item) { + if (item.parentNode === dropdownContent) { + // Update label + obj.setValue(item.k); + // Call method + if (typeof obj.options.onchange == "function") { + obj.options.onchange.call( + obj, + el, + obj, + item.v, + item.v, + item.k, + e + ); + } + } + } + }; + + // Append content and header + el.appendChild(dropdownHeader); + el.appendChild(dropdownContent); + + // Default value + el.value = options.value || 0; + + // Set options + obj.setOptions(options); + + if (typeof obj.options.onload == "function") { + obj.options.onload(el, obj); + } + + // Change + el.change = obj.setValue; + + // Global generic value handler + el.val = function (val) { + if (val === undefined) { + return obj.getValue(); + } else { + obj.setValue(val); + } + }; + + // Reference + el.picker = obj; + }; + + init(); + + return obj; + }; + + jSuites.progressbar = function (el, options) { + var obj = {}; + obj.options = {}; + + // Default configuration + var defaults = { + value: 0, + onchange: null, + width: null, + }; + + // Loop through the initial configuration + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + obj.options[property] = defaults[property]; + } + } + + // Class + el.classList.add("jprogressbar"); + el.setAttribute("tabindex", 1); + el.setAttribute("data-value", obj.options.value); + + var bar = document.createElement("div"); + bar.style.width = obj.options.value + "%"; + bar.style.color = "#fff"; + el.appendChild(bar); + + if (obj.options.width) { + el.style.width = obj.options.width; + } + + // Set value + obj.setValue = function (value) { + value = parseInt(value); + obj.options.value = value; + bar.style.width = value + "%"; + el.setAttribute("data-value", value + "%"); + + if (value < 6) { + el.style.color = "#000"; + } else { + el.style.color = "#fff"; + } + + // Update value + obj.options.value = value; + + if (typeof obj.options.onchange == "function") { + obj.options.onchange(el, value); + } + + // Lemonade JS + if (el.value != obj.options.value) { + el.value = obj.options.value; + if (typeof el.oninput == "function") { + el.oninput({ + type: "input", + target: el, + value: el.value, + }); + } + } + }; + + obj.getValue = function () { + return obj.options.value; + }; + + var action = function (e) { + if (e.which) { + // Get target info + var rect = el.getBoundingClientRect(); + + if (e.changedTouches && e.changedTouches[0]) { + var x = e.changedTouches[0].clientX; + var y = e.changedTouches[0].clientY; + } else { + var x = e.clientX; + var y = e.clientY; + } + + obj.setValue(Math.round(((x - rect.left) / rect.width) * 100)); + } + }; + + // Events + if ("touchstart" in document.documentElement === true) { + el.addEventListener("touchstart", action); + el.addEventListener("touchend", action); + } else { + el.addEventListener("mousedown", action); + el.addEventListener("mousemove", action); + } + + // Change + el.change = obj.setValue; + + // Global generic value handler + el.val = function (val) { + if (val === undefined) { + return obj.getValue(); + } else { + obj.setValue(val); + } + }; + + // Reference + el.progressbar = obj; + + return obj; + }; + + jSuites.rating = function (el, options) { + // Already created, update options + if (el.rating) { + return el.rating.setOptions(options, true); + } + + // New instance + var obj = {}; + obj.options = {}; + + obj.setOptions = function (options, reset) { + // Default configuration + var defaults = { + number: 5, + value: 0, + tooltip: ["Very bad", "Bad", "Average", "Good", "Very good"], + onchange: null, + }; + + // Loop through the initial configuration + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + if (typeof obj.options[property] == "undefined" || reset === true) { + obj.options[property] = defaults[property]; + } + } + } + + // Make sure the container is empty + el.innerHTML = ""; + + // Add elements + for (var i = 0; i < obj.options.number; i++) { + var div = document.createElement("div"); + div.setAttribute("data-index", i + 1); + div.setAttribute("title", obj.options.tooltip[i]); + el.appendChild(div); + } + + // Selected option + if (obj.options.value) { + for (var i = 0; i < obj.options.number; i++) { + if (i < obj.options.value) { + el.children[i].classList.add("jrating-selected"); + } + } + } + + return obj; + }; + + // Set value + obj.setValue = function (index) { + for (var i = 0; i < obj.options.number; i++) { + if (i < index) { + el.children[i].classList.add("jrating-selected"); + } else { + el.children[i].classList.remove("jrating-over"); + el.children[i].classList.remove("jrating-selected"); + } + } + + obj.options.value = index; + + if (typeof obj.options.onchange == "function") { + obj.options.onchange(el, index); + } + + // Lemonade JS + if (el.value != obj.options.value) { + el.value = obj.options.value; + if (typeof el.oninput == "function") { + el.oninput({ + type: "input", + target: el, + value: el.value, + }); + } + } + }; + + obj.getValue = function () { + return obj.options.value; + }; + + var init = function () { + // Start plugin + obj.setOptions(options); + + // Class + el.classList.add("jrating"); + + // Events + el.addEventListener("click", function (e) { + var index = e.target.getAttribute("data-index"); + if (index != undefined) { + if (index == obj.options.value) { + obj.setValue(0); + } else { + obj.setValue(index); + } + } + }); + + el.addEventListener("mouseover", function (e) { + var index = e.target.getAttribute("data-index"); + for (var i = 0; i < obj.options.number; i++) { + if (i < index) { + el.children[i].classList.add("jrating-over"); + } else { + el.children[i].classList.remove("jrating-over"); + } + } + }); + + el.addEventListener("mouseout", function (e) { + for (var i = 0; i < obj.options.number; i++) { + el.children[i].classList.remove("jrating-over"); + } + }); + + // Change + el.change = obj.setValue; + + // Global generic value handler + el.val = function (val) { + if (val === undefined) { + return obj.getValue(); + } else { + obj.setValue(val); + } + }; + + // Reference + el.rating = obj; + }; + + init(); + + return obj; + }; + + jSuites.search = function (el, options) { + if (el.search) { + return el.search; + } + + var index = null; + + var select = function (e) { + if (e.target.classList.contains("jsearch_item")) { + var element = e.target; + } else { + var element = e.target.parentNode; + } + + obj.selectIndex(element); + e.preventDefault(); + }; + + var createList = function (data) { + // Reset container + container.innerHTML = ""; + // Print results + if (!data.length) { + // Show container + el.style.display = ""; + } else { + // Show container + el.style.display = "block"; + + // Show items (only 10) + var len = data.length < 11 ? data.length : 10; + for (var i = 0; i < len; i++) { + if (typeof data[i] == "string") { + var text = data[i]; + var value = data[i]; + } else { + // Legacy + var text = data[i].text; + if (!text && data[i].name) { + text = data[i].name; + } + var value = data[i].value; + if (!value && data[i].id) { + value = data[i].id; + } + } + + var div = document.createElement("div"); + div.setAttribute("data-value", value); + div.setAttribute("data-text", text); + div.className = "jsearch_item"; + + if (data[i].id) { + div.setAttribute("id", data[i].id); + } + + if (obj.options.forceSelect && i == 0) { + div.classList.add("selected"); + } + var img = document.createElement("img"); + if (data[i].image) { + img.src = data[i].image; + } else { + img.style.display = "none"; + } + div.appendChild(img); + + var item = document.createElement("div"); + item.innerHTML = text; + div.appendChild(item); + + // Append item to the container + container.appendChild(div); + } + } + }; + + var execute = function (str) { + if (str != obj.terms) { + // New terms + obj.terms = str; + // New index + if (obj.options.forceSelect) { + index = 0; + } else { + index = null; + } + // Array or remote search + if (Array.isArray(obj.options.data)) { + var test = function (o) { + if (typeof o == "string") { + if (("" + o).toLowerCase().search(str.toLowerCase()) >= 0) { + return true; + } + } else { + for (var key in o) { + var value = o[key]; + if (("" + value).toLowerCase().search(str.toLowerCase()) >= 0) { + return true; + } + } + } + return false; + }; + + var results = obj.options.data.filter(function (item) { + return test(item); + }); + + // Show items + createList(results); + } else { + // Get remove results + jSuites.ajax({ + url: obj.options.data + str, + method: "GET", + dataType: "json", + success: function (data) { + // Show items + createList(data); + }, + }); + } + } + }; + + // Search timer + var timer = null; + + // Search methods + var obj = function (str) { + if (timer) { + clearTimeout(timer); + } + timer = setTimeout(function () { + execute(str); + }, 500); + }; + if (options.forceSelect === null) { + options.forceSelect = true; + } + obj.options = { + data: options.data || null, + input: options.input || null, + searchByNode: options.searchByNode || null, + onselect: options.onselect || null, + forceSelect: options.forceSelect, + onbeforesearch: options.onbeforesearch || null, + }; + + obj.selectIndex = function (item) { + var id = item.getAttribute("id"); + var text = item.getAttribute("data-text"); + var value = item.getAttribute("data-value"); + // Onselect + if (typeof obj.options.onselect == "function") { + obj.options.onselect(obj, text, value, id); + } + // Close container + obj.close(); + }; + + obj.open = function () { + el.style.display = "block"; + }; + + obj.close = function () { + if (timer) { + clearTimeout(timer); + } + // Current terms + obj.terms = ""; + // Remove results + container.innerHTML = ""; + // Hide + el.style.display = ""; + }; + + obj.isOpened = function () { + return el.style.display ? true : false; + }; + + obj.keydown = function (e) { + if (obj.isOpened()) { + if (e.key == "Enter") { + // Enter + if (index !== null && container.children[index]) { + obj.selectIndex(container.children[index]); + e.preventDefault(); + } else { + obj.close(); + } + } else if (e.key === "ArrowUp") { + // Up + if (index !== null && container.children[0]) { + container.children[index].classList.remove("selected"); + if (!obj.options.forceSelect && index === 0) { + index = null; + } else { + index = Math.max(0, index - 1); + container.children[index].classList.add("selected"); + } + } + e.preventDefault(); + } else if (e.key === "ArrowDown") { + // Down + if (index == null) { + index = -1; + } else { + container.children[index].classList.remove("selected"); + } + if (index < 9 && container.children[index + 1]) { + index++; + } + container.children[index].classList.add("selected"); + e.preventDefault(); + } + } + }; + + obj.keyup = function (e) { + if (!obj.options.searchByNode) { + if (obj.options.input.tagName === "DIV") { + var terms = obj.options.input.innerText; + } else { + var terms = obj.options.input.value; + } + } else { + // Current node + var node = jSuites.getNode(); + if (node) { + var terms = node.innerText; + } + } + + if (typeof obj.options.onbeforesearch == "function") { + var ret = obj.options.onbeforesearch(obj, terms); + if (ret) { + terms = ret; + } else { + if (ret === false) { + // Ignore event + return; + } + } + } + + obj(terms); + }; + + // Add events + if (obj.options.input) { + obj.options.input.addEventListener("keyup", obj.keyup); + obj.options.input.addEventListener("keydown", obj.keydown); + } + + // Append element + var container = document.createElement("div"); + container.classList.add("jsearch_container"); + container.onmousedown = select; + el.appendChild(container); + + el.classList.add("jsearch"); + el.search = obj; + + return obj; + }; + + jSuites.slider = function (el, options) { + var obj = {}; + obj.options = {}; + obj.currentImage = null; + + if (options) { + obj.options = options; + } + + // Focus + el.setAttribute("tabindex", "900"); + + // Items + obj.options.items = []; + + if (!el.classList.contains("jslider")) { + el.classList.add("jslider"); + el.classList.add("unselectable"); + + if (obj.options.height) { + el.style.minHeight = obj.options.height; + } + if (obj.options.width) { + el.style.width = obj.options.width; + } + if (obj.options.grid) { + el.classList.add("jslider-grid"); + var number = el.children.length; + if (number > 4) { + el.setAttribute("data-total", number - 4); + } + el.setAttribute("data-number", number > 4 ? 4 : number); + } + + // Add slider counter + var counter = document.createElement("div"); + counter.classList.add("jslider-counter"); + + // Move children inside + if (el.children.length > 0) { + // Keep children items + for (var i = 0; i < el.children.length; i++) { + obj.options.items.push(el.children[i]); + + // counter click event + var item = document.createElement("div"); + item.onclick = function () { + var index = Array.prototype.slice + .call(counter.children) + .indexOf(this); + obj.show((obj.currentImage = obj.options.items[index])); + }; + counter.appendChild(item); + } + } + // Add caption + var caption = document.createElement("div"); + caption.className = "jslider-caption"; + + // Add close buttom + var controls = document.createElement("div"); + var close = document.createElement("div"); + close.className = "jslider-close"; + close.innerHTML = ""; + + close.onclick = function () { + obj.close(); + }; + controls.appendChild(caption); + controls.appendChild(close); + } + + obj.updateCounter = function (index) { + for (var i = 0; i < counter.children.length; i++) { + if (counter.children[i].classList.contains("jslider-counter-focus")) { + counter.children[i].classList.remove("jslider-counter-focus"); + break; + } + } + counter.children[index].classList.add("jslider-counter-focus"); + }; + + obj.show = function (target) { + if (!target) { + var target = el.children[0]; + } + + // Focus element + el.classList.add("jslider-focus"); + el.classList.remove("jslider-grid"); + el.appendChild(controls); + el.appendChild(counter); + + // Update counter + var index = obj.options.items.indexOf(target); + obj.updateCounter(index); + + // Remove display + for (var i = 0; i < el.children.length; i++) { + el.children[i].style.display = ""; + } + target.style.display = "block"; + + // Is there any previous + if (target.previousElementSibling) { + el.classList.add("jslider-left"); + } else { + el.classList.remove("jslider-left"); + } + + // Is there any next + if ( + target.nextElementSibling && + target.nextElementSibling.tagName == "IMG" + ) { + el.classList.add("jslider-right"); + } else { + el.classList.remove("jslider-right"); + } + + obj.currentImage = target; + + // Vertical image + if (obj.currentImage.offsetHeight > obj.currentImage.offsetWidth) { + obj.currentImage.classList.add("jslider-vertical"); + } + + controls.children[0].innerText = obj.currentImage.getAttribute("title"); + }; + + obj.open = function () { + obj.show(); + + // Event + if (typeof obj.options.onopen == "function") { + obj.options.onopen(el); + } + }; + + obj.close = function () { + // Remove control classes + el.classList.remove("jslider-focus"); + el.classList.remove("jslider-left"); + el.classList.remove("jslider-right"); + // Show as a grid depending on the configuration + if (obj.options.grid) { + el.classList.add("jslider-grid"); + } + // Remove display + for (var i = 0; i < el.children.length; i++) { + el.children[i].style.display = ""; + } + // Remove controls from the component + counter.remove(); + controls.remove(); + // Current image + obj.currentImage = null; + // Event + if (typeof obj.options.onclose == "function") { + obj.options.onclose(el); + } + }; + + obj.reset = function () { + el.innerHTML = ""; + }; + + obj.next = function () { + var nextImage = obj.currentImage.nextElementSibling; + if (nextImage && nextImage.tagName === "IMG") { + obj.show(obj.currentImage.nextElementSibling); + } + }; + + obj.prev = function () { + if (obj.currentImage.previousElementSibling) { + obj.show(obj.currentImage.previousElementSibling); + } + }; + + var mouseUp = function (e) { + // Open slider + if (e.target.tagName == "IMG") { + obj.show(e.target); + } else if ( + !e.target.classList.contains("jslider-close") && + !( + e.target.parentNode.classList.contains("jslider-counter") || + e.target.classList.contains("jslider-counter") + ) + ) { + // Arrow controls + var offsetX = e.offsetX || e.changedTouches[0].clientX; + if (e.target.clientWidth - offsetX < 40) { + // Show next image + obj.next(); + } else if (offsetX < 40) { + // Show previous image + obj.prev(); + } + } + }; + + if ("ontouchend" in document.documentElement === true) { + el.addEventListener("touchend", mouseUp); + } else { + el.addEventListener("mouseup", mouseUp); + } + + // Add global events + el.addEventListener("swipeleft", function (e) { + obj.next(); + e.preventDefault(); + e.stopPropagation(); + }); + + el.addEventListener("swiperight", function (e) { + obj.prev(); + e.preventDefault(); + e.stopPropagation(); + }); + + el.addEventListener("keydown", function (e) { + if (e.which == 27) { + obj.close(); + } + }); + + el.slider = obj; + + return obj; + }; + + jSuites.sorting = function (el, options) { + var obj = {}; + obj.options = {}; + + var defaults = { + pointer: null, + direction: null, + ondragstart: null, + ondragend: null, + ondrop: null, + }; + + var dragElement = null; + + // Loop through the initial configuration + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + obj.options[property] = defaults[property]; + } + } + + el.classList.add("jsorting"); + + el.addEventListener("dragstart", function (e) { + var position = Array.prototype.indexOf.call( + e.target.parentNode.children, + e.target + ); + dragElement = { + element: e.target, + o: position, + d: position, + }; + e.target.style.opacity = "0.25"; + + if (typeof obj.options.ondragstart == "function") { + obj.options.ondragstart(el, e.target, e); + } + }); + + el.addEventListener("dragover", function (e) { + e.preventDefault(); + + if (getElement(e.target) && dragElement) { + if ( + e.target.getAttribute("draggable") == "true" && + dragElement.element != e.target + ) { + if (!obj.options.direction) { + var condition = e.target.clientHeight / 2 > e.offsetY; + } else { + var condition = e.target.clientWidth / 2 > e.offsetX; + } + + if (condition) { + e.target.parentNode.insertBefore(dragElement.element, e.target); + } else { + e.target.parentNode.insertBefore( + dragElement.element, + e.target.nextSibling + ); + } + + dragElement.d = Array.prototype.indexOf.call( + e.target.parentNode.children, + dragElement.element + ); + } + } + }); + + el.addEventListener("dragleave", function (e) { + e.preventDefault(); + }); + + el.addEventListener("dragend", function (e) { + e.preventDefault(); + + if (dragElement) { + if (typeof obj.options.ondragend == "function") { + obj.options.ondragend(el, dragElement.element, e); + } + + // Cancelled put element to the original position + if (dragElement.o < dragElement.d) { + e.target.parentNode.insertBefore( + dragElement.element, + e.target.parentNode.children[dragElement.o] + ); + } else { + e.target.parentNode.insertBefore( + dragElement.element, + e.target.parentNode.children[dragElement.o].nextSibling + ); + } + + dragElement.element.style.opacity = ""; + dragElement = null; + } + }); + + el.addEventListener("drop", function (e) { + e.preventDefault(); + + if (dragElement && dragElement.o != dragElement.d) { + if (typeof obj.options.ondrop == "function") { + obj.options.ondrop( + el, + dragElement.o, + dragElement.d, + dragElement.element, + e.target, + e + ); + } + } + + dragElement.element.style.opacity = ""; + dragElement = null; + }); + + var getElement = function (element) { + var sorting = false; + + function path(element) { + if (element.className) { + if (element.classList.contains("jsorting")) { + sorting = true; + } + } + + if (!sorting) { + path(element.parentNode); + } + } + + path(element); + + return sorting; + }; + + for (var i = 0; i < el.children.length; i++) { + if (!el.children[i].hasAttribute("draggable")) { + el.children[i].setAttribute("draggable", "true"); + } + } + + el.val = function () { + var id = null; + var data = []; + for (var i = 0; i < el.children.length; i++) { + if ((id = el.children[i].getAttribute("data-id"))) { + data.push(id); + } + } + return data; + }; + + return el; + }; + + jSuites.tabs = function (el, options) { + var obj = {}; + obj.options = {}; + + // Default configuration + var defaults = { + data: [], + position: null, + allowCreate: false, + allowChangePosition: false, + onclick: null, + onload: null, + onchange: null, + oncreate: null, + ondelete: null, + onbeforecreate: null, + onchangeposition: null, + animation: false, + hideHeaders: false, + padding: null, + palette: null, + maxWidth: null, + }; + + // Loop through the initial configuration + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + obj.options[property] = defaults[property]; + } + } + + // Class + el.classList.add("jtabs"); + + var prev = null; + var next = null; + var border = null; + + // Helpers + var setBorder = function (index) { + if (obj.options.animation) { + setTimeout(function () { + var rect = obj.headers.children[index].getBoundingClientRect(); + + if (obj.options.palette == "modern") { + border.style.width = rect.width - 4 + "px"; + border.style.left = + obj.headers.children[index].offsetLeft + 2 + "px"; + } else { + border.style.width = rect.width + "px"; + border.style.left = obj.headers.children[index].offsetLeft + "px"; + } + + if (obj.options.position == "bottom") { + border.style.top = "0px"; + } else { + border.style.bottom = "0px"; + } + }, 150); + } + }; + + var updateControls = function (x) { + if (typeof obj.headers.scrollTo == "function") { + obj.headers.scrollTo({ + left: x, + behavior: "smooth", + }); + } else { + obj.headers.scrollLeft = x; + } + + if (x <= 1) { + prev.classList.add("disabled"); + } else { + prev.classList.remove("disabled"); + } + + if (x >= obj.headers.scrollWidth - obj.headers.offsetWidth) { + next.classList.add("disabled"); + } else { + next.classList.remove("disabled"); + } + + if (obj.headers.scrollWidth <= obj.headers.offsetWidth) { + prev.style.display = "none"; + next.style.display = "none"; + } else { + prev.style.display = ""; + next.style.display = ""; + } + }; + + obj.setBorder = setBorder; + + // Set value + obj.open = function (index) { + var previous = null; + for (var i = 0; i < obj.headers.children.length; i++) { + if (obj.headers.children[i].classList.contains("jtabs-selected")) { + // Current one + previous = i; + } + // Remote selected + obj.headers.children[i].classList.remove("jtabs-selected"); + if (obj.content.children[i]) { + obj.content.children[i].classList.remove("jtabs-selected"); + } + } + + obj.headers.children[index].classList.add("jtabs-selected"); + if (obj.content.children[index]) { + obj.content.children[index].classList.add("jtabs-selected"); + } + + if (previous != index && typeof obj.options.onchange == "function") { + if (obj.content.children[index]) { + obj.options.onchange( + el, + obj, + index, + obj.headers.children[index], + obj.content.children[index] + ); + } + } + + // Hide + if ( + obj.options.hideHeaders == true && + obj.headers.children.length < 3 && + obj.options.allowCreate == false + ) { + obj.headers.parentNode.style.display = "none"; + } else { + // Set border + setBorder(index); + + obj.headers.parentNode.style.display = ""; + + var x1 = obj.headers.children[index].offsetLeft; + var x2 = x1 + obj.headers.children[index].offsetWidth; + var r1 = obj.headers.scrollLeft; + var r2 = r1 + obj.headers.offsetWidth; + + if (!(r1 <= x1 && r2 >= x2)) { + // Out of the viewport + updateControls(x1 - 1); + } + } + }; + + obj.selectIndex = function (a) { + var index = Array.prototype.indexOf.call(obj.headers.children, a); + if (index >= 0) { + obj.open(index); + } + + return index; + }; + + obj.rename = function (i, title) { + if (!title) { + title = prompt("New title", obj.headers.children[i].innerText); + } + obj.headers.children[i].innerText = title; + obj.open(i); + }; + + obj.create = function (title, url) { + if (typeof obj.options.onbeforecreate == "function") { + var ret = obj.options.onbeforecreate(el); + if (ret === false) { + return false; + } else { + title = ret; + } + } + + var div = obj.appendElement(title); + + if (typeof obj.options.oncreate == "function") { + obj.options.oncreate(el, div); + } + + setBorder(); + + return div; + }; + + obj.remove = function (index) { + return obj.deleteElement(index); + }; + + obj.nextNumber = function () { + var num = 0; + for (var i = 0; i < obj.headers.children.length; i++) { + var tmp = obj.headers.children[i].innerText.match(/[0-9].*/); + if (tmp > num) { + num = parseInt(tmp); + } + } + if (!num) { + num = 1; + } else { + num++; + } + + return num; + }; + + obj.deleteElement = function (index) { + if (!obj.headers.children[index]) { + return false; + } else { + obj.headers.removeChild(obj.headers.children[index]); + obj.content.removeChild(obj.content.children[index]); + } + + obj.open(0); + + if (typeof obj.options.ondelete == "function") { + obj.options.ondelete(el, index); + } + }; + + obj.appendElement = function (title, cb) { + if (!title) { + var title = prompt("Title?", ""); + } + + if (title) { + // Add content + var div = document.createElement("div"); + obj.content.appendChild(div); + + // Add headers + var h = document.createElement("div"); + h.innerHTML = title; + h.content = div; + obj.headers.insertBefore(h, obj.headers.lastChild); + + // Sortable + if (obj.options.allowChangePosition) { + h.setAttribute("draggable", "true"); + } + // Open new tab + obj.selectIndex(h); + + // Callback + if (typeof cb == "function") { + cb(div, h); + } + + // Return element + return div; + } + }; + + obj.getActive = function () { + for (var i = 0; i < obj.headers.children.length; i++) { + if (obj.headers.children[i].classList.contains("jtabs-selected")) { + return i; + } + } + return 0; + }; + + obj.updateContent = function (position, newContent) { + if (typeof newContent !== "string") { + var contentItem = newContent; + } else { + var contentItem = document.createElement("div"); + contentItem.innerHTML = newContent; + } + + if (obj.content.children[position].classList.contains("jtabs-selected")) { + newContent.classList.add("jtabs-selected"); + } + + obj.content.replaceChild(newContent, obj.content.children[position]); + + setBorder(); + }; + + obj.updatePosition = function (f, t) { + // Ondrop update position of content + if (f > t) { + obj.content.insertBefore( + obj.content.children[f], + obj.content.children[t] + ); + } else { + obj.content.insertBefore( + obj.content.children[f], + obj.content.children[t].nextSibling + ); + } + + // Open destination tab + obj.open(t); + + // Call event + if (typeof obj.options.onchangeposition == "function") { + obj.options.onchangeposition(obj.headers, f, t); + } + }; + + obj.move = function (f, t) { + if (f > t) { + obj.headers.insertBefore( + obj.headers.children[f], + obj.headers.children[t] + ); + } else { + obj.headers.insertBefore( + obj.headers.children[f], + obj.headers.children[t].nextSibling + ); + } + + obj.updatePosition(f, t); + }; + + obj.setBorder = setBorder; + + obj.init = function () { + el.innerHTML = ""; + + // Make sure the component is blank + obj.headers = document.createElement("div"); + obj.content = document.createElement("div"); + obj.headers.classList.add("jtabs-headers"); + obj.content.classList.add("jtabs-content"); + + if (obj.options.palette) { + el.classList.add("jtabs-modern"); + } else { + el.classList.remove("jtabs-modern"); + } + + // Padding + if (obj.options.padding) { + obj.content.style.padding = parseInt(obj.options.padding) + "px"; + } + + // Header + var header = document.createElement("div"); + header.className = "jtabs-headers-container"; + header.appendChild(obj.headers); + if (obj.options.maxWidth) { + header.style.maxWidth = parseInt(obj.options.maxWidth) + "px"; + } + + // Controls + var controls = document.createElement("div"); + controls.className = "jtabs-controls"; + controls.setAttribute("draggable", "false"); + header.appendChild(controls); + + // Append DOM elements + if (obj.options.position == "bottom") { + el.appendChild(obj.content); + el.appendChild(header); + } else { + el.appendChild(header); + el.appendChild(obj.content); + } + + // New button + if (obj.options.allowCreate == true) { + var add = document.createElement("div"); + add.className = "jtabs-add"; + add.onclick = function () { + obj.create(); + }; + controls.appendChild(add); + } + + prev = document.createElement("div"); + prev.className = "jtabs-prev"; + prev.onclick = function () { + updateControls(obj.headers.scrollLeft - obj.headers.offsetWidth); + }; + controls.appendChild(prev); + + next = document.createElement("div"); + next.className = "jtabs-next"; + next.onclick = function () { + updateControls(obj.headers.scrollLeft + obj.headers.offsetWidth); + }; + controls.appendChild(next); + + // Data + for (var i = 0; i < obj.options.data.length; i++) { + // Title + if (obj.options.data[i].titleElement) { + var headerItem = obj.options.data[i].titleElement; + } else { + var headerItem = document.createElement("div"); + } + // Icon + if (obj.options.data[i].icon) { + var iconContainer = document.createElement("div"); + var icon = document.createElement("i"); + icon.classList.add("material-icons"); + icon.innerHTML = obj.options.data[i].icon; + iconContainer.appendChild(icon); + headerItem.appendChild(iconContainer); + } + // Title + if (obj.options.data[i].title) { + var title = document.createTextNode(obj.options.data[i].title); + headerItem.appendChild(title); + } + // Width + if (obj.options.data[i].width) { + headerItem.style.width = obj.options.data[i].width; + } + // Content + if (obj.options.data[i].contentElement) { + var contentItem = obj.options.data[i].contentElement; + } else { + var contentItem = document.createElement("div"); + contentItem.innerHTML = obj.options.data[i].content; + } + obj.headers.appendChild(headerItem); + obj.content.appendChild(contentItem); + } + + // Animation + border = document.createElement("div"); + border.className = "jtabs-border"; + obj.headers.appendChild(border); + + if (obj.options.animation) { + el.classList.add("jtabs-animation"); + } + + // Events + obj.headers.addEventListener("click", function (e) { + if (e.target.parentNode.classList.contains("jtabs-headers")) { + var target = e.target; + } else { + if (e.target.tagName == "I") { + var target = e.target.parentNode.parentNode; + } else { + var target = e.target.parentNode; + } + } + + var index = obj.selectIndex(target); + + if (typeof obj.options.onclick == "function") { + obj.options.onclick( + el, + obj, + index, + obj.headers.children[index], + obj.content.children[index] + ); + } + }); + + obj.headers.addEventListener("contextmenu", function (e) { + obj.selectIndex(e.target); + }); + + if (obj.headers.children.length) { + // Open first tab + obj.open(0); + } + + // Update controls + updateControls(0); + + if (obj.options.allowChangePosition == true) { + jSuites.sorting(obj.headers, { + direction: 1, + ondrop: function (a, b, c) { + obj.updatePosition(b, c); + }, + }); + } + + if (typeof obj.options.onload == "function") { + obj.options.onload(el, obj); + } + }; + + // Loading existing nodes as the data + if (el.children[0] && el.children[0].children.length) { + // Create from existing elements + for (var i = 0; i < el.children[0].children.length; i++) { + var item = + obj.options.data && obj.options.data[i] ? obj.options.data[i] : {}; + + if (el.children[1] && el.children[1].children[i]) { + item.titleElement = el.children[0].children[i]; + item.contentElement = el.children[1].children[i]; + } else { + item.contentElement = el.children[0].children[i]; + } + + obj.options.data[i] = item; + } + } + + // Remote controller flag + var loadingRemoteData = false; + + // Create from data + if (obj.options.data) { + // Append children + for (var i = 0; i < obj.options.data.length; i++) { + if (obj.options.data[i].url) { + jSuites.ajax({ + url: obj.options.data[i].url, + type: "GET", + dataType: "text/html", + index: i, + success: function (result) { + obj.options.data[this.index].content = result; + }, + complete: function () { + obj.init(); + }, + }); + + // Flag loading + loadingRemoteData = true; + } + } + } + + if (!loadingRemoteData) { + obj.init(); + } + + el.tabs = obj; + + return obj; + }; + + jSuites.tags = function (el, options) { + // Redefine configuration + if (el.tags) { + return el.tags.setOptions(options, true); + } + + var obj = { type: "tags" }; + obj.options = {}; + + // Limit + var limit = function () { + return obj.options.limit && el.children.length >= obj.options.limit + ? true + : false; + }; + + // Search helpers + var search = null; + var searchContainer = null; + + obj.setOptions = function (options, reset) { + /** + * @typedef {Object} defaults + * @property {(string|Array)} value - Initial value of the compontent + * @property {number} limit - Max number of tags inside the element + * @property {string} search - The URL for suggestions + * @property {string} placeholder - The default instruction text on the element + * @property {validation} validation - Method to validate the tags + * @property {requestCallback} onbeforechange - Method to be execute before any changes on the element + * @property {requestCallback} onchange - Method to be execute after any changes on the element + * @property {requestCallback} onfocus - Method to be execute when on focus + * @property {requestCallback} onblur - Method to be execute when on blur + * @property {requestCallback} onload - Method to be execute when the element is loaded + */ + var defaults = { + value: "", + limit: null, + limitMessage: null, + search: null, + placeholder: null, + validation: null, + onbeforepaste: null, + onbeforechange: null, + onlimit: null, + onchange: null, + onfocus: null, + onblur: null, + onload: null, + colors: null, + }; + + // Loop through though the default configuration + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + if (typeof obj.options[property] == "undefined" || reset === true) { + obj.options[property] = defaults[property]; + } + } + } + + // Placeholder + if (obj.options.placeholder) { + el.setAttribute("data-placeholder", obj.options.placeholder); + } else { + el.removeAttribute("data-placeholder"); + } + el.placeholder = obj.options.placeholder; + + // Update value + obj.setValue(obj.options.value); + + // Validate items + filter(); + + // Create search box + if (obj.options.search) { + if (!searchContainer) { + searchContainer = document.createElement("div"); + el.parentNode.insertBefore(searchContainer, el.nextSibling); + + // Create container + search = jSuites.search(searchContainer, { + data: obj.options.search, + onselect: function (a, b, c) { + obj.selectIndex(b, c); + }, + }); + } + } else { + if (searchContainer) { + search = null; + searchContainer.remove(); + searchContainer = null; + } + } + + return obj; + }; + + /** + * Add a new tag to the element + * @param {(?string|Array)} value - The value of the new element + */ + obj.add = function (value, focus) { + if (typeof obj.options.onbeforechange == "function") { + var ret = obj.options.onbeforechange(el, obj, obj.options.value, value); + if (ret === false) { + return false; + } else { + if (ret != null) { + value = ret; + } + } + } + + // Make sure search is closed + if (search) { + search.close(); + } + + if (limit()) { + if (typeof obj.options.onlimit == "function") { + obj.options.onlimit(obj, obj.options.limit); + } else if (obj.options.limitMessage) { + alert(obj.options.limitMessage + " " + obj.options.limit); + } + } else { + // Get node + var node = jSuites.getNode(); + + if ( + node && + node.parentNode && + node.parentNode.classList.contains("jtags") && + node.nextSibling && + !(node.nextSibling.innerText && node.nextSibling.innerText.trim()) + ) { + div = node.nextSibling; + } else { + // Remove not used last item + if (el.lastChild) { + if (!el.lastChild.innerText.trim()) { + el.removeChild(el.lastChild); + } + } + + // Mix argument string or array + if (!value || typeof value == "string") { + var div = createElement(value, value, node); + } else { + for (var i = 0; i <= value.length; i++) { + if (!limit()) { + if (!value[i] || typeof value[i] == "string") { + var t = value[i] || ""; + var v = null; + } else { + var t = value[i].text; + var v = value[i].value; + } + + // Add element + var div = createElement(t, v); + } + } + } + + // Change + change(); + } + + // Place caret + if (focus) { + setFocus(div); + } + } + }; + + obj.setLimit = function (limit) { + obj.options.limit = limit; + var n = el.children.length - limit; + while (el.children.length > limit) { + el.removeChild(el.lastChild); + } + }; + + // Remove a item node + obj.remove = function (node) { + // Remove node + node.parentNode.removeChild(node); + // Make sure element is not blank + if (!el.children.length) { + obj.add("", true); + } else { + change(); + } + }; + + /** + * Get all tags in the element + * @return {Array} data - All tags as an array + */ + obj.getData = function () { + var data = []; + for (var i = 0; i < el.children.length; i++) { + // Get value + var text = el.children[i].innerText.replace("\n", ""); + // Get id + var value = el.children[i].getAttribute("data-value"); + if (!value) { + value = text; + } + // Item + if (text || value) { + data.push({ text: text, value: value }); + } + } + return data; + }; + + /** + * Get the value of one tag. Null for all tags + * @param {?number} index - Tag index number. Null for all tags. + * @return {string} value - All tags separated by comma + */ + obj.getValue = function (index) { + var value = null; + + if (index != null) { + // Get one individual value + value = el.children[index].getAttribute("data-value"); + if (!value) { + value = el.children[index].innerText.replace("\n", ""); + } + } else { + // Get all + var data = []; + for (var i = 0; i < el.children.length; i++) { + value = el.children[i].innerText.replace("\n", ""); + if (value) { + data.push(obj.getValue(i)); + } + } + value = data.join(","); + } + + return value; + }; + + /** + * Set the value of the element based on a string separeted by (,|;|\r\n) + * @param {mixed} value - A string or array object with values + */ + obj.setValue = function (mixed) { + if (!mixed) { + obj.reset(); + } else { + if (el.value != mixed) { + if (Array.isArray(mixed)) { + obj.add(mixed); + } else { + // Remove whitespaces + var text = ("" + mixed).trim(); + // Tags + var data = extractTags(text); + // Reset + el.innerHTML = ""; + // Add tags to the element + obj.add(data); + } + } + } + }; + + /** + * Reset the data from the element + */ + obj.reset = function () { + // Empty class + el.classList.add("jtags-empty"); + // Empty element + el.innerHTML = "
"; + // Execute changes + change(); + }; + + /** + * Verify if all tags in the element are valid + * @return {boolean} + */ + obj.isValid = function () { + var test = 0; + for (var i = 0; i < el.children.length; i++) { + if (el.children[i].classList.contains("jtags_error")) { + test++; + } + } + return test == 0 ? true : false; + }; + + /** + * Add one element from the suggestions to the element + * @param {object} item - Node element in the suggestions container + */ + obj.selectIndex = function (text, value) { + var node = jSuites.getNode(); + if (node) { + // Append text to the caret + node.innerText = text; + // Set node id + if (value) { + node.setAttribute("data-value", value); + } + // Remove any error + node.classList.remove("jtags_error"); + if (!limit()) { + // Add new item + obj.add("", true); + } + } + }; + + /** + * Search for suggestions + * @param {object} node - Target node for any suggestions + */ + obj.search = function (node) { + // Search for + var terms = node.innerText; + }; + + // Destroy tags element + obj.destroy = function () { + // Bind events + el.removeEventListener("mouseup", tagsMouseUp); + el.removeEventListener("keydown", tagsKeyDown); + el.removeEventListener("keyup", tagsKeyUp); + el.removeEventListener("paste", tagsPaste); + el.removeEventListener("focus", tagsFocus); + el.removeEventListener("blur", tagsBlur); + + // Remove element + el.parentNode.removeChild(el); + }; + + var setFocus = function (node) { + if (el.children.length > 1) { + var range = document.createRange(); + var sel = window.getSelection(); + if (!node) { + var node = el.childNodes[el.childNodes.length - 1]; + } + range.setStart(node, node.length); + range.collapse(true); + sel.removeAllRanges(); + sel.addRange(range); + el.scrollLeft = el.scrollWidth; + } + }; + + var createElement = function (label, value, node) { + var div = document.createElement("div"); + div.innerHTML = label ? label : ""; + if (value) { + div.setAttribute("data-value", value); + } + + if (node && node.parentNode.classList.contains("jtags")) { + el.insertBefore(div, node.nextSibling); + } else { + el.appendChild(div); + } + + return div; + }; + + var change = function () { + // Value + var value = obj.getValue(); + + if (value != obj.options.value) { + obj.options.value = value; + if (typeof obj.options.onchange == "function") { + obj.options.onchange(el, obj, obj.options.value); + } + + // Lemonade JS + if (el.value != obj.options.value) { + el.value = obj.options.value; + if (typeof el.oninput == "function") { + el.oninput({ + type: "input", + target: el, + value: el.value, + }); + } + } + } + + filter(); + }; + + /** + * Filter tags + */ + var filter = function () { + for (var i = 0; i < el.children.length; i++) { + // Create label design + if (!obj.getValue(i)) { + el.children[i].classList.remove("jtags_label"); + } else { + el.children[i].classList.add("jtags_label"); + + // Validation in place + if (typeof obj.options.validation == "function") { + if (obj.getValue(i)) { + if ( + !obj.options.validation( + el.children[i], + el.children[i].innerText, + el.children[i].getAttribute("data-value") + ) + ) { + el.children[i].classList.add("jtags_error"); + } else { + el.children[i].classList.remove("jtags_error"); + } + } else { + el.children[i].classList.remove("jtags_error"); + } + } else { + el.children[i].classList.remove("jtags_error"); + } + } + } + + isEmpty(); + }; + + var isEmpty = function () { + // Can't be empty + if (!el.innerText.trim()) { + el.innerHTML = "
"; + el.classList.add("jtags-empty"); + } else { + el.classList.remove("jtags-empty"); + } + }; + + /** + * Extract tags from a string + * @param {string} text - Raw string + * @return {Array} data - Array with extracted tags + */ + var extractTags = function (text) { + /** @type {Array} */ + var data = []; + + /** @type {string} */ + var word = ""; + + // Remove whitespaces + text = text.trim(); + + if (text) { + for (var i = 0; i < text.length; i++) { + if (text[i] == "," || text[i] == ";" || text[i] == "\n") { + if (word) { + data.push(word.trim()); + word = ""; + } + } else { + word += text[i]; + } + } + + if (word) { + data.push(word); + } + } + + return data; + }; + + /** @type {number} */ + var anchorOffset = 0; + + /** + * Processing event keydown on the element + * @param e {object} + */ + var tagsKeyDown = function (e) { + // Anchoroffset + anchorOffset = window.getSelection().anchorOffset; + + // Verify if is empty + isEmpty(); + + // Comma + if (e.key === "Tab" || e.key === ";" || e.key === ",") { + var n = window.getSelection().anchorOffset; + if (n > 1) { + if (limit()) { + if (typeof obj.options.onlimit == "function") { + obj.options.onlimit(obj, obj.options.limit); + } + } else { + obj.add("", true); + } + } + e.preventDefault(); + } else if (e.key == "Enter") { + if (!search || !search.isOpened()) { + var n = window.getSelection().anchorOffset; + if (n > 1) { + if (!limit()) { + obj.add("", true); + } + } + e.preventDefault(); + } + } else if (e.key == "Backspace") { + // Back space - do not let last item to be removed + if (el.children.length == 1 && window.getSelection().anchorOffset < 1) { + e.preventDefault(); + } + } + + // Search events + if (search) { + search.keydown(e); + } + }; + + /** + * Processing event keyup on the element + * @param e {object} + */ + var tagsKeyUp = function (e) { + if (e.which == 39) { + // Right arrow + var n = window.getSelection().anchorOffset; + if (n > 1 && n == anchorOffset) { + obj.add("", true); + } + } else if (e.which == 13 || e.which == 38 || e.which == 40) { + e.preventDefault(); + } else { + if (search) { + search.keyup(e); + } + } + + filter(); + }; + + /** + * Processing event paste on the element + * @param e {object} + */ + var tagsPaste = function (e) { + if (e.clipboardData || e.originalEvent.clipboardData) { + var text = (e.originalEvent || e).clipboardData.getData("text/plain"); + } else if (window.clipboardData) { + var text = window.clipboardData.getData("Text"); + } + + var data = extractTags(text); + + if (typeof obj.options.onbeforepaste == "function") { + var ret = obj.options.onbeforepaste(el, obj, data); + if (ret === false) { + e.preventDefault(); + return false; + } else { + if (ret) { + data = ret; + } + } + } + + if (data.length > 1) { + obj.add(data, true); + e.preventDefault(); + } else if (data[0]) { + document.execCommand("insertText", false, data[0]); + e.preventDefault(); + } + }; + + /** + * Processing event mouseup on the element + * @param e {object} + */ + var tagsMouseUp = function (e) { + if ( + e.target.parentNode && + e.target.parentNode.classList.contains("jtags") + ) { + if ( + e.target.classList.contains("jtags_label") || + e.target.classList.contains("jtags_error") + ) { + var rect = e.target.getBoundingClientRect(); + if (rect.width - (e.clientX - rect.left) < 16) { + obj.remove(e.target); + } + } + } + + // Set focus in the last item + if (e.target == el) { + setFocus(); + } + }; + + var tagsFocus = function () { + if (!el.classList.contains("jtags-focus")) { + if (!el.children.length || obj.getValue(el.children.length - 1)) { + if (!limit()) { + createElement(""); + } + } + + if (typeof obj.options.onfocus == "function") { + obj.options.onfocus(el, obj, obj.getValue()); + } + + el.classList.add("jtags-focus"); + } + }; + + var tagsBlur = function () { + if (el.classList.contains("jtags-focus")) { + if (search) { + search.close(); + } + + for (var i = 0; i < el.children.length - 1; i++) { + // Create label design + if (!obj.getValue(i)) { + el.removeChild(el.children[i]); + } + } + + change(); + + el.classList.remove("jtags-focus"); + + if (typeof obj.options.onblur == "function") { + obj.options.onblur(el, obj, obj.getValue()); + } + } + }; + + var init = function () { + // Bind events + if ("touchend" in document.documentElement === true) { + el.addEventListener("touchend", tagsMouseUp); + } else { + el.addEventListener("mouseup", tagsMouseUp); + } + + el.addEventListener("keydown", tagsKeyDown); + el.addEventListener("keyup", tagsKeyUp); + el.addEventListener("paste", tagsPaste); + el.addEventListener("focus", tagsFocus); + el.addEventListener("blur", tagsBlur); + + // Editable + el.setAttribute("contenteditable", true); + + // Prepare container + el.classList.add("jtags"); + + // Initial options + obj.setOptions(options); + + if (typeof obj.options.onload == "function") { + obj.options.onload(el, obj); + } + + // Change methods + el.change = obj.setValue; + + // Global generic value handler + el.val = function (val) { + if (val === undefined) { + return obj.getValue(); + } else { + obj.setValue(val); + } + }; + + el.tags = obj; + }; + + init(); + + return obj; + }; + + jSuites.toolbar = function (el, options) { + // New instance + var obj = { type: "toolbar" }; + obj.options = {}; + + // Default configuration + var defaults = { + app: null, + container: false, + badge: false, + title: false, + responsive: false, + maxWidth: null, + bottom: true, + items: [], + }; + + // Loop through our object + for (var property in defaults) { + if (options && options.hasOwnProperty(property)) { + obj.options[property] = options[property]; + } else { + obj.options[property] = defaults[property]; + } + } + + if (!el && options.app && options.app.el) { + el = document.createElement("div"); + options.app.el.appendChild(el); + } + + // Arrow + var toolbarArrow = document.createElement("div"); + toolbarArrow.classList.add("jtoolbar-item"); + toolbarArrow.classList.add("jtoolbar-arrow"); + + var toolbarFloating = document.createElement("div"); + toolbarFloating.classList.add("jtoolbar-floating"); + toolbarArrow.appendChild(toolbarFloating); + + obj.selectItem = function (element) { + var elements = toolbarContent.children; + for (var i = 0; i < elements.length; i++) { + if (element != elements[i]) { + elements[i].classList.remove("jtoolbar-selected"); + } + } + element.classList.add("jtoolbar-selected"); + }; + + obj.hide = function () { + jSuites.animation.slideBottom(el, 0, function () { + el.style.display = "none"; + }); + }; + + obj.show = function () { + el.style.display = ""; + jSuites.animation.slideBottom(el, 1); + }; + + obj.get = function () { + return el; + }; + + obj.setBadge = function (index, value) { + toolbarContent.children[index].children[1].firstChild.innerHTML = value; + }; + + obj.destroy = function () { + toolbar.remove(); + el.innerHTML = ""; + }; + + obj.update = function (a, b) { + for (var i = 0; i < toolbarContent.children.length; i++) { + // Toolbar element + var toolbarItem = toolbarContent.children[i]; + // State management + if (typeof toolbarItem.updateState == "function") { + toolbarItem.updateState(el, obj, toolbarItem, a, b); + } + } + for (var i = 0; i < toolbarFloating.children.length; i++) { + // Toolbar element + var toolbarItem = toolbarFloating.children[i]; + // State management + if (typeof toolbarItem.updateState == "function") { + toolbarItem.updateState(el, obj, toolbarItem, a, b); + } + } + }; + + obj.create = function (items) { + // Reset anything in the toolbar + toolbarContent.innerHTML = ""; + // Create elements in the toolbar + for (var i = 0; i < items.length; i++) { + var toolbarItem = document.createElement("div"); + toolbarItem.classList.add("jtoolbar-item"); + + if (items[i].width) { + toolbarItem.style.width = parseInt(items[i].width) + "px"; + } + + if (items[i].k) { + toolbarItem.k = items[i].k; + } + + if (items[i].tooltip) { + toolbarItem.setAttribute("title", items[i].tooltip); + } + + // Id + if (items[i].id) { + toolbarItem.setAttribute("id", items[i].id); + } + + // Selected + if (items[i].updateState) { + toolbarItem.updateState = items[i].updateState; + } + + if (items[i].active) { + toolbarItem.classList.add("jtoolbar-active"); + } + + if (items[i].type == "select" || items[i].type == "dropdown") { + jSuites.picker(toolbarItem, items[i]); + } else if (items[i].type == "divisor") { + toolbarItem.classList.add("jtoolbar-divisor"); + } else if (items[i].type == "label") { + toolbarItem.classList.add("jtoolbar-label"); + toolbarItem.innerHTML = items[i].content; + } else { + // Material icons + var toolbarIcon = document.createElement("i"); + if (typeof items[i].class === "undefined") { + toolbarIcon.classList.add("material-icons"); + } else { + var c = items[i].class.split(" "); + for (var j = 0; j < c.length; j++) { + toolbarIcon.classList.add(c[j]); + } + } + toolbarIcon.innerHTML = items[i].content ? items[i].content : ""; + toolbarItem.appendChild(toolbarIcon); + + // Badge options + if (obj.options.badge == true) { + var toolbarBadge = document.createElement("div"); + toolbarBadge.classList.add("jbadge"); + var toolbarBadgeContent = document.createElement("div"); + toolbarBadgeContent.innerHTML = items[i].badge + ? items[i].badge + : ""; + toolbarBadge.appendChild(toolbarBadgeContent); + toolbarItem.appendChild(toolbarBadge); + } + + // Title + if (items[i].title) { + if (obj.options.title == true) { + var toolbarTitle = document.createElement("span"); + toolbarTitle.innerHTML = items[i].title; + toolbarItem.appendChild(toolbarTitle); + } else { + toolbarItem.setAttribute("title", items[i].title); + } + } + + if (obj.options.app && items[i].route) { + // Route + toolbarItem.route = items[i].route; + // Onclick for route + toolbarItem.onclick = function () { + obj.options.app.pages(this.route); + }; + // Create pages + obj.options.app.pages(items[i].route, { + toolbarItem: toolbarItem, + closed: true, + }); + } + } + + if (items[i].onclick) { + toolbarItem.onclick = items[i].onclick.bind( + items[i], + el, + obj, + toolbarItem + ); + } + + toolbarContent.appendChild(toolbarItem); + } + + // Fits to the page + setTimeout(function () { + obj.refresh(); + }, 0); + }; + + obj.open = function () { + toolbarArrow.classList.add("jtoolbar-arrow-selected"); + + var rectElement = el.getBoundingClientRect(); + var rect = toolbarFloating.getBoundingClientRect(); + if (rect.bottom > window.innerHeight || obj.options.bottom) { + toolbarFloating.style.bottom = "0"; + } else { + toolbarFloating.style.removeProperty("bottom"); + } + + toolbarFloating.style.right = "0"; + + toolbarArrow.children[0].focus(); + // Start tracking + jSuites.tracking(obj, true); + }; + + obj.close = function () { + toolbarArrow.classList.remove("jtoolbar-arrow-selected"); + // End tracking + jSuites.tracking(obj, false); + }; + + obj.refresh = function () { + if (obj.options.responsive == true) { + // Width of the c + var rect = el.parentNode.getBoundingClientRect(); + if (!obj.options.maxWidth) { + obj.options.maxWidth = rect.width; + } + // Available parent space + var available = parseInt(obj.options.maxWidth); + // Remove arrow + if (toolbarArrow.parentNode) { + toolbarArrow.parentNode.removeChild(toolbarArrow); + } + // Move all items to the toolbar + while (toolbarFloating.firstChild) { + toolbarContent.appendChild(toolbarFloating.firstChild); + } + // Toolbar is larger than the parent, move elements to the floating element + if (available < toolbarContent.offsetWidth) { + // Give space to the floating element + available -= 50; + // Move to the floating option + while ( + toolbarContent.lastChild && + available < toolbarContent.offsetWidth + ) { + toolbarFloating.insertBefore( + toolbarContent.lastChild, + toolbarFloating.firstChild + ); + } + } + // Show arrow + if (toolbarFloating.children.length > 0) { + toolbarContent.appendChild(toolbarArrow); + } + } + }; + + obj.setReadonly = function (state) { + state = state ? "add" : "remove"; + el.classList[state]("jtoolbar-readonly"); + }; + + el.onclick = function (e) { + var element = jSuites.findElement(e.target, "jtoolbar-item"); + if (element) { + obj.selectItem(element); + } + + if (e.target.classList.contains("jtoolbar-arrow")) { + obj.open(); + } + }; + + window.addEventListener("resize", function () { + obj.refresh(); + }); + + // Toolbar + el.classList.add("jtoolbar"); + // Reset content + el.innerHTML = ""; + // Container + if (obj.options.container == true) { + el.classList.add("jtoolbar-container"); + } + // Content + var toolbarContent = document.createElement("div"); + el.appendChild(toolbarContent); + // Special toolbar for mobile applications + if (obj.options.app) { + el.classList.add("jtoolbar-mobile"); + } + // Create toolbar + obj.create(obj.options.items); + // Shortcut + el.toolbar = obj; + + return obj; + }; + + jSuites.validations = (function () { + /** + * Options: Object, + * Properties: + * Constraint, + * Reference, + * Value + */ + + var isNumeric = function (num) { + return !isNaN(num) && num !== null && num !== ""; + }; + + var numberCriterias = { + between: function (value, range) { + return value >= range[0] && value <= range[1]; + }, + "not between": function (value, range) { + return value < range[0] || value > range[1]; + }, + "<": function (value, range) { + return value < range[0]; + }, + "<=": function (value, range) { + return value <= range[0]; + }, + ">": function (value, range) { + return value > range[0]; + }, + ">=": function (value, range) { + return value >= range[0]; + }, + "=": function (value, range) { + return value == range[0]; + }, + "!=": function (value, range) { + return value != range[0]; + }, + }; + + var dateCriterias = { + "valid date": function () { + return true; + }, + "=": function (value, range) { + return value === range[0]; + }, + "<": function (value, range) { + return value < range[0]; + }, + "<=": function (value, range) { + return value <= range[0]; + }, + ">": function (value, range) { + return value > range[0]; + }, + ">=": function (value, range) { + return value >= range[0]; + }, + between: function (value, range) { + return value >= range[0] && value <= range[1]; + }, + "not between": function (value, range) { + return value < range[0] || value > range[1]; + }, + }; + + var textCriterias = { + contains: function (value, range) { + return value.includes(range[0]); + }, + "not contains": function (value, range) { + return !value.includes(range[0]); + }, + "begins with": function (value, range) { + return value.startsWith(range[0]); + }, + "ends with": function (value, range) { + return value.endsWith(range[0]); + }, + "=": function (value, range) { + return value === range[0]; + }, + "valid email": function (value) { + var pattern = new RegExp(/^[^\s@]+@[^\s@]+\.[^\s@]+$/); + + return pattern.test(value); + }, + "valid url": function (value) { + var pattern = new RegExp( + /(((https?:\/\/)|(www\.))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]+)/gi + ); + + return pattern.test(value); + }, + }; + + // Component router + var component = function (value, options) { + if (typeof component[options.type] === "function") { + if (options.allowBlank && value === "") { + return true; + } + + return component[options.type](value, options); + } + return null; + }; + + component.url = function () { + var pattern = new RegExp( + /(((https?:\/\/)|(www\.))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]+)/gi + ); + return pattern.test(data) ? true : false; + }; + + component.email = function (data) { + var pattern = new RegExp(/^[^\s@]+@[^\s@]+\.[^\s@]+$/); + return data && pattern.test(data) ? true : false; + }; + + component.required = function (data) { + return data.trim() ? true : false; + }; + + component.exist = function (data, options) { + return !!data.toString(); + }; + + component["not exist"] = function (data, options) { + return !data.toString(); + }; + + component.number = function (data, options) { + if (!isNumeric(data)) { + return false; + } + + if (!options || !options.criteria) { + return true; + } + + if (!numberCriterias[options.criteria]) { + return false; + } + + var values = options.value.map(function (num) { + return parseFloat(num); + }); + + return numberCriterias[options.criteria](data, values); + }; + + component.login = function (data) { + var pattern = new RegExp(/^[a-zA-Z0-9\_\-\.\s+]+$/); + return data && pattern.test(data) ? true : false; + }; + + component.list = function (data, options) { + var dataType = typeof data; + if (dataType !== "string" && dataType !== "number") { + return false; + } + if (typeof options.value[0] === "string") { + var list = options.value[0].split(","); + } else { + var list = options.value[0]; + } + + var validOption = list.findIndex(function name(item) { + return item == data; + }); + + return validOption > -1; + }; + + component.date = function (data, options) { + if (new Date(data) == "Invalid Date") { + return false; + } + + if (!options || !options.criteria) { + return true; + } + + if (!dateCriterias[options.criteria]) { + return false; + } + + var values = options.value.map(function (date) { + return new Date(date).getTime(); + }); + + return dateCriterias[options.criteria](new Date(data).getTime(), values); + }; + + component.text = function (data, options) { + if (typeof data !== "string") { + return false; + } + + if (!options || !options.criteria) { + return true; + } + + if (!textCriterias[options.criteria]) { + return false; + } + + return textCriterias[options.criteria](data, options.value); + }; + + component.textLength = function (data, options) { + data = data.toString(); + + return component.number(data.length, options); + }; + + return component; + })(); + + return jSuites; +}); diff --git a/javascripts/discourse/components/spreadsheet-editor.js b/javascripts/discourse/components/spreadsheet-editor.js index 736a1c2..c8bd7ec 100644 --- a/javascripts/discourse/components/spreadsheet-editor.js +++ b/javascripts/discourse/components/spreadsheet-editor.js @@ -13,11 +13,17 @@ export default Component.extend({ // ? TODO move to component (read about not allowing Controllers to do DOM manipulation) this._super(...arguments); - loadScript(settings.theme_uploads.jspreadsheet).then(() => { + this.loadLibraries().then(() => { this.buildTable(this.tableHtml); }); }, + loadLibraries() { + return loadScript(settings.theme_uploads.jsuites).then(() => { + return loadScript(settings.theme_uploads.jspreadsheet); + }); + }, + buildTable(table) { const tableObject = tableToObj(table); const headings = []; @@ -41,6 +47,7 @@ export default Component.extend({ const spreadsheetContainer = document.querySelector("#spreadsheet"); + // eslint-disable-next-line no-undef this.spreadsheet = jspreadsheet(spreadsheetContainer, { data: tableData, columns,