From e7de04494b70ca62ac1abda7f9a3ef41994f4f51 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 14 Oct 2021 16:59:23 +0200 Subject: Adding web-tools (WIP). Signed-off-by: Daniel Baumann --- web-tools/web/_static/jsuites/jsuites.layout.js | 1491 +++++++++++++++++++++++ 1 file changed, 1491 insertions(+) create mode 100644 web-tools/web/_static/jsuites/jsuites.layout.js (limited to 'web-tools/web/_static/jsuites/jsuites.layout.js') diff --git a/web-tools/web/_static/jsuites/jsuites.layout.js b/web-tools/web/_static/jsuites/jsuites.layout.js new file mode 100644 index 0000000..ad5c23d --- /dev/null +++ b/web-tools/web/_static/jsuites/jsuites.layout.js @@ -0,0 +1,1491 @@ +jSuites.login = (function(el, options) { + var obj = {}; + obj.options = {}; + + // Default configuration + var defaults = { + url: window.location.href, + prepareRequest: null, + accessToken: null, + deviceToken: null, + facebookUrl: null, + facebookAuthentication: null, + maxHeight: null, + onload: null, + onsuccess: null, + onerror: null, + message: null, + logo: null, + newProfile: false, + newProfileUrl: false, + newProfileLogin: false, + fullscreen: false, + newPasswordValidation: 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]; + } + } + + // Message console container + if (! obj.options.message) { + var messageElement = document.querySelector('.message'); + if (messageElement) { + obj.options.message = messageElement; + } + } + + // Action + var action = null; + + // Container + var container = document.createElement('form'); + el.appendChild(container); + + // Logo + var divLogo = document.createElement('div'); + divLogo.className = 'jlogin-logo' + container.appendChild(divLogo); + + if (obj.options.logo) { + var logo = document.createElement('img'); + logo.src = obj.options.logo; + divLogo.appendChild(logo); + } + + // Code + var labelCode = document.createElement('label'); + labelCode.innerHTML = 'Please enter here the code received'; + var inputCode = document.createElement('input'); + inputCode.type = 'number'; + inputCode.id = 'code'; + inputCode.setAttribute('maxlength', 6); + var divCode = document.createElement('div'); + divCode.appendChild(labelCode); + divCode.appendChild(inputCode); + + // Hash + var inputHash = document.createElement('input'); + inputHash.type = 'hidden'; + inputHash.name = 'h'; + var divHash = document.createElement('div'); + divHash.appendChild(inputHash); + + // Recovery + var inputRecovery = document.createElement('input'); + inputRecovery.type = 'hidden'; + inputRecovery.name = 'recovery'; + inputRecovery.value = '1'; + var divRecovery = document.createElement('div'); + divRecovery.appendChild(inputRecovery); + + // Login + var labelLogin = document.createElement('label'); + labelLogin.innerHTML = 'Login'; + var inputLogin = document.createElement('input'); + inputLogin.type = 'text'; + inputLogin.name = 'login'; + inputLogin.setAttribute('autocomplete', 'off'); + inputLogin.onkeyup = function() { + this.value = this.value.toLowerCase().replace(/[^a-zA-Z0-9_+]+/gi, ''); + } + var divLogin = document.createElement('div'); + divLogin.appendChild(labelLogin); + divLogin.appendChild(inputLogin); + + // Name + var labelName = document.createElement('label'); + labelName.innerHTML = 'Name'; + var inputName = document.createElement('input'); + inputName.type = 'text'; + inputName.name = 'name'; + var divName = document.createElement('div'); + divName.appendChild(labelName); + divName.appendChild(inputName); + + // Email + var labelUsername = document.createElement('label'); + labelUsername.innerHTML = 'E-mail'; + var inputUsername = document.createElement('input'); + inputUsername.type = 'text'; + inputUsername.name = 'username'; + inputUsername.setAttribute('autocomplete', 'new-username'); + var divUsername = document.createElement('div'); + divUsername.appendChild(labelUsername); + divUsername.appendChild(inputUsername); + + // Password + var labelPassword = document.createElement('label'); + labelPassword.innerHTML = 'Password'; + var inputPassword = document.createElement('input'); + inputPassword.type = 'password'; + inputPassword.name = 'password'; + inputPassword.setAttribute('autocomplete', 'new-password'); + var divPassword = document.createElement('div'); + divPassword.appendChild(labelPassword); + divPassword.appendChild(inputPassword); + divPassword.onkeydown = function(e) { + if (e.keyCode == 13) { + obj.execute(); + } + } + + // Repeat password + var labelRepeatPassword = document.createElement('label'); + labelRepeatPassword.innerHTML = 'Repeat the new password'; + var inputRepeatPassword = document.createElement('input'); + inputRepeatPassword.type = 'password'; + inputRepeatPassword.name = 'password'; + var divRepeatPassword = document.createElement('div'); + divRepeatPassword.appendChild(labelRepeatPassword); + divRepeatPassword.appendChild(inputRepeatPassword); + + // Remember checkbox + var labelRemember = document.createElement('label'); + labelRemember.innerHTML = 'Remember me on this device'; + var inputRemember = document.createElement('input'); + inputRemember.type = 'checkbox'; + inputRemember.name = 'remember'; + inputRemember.value = '1'; + labelRemember.appendChild(inputRemember); + var divRememberButton = document.createElement('div'); + divRememberButton.className = 'rememberButton'; + divRememberButton.appendChild(labelRemember); + + // Login button + var actionButton = document.createElement('input'); + actionButton.type = 'button'; + actionButton.value = 'Log In'; + actionButton.onclick = function() { + obj.execute(); + } + var divActionButton = document.createElement('div'); + divActionButton.appendChild(actionButton); + + // Cancel button + var cancelButton = document.createElement('div'); + cancelButton.innerHTML = 'Cancel'; + cancelButton.className = 'cancelButton'; + cancelButton.onclick = function() { + obj.requestAccess(); + } + var divCancelButton = document.createElement('div'); + divCancelButton.appendChild(cancelButton); + + // Captcha + var labelCaptcha = document.createElement('label'); + labelCaptcha.innerHTML = 'Please type here the code below'; + var inputCaptcha = document.createElement('input'); + inputCaptcha.type = 'text'; + inputCaptcha.name = 'captcha'; + var imageCaptcha = document.createElement('img'); + var divCaptcha = document.createElement('div'); + divCaptcha.className = 'jlogin-captcha'; + divCaptcha.appendChild(labelCaptcha); + divCaptcha.appendChild(inputCaptcha); + divCaptcha.appendChild(imageCaptcha); + + // Facebook + var facebookButton = document.createElement('div'); + facebookButton.innerHTML = 'Login with Facebook'; + facebookButton.className = 'facebookButton'; + var divFacebookButton = document.createElement('div'); + divFacebookButton.appendChild(facebookButton); + divFacebookButton.onclick = function() { + obj.requestLoginViaFacebook(); + } + // Forgot password + var inputRequest = document.createElement('span'); + inputRequest.innerHTML = 'Request a new password'; + var divRequestButton = document.createElement('div'); + divRequestButton.className = 'requestButton'; + divRequestButton.appendChild(inputRequest); + divRequestButton.onclick = function() { + obj.requestNewPassword(); + } + // Create a new Profile + var inputNewProfile = document.createElement('span'); + inputNewProfile.innerHTML = 'Create a new profile'; + var divNewProfileButton = document.createElement('div'); + divNewProfileButton.className = 'newProfileButton'; + divNewProfileButton.appendChild(inputNewProfile); + divNewProfileButton.onclick = function() { + obj.newProfile(); + } + + el.className = 'jlogin'; + + if (obj.options.fullscreen == true) { + el.classList.add('jlogin-fullscreen'); + } + + /** + * Show message + */ + obj.showMessage = function(data) { + var message = (typeof(data) == 'object') ? data.message : data; + + if (typeof(obj.options.showMessage) == 'function') { + obj.options.showMessage(data); + } else { + jSuites.alert(data); + } + } + + /** + * New profile + */ + obj.newProfile = function() { + container.innerHTML = ''; + container.appendChild(divLogo); + if (obj.options.newProfileLogin) { + container.appendChild(divLogin); + } + container.appendChild(divName); + container.appendChild(divUsername); + container.appendChild(divActionButton); + if (obj.options.facebookAuthentication == true) { + container.appendChild(divFacebookButton); + } + container.appendChild(divCancelButton); + + // Reset inputs + inputLogin.value = ''; + inputUsername.value = ''; + inputPassword.value = ''; + + // Button + actionButton.value = 'Create new profile'; + + // Action + action = 'newProfile'; + } + + /** + * Request the email with the recovery instructions + */ + obj.requestNewPassword = function() { + if (Array.prototype.indexOf.call(container.children, divCaptcha) >= 0) { + var captcha = true; + } + + container.innerHTML = ''; + container.appendChild(divLogo); + container.appendChild(divRecovery); + container.appendChild(divUsername); + if (captcha) { + container.appendChild(divCaptcha); + } + container.appendChild(divActionButton); + container.appendChild(divCancelButton); + actionButton.value = 'Request a new password'; + inputRecovery.value = 1; + + // Action + action = 'requestNewPassword'; + } + + /** + * Confirm recovery code + */ + obj.codeConfirmation = function() { + container.innerHTML = ''; + container.appendChild(divLogo); + container.appendChild(divHash); + container.appendChild(divCode); + container.appendChild(divActionButton); + container.appendChild(divCancelButton); + actionButton.value = 'Confirm code'; + inputRecovery.value = 2; + + // Action + action = 'codeConfirmation'; + } + + /** + * Update my password + */ + obj.changeMyPassword = function(hash) { + container.innerHTML = ''; + container.appendChild(divLogo); + container.appendChild(divHash); + container.appendChild(divPassword); + container.appendChild(divRepeatPassword); + container.appendChild(divActionButton); + container.appendChild(divCancelButton); + actionButton.value = 'Change my password'; + inputHash.value = hash; + + // Action + action = 'changeMyPassword'; + } + + /** + * Request access default method + */ + obj.requestAccess = function() { + container.innerHTML = ''; + container.appendChild(divLogo); + container.appendChild(divUsername); + container.appendChild(divPassword); + container.appendChild(divActionButton); + if (obj.options.facebookAuthentication == true) { + container.appendChild(divFacebookButton); + } + container.appendChild(divRequestButton); + container.appendChild(divRememberButton); + container.appendChild(divRequestButton); + if (obj.options.newProfile == true) { + container.appendChild(divNewProfileButton); + } + + // Button + actionButton.value = 'Login'; + + // Password + inputPassword.value = ''; + + // Email persistence + if (window.localStorage.getItem('username')) { + inputUsername.value = window.localStorage.getItem('username'); + inputPassword.focus(); + } else { + inputUsername.focus(); + } + + // Action + action = 'requestAccess'; + } + + /** + * Request login via facebook + */ + obj.requestLoginViaFacebook = function() { + if (typeof(deviceNotificationToken) == 'undefined') { + FB.getLoginStatus(function(response) { + if (! response.status || response.status != 'connected') { + FB.login(function(response) { + if (response.authResponse) { + obj.execute({ f:response.authResponse.accessToken }); + } else { + obj.showMessage('Not authorized by facebook'); + } + }, {scope: 'public_profile,email'}); + } else { + obj.execute({ f:response.authResponse.accessToken }); + } + }, true); + } else { + jDestroy = function() { + fbLogin.removeEventListener('loadstart', jStart); + fbLogin.removeEventListener('loaderror', jError); + fbLogin.removeEventListener('exit', jExit); + fbLogin.close(); + fbLogin = null; + } + + jStart = function(event) { + var url = event.url; + if (url.indexOf("access_token") >= 0) { + setTimeout(function(){ + var u = url.match(/=(.*?)&/); + if (u[1].length > 32) { + obj.execute({ f:u[1] }); + } + jDestroy(); + },500); + } + + if (url.indexOf("error=access_denied") >= 0) { + setTimeout(jDestroy ,500); + // Not authorized by facebook + obj.showMessage('Not authorized by facebook'); + } + } + + jError = function(event) { + jDestroy(); + } + + jExit = function(event) { + jDestroy(); + } + + fbLogin = window.open(obj.options.facebookUrl, "_blank", "location=no,closebuttoncaption=Exit,disallowoverscroll=yes,toolbar=no"); + fbLogin.addEventListener('loadstart', jStart); + fbLogin.addEventListener('loaderror', jError); + fbLogin.addEventListener('exit', jExit); + } + + // Action + action = 'requestLoginViaFacebook'; + } + + // Perform request + obj.execute = function(data) { + // New profile + if (action == 'newProfile') { + var pattern = new RegExp(/^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/); + if (! inputUsername.value || ! pattern.test(inputUsername.value)) { + var message = 'Invalid e-mail address'; + } + + var pattern = new RegExp(/^[a-zA-Z0-9\_\-\.\s+]+$/); + if (! inputLogin.value || ! pattern.test(inputLogin.value)) { + var message = 'Invalid username, please use only characters and numbers'; + } + + if (message) { + obj.showMessage(message); + return false; + } + } else if (action == 'changeMyPassword') { + if (inputPassword.value.length < 3) { + var message = 'Password is too short'; + } else if (inputPassword.value != inputRepeatPassword.value) { + var message = 'Password should match'; + } else { + if (typeof(obj.options.newPasswordValidation) == 'function') { + var val = obj.options.newPasswordValidation(obj, inputPassword.value, inputPassword.value); + if (val != undefined) { + message = val; + } + } + } + + if (message) { + obj.showMessage(message); + return false; + } + } + + // Keep email + if (inputUsername.value != '') { + window.localStorage.setItem('username', inputUsername.value); + } + + // Captcha + if (Array.prototype.indexOf.call(container.children, divCaptcha) >= 0) { + if (inputCaptcha.value == '') { + obj.showMessage('Please enter the captch code below'); + return false; + } + } + + // Url + var url = obj.options.url; + + // Device token + if (obj.options.deviceToken) { + url += '?token=' + obj.options.deviceToken; + } + + // Callback + var onsuccess = function(result) { + if (result) { + // Successfully response + if (result.success == 1) { + // Recovery process + if (action == 'requestNewPassword') { + obj.codeConfirmation(); + } else if (action == 'codeConfirmation') { + obj.requestAccess(); + } else if (action == 'newProfile') { + obj.requestAccess(); + // New profile + result.newProfile = true; + } + + // Token + if (result.token) { + // Set token + obj.options.accessToken = result.token; + // Save token + window.localStorage.setItem('Access-Token', result.token); + } + } + + // Show message + if (result.message) { + // Show message + obj.showMessage(result.message) + } + + // Request captcha code + if (! result.data) { + if (Array.prototype.indexOf.call(container.children, divCaptcha) >= 0) { + divCaptcha.remove(); + } + } else { + container.insertBefore(divCaptcha, divActionButton); + imageCaptcha.setAttribute('src', 'data:image/png;base64,' + result.data); + } + + // Give time to user see the message + if (result.hash) { + // Change password + obj.changeMyPassword(result.hash); + } else if (result.url) { + // App initialization + if (result.success == 1) { + if (typeof(obj.options.onsuccess) == 'function') { + obj.options.onsuccess(result); + } else { + if (result.message) { + setTimeout(function() { window.location.href = result.url; }, 2000); + } else { + window.location.href = result.url; + } + } + } else { + if (typeof(obj.options.onerror) == 'function') { + obj.options.onerror(result); + } + } + } + } + } + + // Password + if (! data) { + var data = jSuites.form.getElements(el, true); + // Encode passworfd + if (data.password) { + data.password = jSuites.sha512(data.password); + } + // Recovery code + if (Array.prototype.indexOf.call(container.children, divCode) >= 0 && inputCode.value) { + data.h = jSuites.sha512(inputCode.value); + } + } + + // Loading + el.classList.add('jlogin-loading'); + + // Url + var url = (action == 'newProfile' && obj.options.newProfileUrl) ? obj.options.newProfileUrl : obj.options.url; + + // Remote call + jSuites.ajax({ + url: url, + method: 'POST', + dataType: 'json', + data: data, + success: function(result) { + // Remove loading + el.classList.remove('jlogin-loading'); + // Callback + onsuccess(result); + }, + error: function(result) { + // Error + el.classList.remove('jlogin-loading'); + + if (typeof(obj.options.onerror) == 'function') { + obj.options.onerror(result); + } + } + }); + } + + var queryString = window.location.href.split('?'); + if (queryString[1] && queryString[1].length == 130 && queryString[1].substr(0,2) == 'h=') { + obj.changeMyPassword(queryString[1].substr(2)); + } else { + obj.requestAccess(); + } + + return obj; +}); + +jSuites.login.sha512 = jSuites.sha512; + +/** + * (c) jSuites template renderer + * https://github.com/paulhodel/jsuites + * + * @author: Paul Hodel + * @description: Template renderer + */ + +jSuites.template = (function(el, options) { + var obj = {}; + obj.options = {}; + + // Default configuration + var defaults = { + url: null, + data: null, + filter: null, + pageNumber: 0, + numberOfPages: 0, + template: null, + render: null, + noRecordsFound: 'No records found', + // Searchable + search: null, + searchInput: true, + searchPlaceHolder: '', + searchValue: '', + // Remote search + remoteData: null, + // Pagination page number of items + pagination: null, + onload: null, + onchange: null, + onsearch: 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]; + } + } + + // Reset content + el.innerHTML = ''; + + // Input search + if (obj.options.search && obj.options.searchInput == true) { + // Timer + var searchTimer = null; + + // Search container + var searchContainer = document.createElement('div'); + searchContainer.className = 'jtemplate-results'; + obj.searchInput = document.createElement('input'); + obj.searchInput.value = obj.options.searchValue; + obj.searchInput.onkeyup = function(e) { + // Clear current trigger + if (searchTimer) { + clearTimeout(searchTimer); + } + // Prepare search + searchTimer = setTimeout(function() { + obj.search(obj.searchInput.value.toLowerCase()); + searchTimer = null; + }, 300) + } + searchContainer.appendChild(obj.searchInput); + el.appendChild(searchContainer); + + if (obj.options.searchPlaceHolder) { + obj.searchInput.setAttribute('placeholder', obj.options.searchPlaceHolder); + } + } + + // Pagination container + if (obj.options.pagination) { + var pagination = document.createElement('div'); + pagination.className = 'jtemplate-pagination'; + el.appendChild(pagination); + } + + // Content + var container = document.createElement('div'); + container.className = 'jtemplate-content options'; + el.appendChild(container); + + // Data container + var searchResults = null; + + obj.updatePagination = function() { + // Reset pagination container + if (pagination) { + pagination.innerHTML = ''; + } + + // Create pagination + if (obj.options.pagination > 0 && obj.options.numberOfPages > 1) { + // Number of pages + var numberOfPages = obj.options.numberOfPages; + + // Controllers + if (obj.options.pageNumber < 6) { + var startNumber = 1; + var finalNumber = numberOfPages < 10 ? numberOfPages : 10; + } else if (numberOfPages - obj.options.pageNumber < 5) { + var startNumber = numberOfPages - 9; + var finalNumber = numberOfPages; + if (startNumber < 1) { + startNumber = 1; + } + } else { + var startNumber = obj.options.pageNumber - 4; + var finalNumber = obj.options.pageNumber + 5; + } + + // First + if (startNumber > 1) { + var paginationItem = document.createElement('div'); + paginationItem.innerHTML = '<'; + paginationItem.title = 1; + pagination.appendChild(paginationItem); + } + + // Get page links + for (var i = startNumber; i <= finalNumber; i++) { + var paginationItem = document.createElement('div'); + paginationItem.innerHTML = i; + pagination.appendChild(paginationItem); + + if (obj.options.pageNumber == i - 1) { + paginationItem.style.fontWeight = 'bold'; + } + } + + // Last + if (finalNumber < numberOfPages) { + var paginationItem = document.createElement('div'); + paginationItem.innerHTML = '>'; + paginationItem.title = numberOfPages - 1; + pagination.appendChild(paginationItem); + } + } + } + + /** + * Append data to the template and add to the DOMContainer + * @param data + * @param contentDOMContainer + */ + obj.setContent = function(a, b) { + var c = obj.options.template[Object.keys(obj.options.template)[0]](a); + if ((c instanceof Element || c instanceof HTMLDocument)) { + b.appendChild(c); + } else { + b.innerHTML = c; + } + } + + obj.addItem = function(data, beginOfDataSet) { + // Append itens + var content = document.createElement('div'); + // Append data + if (beginOfDataSet) { + obj.options.data.unshift(data); + } else { + obj.options.data.push(data); + } + // If is empty remove indication + if (container.classList.contains('jtemplate-empty')) { + container.classList.remove('jtemplate-empty'); + container.innerHTML = ''; + } + // Get content + obj.setContent(data, content); + // Add animation + jSuites.animation.fadeIn(content.children[0]); + // Add and do the animation + if (beginOfDataSet) { + container.prepend(content.children[0]); + } else { + container.append(content.children[0]); + } + // Onchange method + if (typeof(obj.options.onchange) == 'function') { + obj.options.onchange(el, obj.options.data); + } + } + + obj.removeItem = function(element) { + if (Array.prototype.indexOf.call(container.children, element) > -1) { + // Remove data from array + var index = obj.options.data.indexOf(element.dataReference); + if (index > -1) { + obj.options.data.splice(index, 1); + } + // Remove element from DOM + jSuites.animation.fadeOut(element, function() { + element.parentNode.removeChild(element); + + if (! container.innerHTML) { + container.classList.add('jtemplate-empty'); + container.innerHTML = obj.options.noRecordsFound; + } + }); + } else { + console.error('Element not found'); + } + } + + obj.setData = function(data) { + if (data) { + obj.options.pageNumber = 1; + obj.options.searchValue = ''; + // Set data + obj.options.data = data; + // Reset any search results + searchResults = null; + + // Render new data + obj.render(); + + // Onchange method + if (typeof(obj.options.onchange) == 'function') { + obj.options.onchange(el, obj.options.data); + } + } + } + + obj.appendData = function(data, pageNumber) { + if (pageNumber) { + obj.options.pageNumber = pageNumber; + } + + var execute = function(data) { + // Concat data + obj.options.data.concat(data); + // Number of pages + if (obj.options.pagination > 0) { + obj.options.numberOfPages = Math.ceil(obj.options.data.length / obj.options.pagination); + } + var startNumber = 0; + var finalNumber = data.length; + // Append itens + var content = document.createElement('div'); + for (var i = startNumber; i < finalNumber; i++) { + obj.setContent(data[i], content) + content.children[0].dataReference = data[i]; // TODO: data[i] or i? + container.appendChild(content.children[0]); + } + } + + if (obj.options.url && obj.options.remoteData == true) { + // URL + var url = obj.options.url; + // Data + var ajaxData = {}; + // Options for backend search + if (obj.options.remoteData) { + // Search value + if (obj.options.searchValue) { + ajaxData.q = obj.options.searchValue; + } + // Page number + if (obj.options.pageNumber) { + ajaxData.p = obj.options.pageNumber; + } + // Number items per page + if (obj.options.pagination) { + ajaxData.t = obj.options.pagination; + } + } + // Remote loading + jSuites.ajax({ + url: url, + method: 'GET', + data: ajaxData, + dataType: 'json', + success: function(data) { + execute(data); + } + }); + } else { + if (! obj.options.data) { + console.log('TEMPLATE: no data or external url defined'); + } else { + execute(data); + } + } + } + + obj.renderTemplate = function() { + // Data container + var data = searchResults ? searchResults : obj.options.data; + + // Reset pagination + obj.updatePagination(); + + if (! data.length) { + container.innerHTML = obj.options.noRecordsFound; + container.classList.add('jtemplate-empty'); + } else { + // Reset content + container.classList.remove('jtemplate-empty'); + + // Create pagination + if (obj.options.pagination && data.length > obj.options.pagination) { + var startNumber = (obj.options.pagination * obj.options.pageNumber); + var finalNumber = (obj.options.pagination * obj.options.pageNumber) + obj.options.pagination; + + if (data.length < finalNumber) { + var finalNumber = data.length; + } + } else { + var startNumber = 0; + var finalNumber = data.length; + } + + // Append itens + var content = document.createElement('div'); + for (var i = startNumber; i < finalNumber; i++) { + // Get content + obj.setContent(data[i], content); + content.children[0].dataReference = data[i]; + container.appendChild(content.children[0]); + } + } + } + + obj.render = function(pageNumber, forceLoad) { + // Update page number + if (pageNumber != undefined) { + obj.options.pageNumber = pageNumber; + } else { + if (! obj.options.pageNumber && obj.options.pagination > 0) { + obj.options.pageNumber = 0; + } + } + + // Render data into template + var execute = function() { + // Render new content + if (typeof(obj.options.render) == 'function') { + container.innerHTML = obj.options.render(obj); + } else { + container.innerHTML = ''; + } + + // Load data + obj.renderTemplate(); + + // Onload + if (typeof(obj.options.onload) == 'function') { + obj.options.onload(el, obj); + } + } + + if (obj.options.url && (obj.options.remoteData == true || forceLoad)) { + // URL + var url = obj.options.url; + // Data + var ajaxData = {}; + // Options for backend search + if (obj.options.remoteData) { + // Search value + if (obj.options.searchValue) { + ajaxData.q = obj.options.searchValue; + } + // Page number + if (obj.options.pageNumber) { + ajaxData.p = obj.options.pageNumber; + } + // Number items per page + if (obj.options.pagination) { + ajaxData.t = obj.options.pagination; + } + } + // Remote loading + jSuites.ajax({ + url: url, + method: 'GET', + dataType: 'json', + data: ajaxData, + success: function(data) { + // Search and keep data in the client side + if (data.hasOwnProperty("total")) { + obj.options.numberOfPages = Math.ceil(data.total / obj.options.pagination); + obj.options.data = data.data; + } else { + // Number of pages + if (obj.options.pagination > 0) { + obj.options.numberOfPages = Math.ceil(data.length / obj.options.pagination); + } + obj.options.data = data; + } + + // Load data for the user + execute(); + } + }); + } else { + if (! obj.options.data) { + console.log('TEMPLATE: no data or external url defined'); + } else { + // Number of pages + if (obj.options.pagination > 0) { + if (searchResults) { + obj.options.numberOfPages = Math.ceil(searchResults.length / obj.options.pagination); + } else { + obj.options.numberOfPages = Math.ceil(obj.options.data.length / obj.options.pagination); + } + } + // Load data for the user + execute(); + } + } + } + + obj.search = function(query) { + obj.options.pageNumber = 0; + obj.options.searchValue = query ? query : ''; + + // Filter data + if (obj.options.remoteData == true || ! query) { + searchResults = null; + } else { + var test = function(o, query) { + for (var key in o) { + var value = o[key]; + + if ((''+value).toLowerCase().search(query) >= 0) { + return true; + } + } + return false; + } + + if (typeof(obj.options.filter) == 'function') { + searchResults = obj.options.filter(obj.options.data, query); + } else { + searchResults = obj.options.data.filter(function(item) { + return test(item, query); + }); + } + } + + obj.render(); + + if (typeof(obj.options.onsearch) == 'function') { + obj.options.onsearch(el, obj, query); + } + } + + obj.refresh = function() { + obj.render(); + } + + obj.reload = function() { + obj.render(0, true); + } + + el.addEventListener('mousedown', function(e) { + if (e.target.parentNode.classList.contains('jtemplate-pagination')) { + var index = e.target.innerText; + if (index == '<') { + obj.render(0); + } else if (index == '>') { + obj.render(e.target.getAttribute('title')); + } else { + obj.render(parseInt(index)-1); + } + e.preventDefault(); + } + }); + + el.template = obj; + + // Render data + obj.render(0, true); + + return obj; +}); + +/** + * (c) jSuites Timeline + * https://github.com/paulhodel/jsuites + * + * @author: Paul Hodel + * @description: Timeline + */ + +jSuites.timeline = (function(el, options) { + var obj = {}; + obj.options = {}; + + // Two digits + var two = function(value) { + value = '' + value; + if (value.length == 1) { + value = '0' + value; + } + return value; + } + + // Default date format + if (! options.date) { + var date = new Date(); + var y = date.getFullYear(); + var m = two(date.getMonth() + 1); + date = y + '-' + m; + } + + // Default configurations + var defaults = { + url: null, + data: [], + date: date, + months: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ], + monthsFull: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], + onaction: null, + text: { + noInformation: '
No information for this period
', + } + }; + + // 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]; + } + } + + // Add class + el.classList.add('jtimeline'); + + // Header + var timelineHeader = document.createElement('div'); + timelineHeader.className = 'jtimeline-header'; + + var timelineLabel = document.createElement('div'); + timelineLabel.className = 'jtimeline-label'; + + var timelineNavigation = document.createElement('div'); + timelineNavigation.className = 'jtimeline-navigation'; + + // Labels + var timelineMonth = document.createElement('div'); + timelineMonth.className = 'jtimeline-month'; + timelineMonth.innerHTML = ''; + timelineLabel.appendChild(timelineMonth); + + var timelineYear = document.createElement('div'); + timelineYear.className = 'jtimeline-year'; + timelineYear.innerHTML = ''; + timelineLabel.appendChild(timelineYear); + + // Navigation + var timelinePrev = document.createElement('div'); + timelinePrev.className = 'jtimeline-prev'; + timelinePrev.innerHTML = 'keyboard_arrow_left'; + timelineNavigation.appendChild(timelinePrev); + + var timelineNext = document.createElement('div'); + timelineNext.className = 'jtimeline-next'; + timelineNext.innerHTML = 'keyboard_arrow_right'; + timelineNavigation.appendChild(timelineNext); + + timelineHeader.appendChild(timelineLabel); + timelineHeader.appendChild(timelineNavigation); + + // Data container + var timelineContainer = document.createElement('div'); + timelineContainer.className = 'jtimeline-container'; + + // Append headers + el.appendChild(timelineHeader); + el.appendChild(timelineContainer); + + // Date + if (obj.options.date.length > 7) { + obj.options.date = obj.options.date.substr(0, 7) + } + + // Action + var action = function(o) { + // Get item + var item = o.parentNode.parentNode.parentNode.parentNode; + // Get id + var id = item.getAttribute('data-id'); + + } + + obj.setData = function(rows) { + var data = []; + for (var i = 0; i < rows.length; i++) { + var d = rows[i].date.substr(0,7); + + // Create the object if not exists + if (! data[d]) { + data[d] = []; + } + + // Create array + data[d].push(rows[i]); + }; + obj.options.data = data; + obj.render(obj.options.date); + } + + obj.add = function(data) { + var date = data.date.substr(0,7); + + // Create the object if not exists + if (! obj.options.data[date]) { + obj.options.data[date] = []; + } + + // Format date + data.date = data.date.substr(0,10); + + // Append data + obj.options.data[date].push(data); + + // Reorder + obj.options.data[date] = obj.options.data[date].order(); + + // Render + obj.render(date); + } + + obj.remove = function(item) { + var index = item.getAttribute('data-index'); + var date = item.getAttribute('data-date'); + + jSuites.animation.fadeOut(item, function() { + item.remove(); + }); + + obj.options.data[date].splice(index, 1); + } + + obj.reload = function() { + var date = obj.options.date + obj.render(date); + } + + obj.render = function(date) { + // Filter + if (date.length > 7) { + var date = date.substr(0,7); + } + + // Update current date + obj.options.date = date; + + // Reset data + timelineContainer.innerHTML = ''; + + // Days + var timelineDays = []; + + // Itens + if (! obj.options.data[date]) { + timelineContainer.innerHTML = obj.options.text.noInformation; + } else { + for (var i = 0; i < obj.options.data[date].length; i++) { + var v = obj.options.data[date][i]; + var d = v.date.split('-'); + + // Item container + var timelineItem = document.createElement('div'); + timelineItem.className = 'jtimeline-item'; + timelineItem.setAttribute('data-id', v.id); + timelineItem.setAttribute('data-index', i); + timelineItem.setAttribute('data-date', date); + + // Date + var timelineDateContainer = document.createElement('div'); + timelineDateContainer.className = 'jtimeline-date-container'; + + var timelineDate = document.createElement('div'); + if (! timelineDays[d[2]]) { + timelineDate.className = 'jtimeline-date jtimeline-date-bullet'; + timelineDate.innerHTML = d[2]; + } else { + timelineDate.className = 'jtimeline-date'; + timelineDate.innerHTML = ''; + } + timelineDateContainer.appendChild(timelineDate); + + var timelineContent = document.createElement('div'); + timelineContent.className = 'jtimeline-content'; + + // Title + if (! v.title) { + v.title = v.subtitle ? v.subtitle : 'Information'; + } + + var timelineTitleContainer = document.createElement('div'); + timelineTitleContainer.className = 'jtimeline-title-container'; + timelineContent.appendChild(timelineTitleContainer); + + var timelineTitle = document.createElement('div'); + timelineTitle.className = 'jtimeline-title'; + timelineTitle.innerHTML = v.title; + timelineTitleContainer.appendChild(timelineTitle); + + var timelineControls = document.createElement('div'); + timelineControls.className = 'jtimeline-controls'; + timelineTitleContainer.appendChild(timelineControls); + + var timelineEdit = document.createElement('i'); + timelineEdit.className = 'material-icons timeline-edit'; + timelineEdit.innerHTML = 'edit'; + timelineEdit.onclick = function() { + if (typeof(obj.options.onaction) == 'function') { + obj.options.onaction(obj, this); + } + } + if (v.author == 1) { + timelineControls.appendChild(timelineEdit); + } + + var timelineSubtitle = document.createElement('div'); + timelineSubtitle.className = 'jtimeline-subtitle'; + timelineSubtitle.innerHTML = v.subtitle ? v.subtitle : ''; + timelineContent.appendChild(timelineSubtitle); + + // Text + var timelineText = document.createElement('div'); + timelineText.className = 'jtimeline-text'; + timelineText.innerHTML = v.text; + timelineContent.appendChild(timelineText); + + // Tag + var timelineTags = document.createElement('div'); + timelineTags.className = 'jtimeline-tags'; + timelineContent.appendChild(timelineTags); + + if (v.tags) { + var createTag = function(name, color) { + var timelineTag = document.createElement('div'); + timelineTag.className = 'jtimeline-tag'; + timelineTag.innerHTML = name; + if (color) { + timelineTag.style.backgroundColor = color; + } + return timelineTag; + } + + if (typeof(v.tags) == 'string') { + var t = createTag(v.tags); + timelineTags.appendChild(t); + } else { + for (var j = 0; j < v.tags.length; j++) { + var t = createTag(v.tags[j].text, v.tags[j].color); + timelineTags.appendChild(t); + } + } + } + + // Day + timelineDays[d[2]] = true; + + // Append Item + timelineItem.appendChild(timelineDateContainer); + timelineItem.appendChild(timelineContent); + timelineContainer.appendChild(timelineItem); + }; + } + + // Update labels + var d = date.split('-'); + timelineYear.innerHTML = d[0]; + timelineMonth.innerHTML = obj.options.monthsFull[parseInt(d[1]) - 1]; + } + + obj.next = function() { + // Update current date + var d = obj.options.date.split('-'); + // Next month + d[1]++; + // Next year + if (d[1] > 12) { + d[0]++; + d[1] = 1; + } + date = d[0] + '-' + (d[1] < 10 ? '0' + d[1] : d[1]); + + // Animation + jSuites.animation.slideLeft(timelineContainer, 0, function() { + obj.render(date); + jSuites.animation.slideRight(timelineContainer, 1); + }); + } + + obj.prev = function() { + // Update current date + var d = obj.options.date.split('-'); + // Next month + d[1]--; + // Next year + if (d[1] < 1) { + d[0]--; + d[1] = 12; + } + date = d[0] + '-' + (d[1] < 10 ? '0' + d[1] : d[1]); + + // Animation + jSuites.animation.slideRight(timelineContainer, 0, function() { + obj.render(date); + jSuites.animation.slideLeft(timelineContainer, 1); + }); + } + + obj.load = function() { + // Init + if (obj.options.url) { + jSuites.ajax({ + url: obj.options.url, + type: 'GET', + dataType:'json', + success: function(data) { + // Timeline data + obj.setData(data); + } + }); + } else { + // Timeline data + obj.setData(obj.options.data); + } + } + + obj.reload = function() { + obj.load(); + } + + obj.load(); + + var timelineMouseUpControls = function(e) { + if (e.target.classList.contains('jtimeline-next') || e.target.parentNode.classList.contains('jtimeline-next')) { + obj.next(); + } else if (e.target.classList.contains('jtimeline-prev') || e.target.parentNode.classList.contains('jtimeline-prev')) { + obj.prev(); + } + } + + if ('ontouchend' in document.documentElement === true) { + el.addEventListener("touchend", timelineMouseUpControls); + } else { + el.addEventListener("mouseup", timelineMouseUpControls); + } + + // 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(); + }); + + // Orderby + Array.prototype.order = function() { + return this.slice(0).sort(function(a, b) { + var valueA = a.date; + var valueB = b.date; + + return (valueA > valueB) ? 1 : (valueA < valueB) ? -1 : 0; + }); + } + + el.timeline = obj; + + return obj; +}); -- cgit v1.2.3