X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=assets%2Fdefault%2Fjs%2Fbase.js;h=3168881514595071111672d52959baa1976713aa;hb=4cf3564d28dc8e4d08a3e64f09ad045ffbde97ae;hp=cf628e87fc4f15e0b9d1c71a42b5e14994e613f1;hpb=b3375c7f86f35fce723185bb76d3b5f9c4ff7a07;p=github%2Fshaarli%2FShaarli.git diff --git a/assets/default/js/base.js b/assets/default/js/base.js index cf628e87..31688815 100644 --- a/assets/default/js/base.js +++ b/assets/default/js/base.js @@ -1,664 +1,637 @@ -/** @licstart The following is the entire license notice for the - * JavaScript code in this page. - * - * Copyright: (c) 2011-2015 Sébastien SAUVAGE - * (c) 2011-2017 The Shaarli Community, see AUTHORS - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from - * the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would - * be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must - * not be misrepresented as being the original software. +import Awesomplete from 'awesomplete'; +import he from 'he'; + +/** + * Find a parent element according to its tag and its attributes * - * 3. This notice may not be removed or altered from any source distribution. + * @param element Element where to start the search + * @param tagName Expected parent tag name + * @param attributes Associative array of expected attributes (name=>value). * - * @licend The above is the entire license notice - * for the JavaScript code in this page. + * @returns Found element or null. */ - -window.onload = function () { - - /** - * Retrieve an element up in the tree from its class name. - */ - function getParentByClass(el, className) { - var p = el.parentNode; - if (p == null || p.classList.contains(className)) { - return p; - } - return getParentByClass(p, className); +function findParent(element, tagName, attributes) { + const parentMatch = (key) => attributes[key] !== '' && element.getAttribute(key).indexOf(attributes[key]) !== -1; + while (element) { + if (element.tagName.toLowerCase() === tagName) { + if (Object.keys(attributes).find(parentMatch)) { + return element; + } } + element = element.parentElement; + } + return null; +} - - /** - * Handle responsive menu. - * Source: http://purecss.io/layouts/tucked-menu-vertical/ - */ - (function (window, document) { - var menu = document.getElementById('shaarli-menu'), - WINDOW_CHANGE_EVENT = ('onorientationchange' in window) ? 'orientationchange':'resize'; - - function toggleHorizontal() { - [].forEach.call( - document.getElementById('shaarli-menu').querySelectorAll('.menu-transform'), - function(el){ - el.classList.toggle('pure-menu-horizontal'); - } - ); - }; - - function toggleMenu() { - // set timeout so that the panel has a chance to roll up - // before the menu switches states - if (menu.classList.contains('open')) { - setTimeout(toggleHorizontal, 500); - } - else { - toggleHorizontal(); - } - menu.classList.toggle('open'); - document.getElementById('menu-toggle').classList.toggle('x'); - }; - - function closeMenu() { - if (menu.classList.contains('open')) { - toggleMenu(); - } - } - - var menuToggle = document.getElementById('menu-toggle'); - if (menuToggle != null) { - menuToggle.addEventListener('click', function (e) { - toggleMenu(); - }); - } - - window.addEventListener(WINDOW_CHANGE_EVENT, closeMenu); - })(this, this.document); - - /** - * Fold/Expand shaares description and thumbnail. - */ - var foldAllButtons = document.getElementsByClassName('fold-all'); - var foldButtons = document.getElementsByClassName('fold-button'); - - [].forEach.call(foldButtons, function (foldButton) { - // Retrieve description - var description = null; - var thumbnail = null; - var linklistItem = getParentByClass(foldButton, 'linklist-item'); - if (linklistItem != null) { - description = linklistItem.querySelector('.linklist-item-description'); - thumbnail = linklistItem.querySelector('.linklist-item-thumbnail'); - if (description != null || thumbnail != null) { - foldButton.style.display = 'inline'; - } - } - - foldButton.addEventListener('click', function (event) { - event.preventDefault(); - toggleFold(event.target, description, thumbnail); - }); +/** + * Ajax request to refresh the CSRF token. + */ +function refreshToken(basePath, callback) { + const xhr = new XMLHttpRequest(); + xhr.open('GET', `${basePath}/admin/token`); + xhr.onload = () => { + const elements = document.querySelectorAll('input[name="token"]'); + [...elements].forEach((element) => { + element.setAttribute('value', xhr.responseText); }); - if (foldAllButtons != null) { - [].forEach.call(foldAllButtons, function (foldAllButton) { - foldAllButton.addEventListener('click', function (event) { - event.preventDefault(); - var state = foldAllButton.firstElementChild.getAttribute('class').indexOf('down') != -1 ? 'down' : 'up'; - [].forEach.call(foldButtons, function (foldButton) { - if (foldButton.firstElementChild.classList.contains('fa-chevron-up') && state == 'down' - || foldButton.firstElementChild.classList.contains('fa-chevron-down') && state == 'up' - ) { - return; - } - // Retrieve description - var description = null; - var thumbnail = null; - var linklistItem = getParentByClass(foldButton, 'linklist-item'); - if (linklistItem != null) { - description = linklistItem.querySelector('.linklist-item-description'); - thumbnail = linklistItem.querySelector('.linklist-item-thumbnail'); - if (description != null || thumbnail != null) { - foldButton.style.display = 'inline'; - } - } - - toggleFold(foldButton.firstElementChild, description, thumbnail); - }); - foldAllButton.firstElementChild.classList.toggle('fa-chevron-down'); - foldAllButton.firstElementChild.classList.toggle('fa-chevron-up'); - foldAllButton.title = state === 'down' - ? document.getElementById('translation-fold-all').innerHTML - : document.getElementById('translation-expand-all').innerHTML - }); - }); + if (callback) { + callback(xhr.response); } + }; + xhr.send(); +} - function toggleFold(button, description, thumb) - { - // Switch fold/expand - up = fold - if (button.classList.contains('fa-chevron-up')) { - button.title = document.getElementById('translation-expand').innerHTML; - if (description != null) { - description.style.display = 'none'; - } - if (thumb != null) { - thumb.style.display = 'none'; - } - } - else { - button.title = document.getElementById('translation-fold').innerHTML; - if (description != null) { - description.style.display = 'block'; - } - if (thumb != null) { - thumb.style.display = 'block'; - } - } - button.classList.toggle('fa-chevron-down'); - button.classList.toggle('fa-chevron-up'); +function createAwesompleteInstance(element, tags = []) { + const awesome = new Awesomplete(Awesomplete.$(element)); + // Tags are separated by a space + awesome.filter = (text, input) => Awesomplete.FILTER_CONTAINS(text, input.match(/[^ ]*$/)[0]); + // Insert new selected tag in the input + awesome.replace = (text) => { + const before = awesome.input.value.match(/^.+ \s*|/)[0]; + awesome.input.value = `${before}${text} `; + }; + // Highlight found items + awesome.item = (text, input) => Awesomplete.ITEM(text, input.match(/[^ ]*$/)[0]); + // Don't display already selected items + const reg = /(\w+) /g; + let match; + awesome.data = (item, input) => { + while ((match = reg.exec(input))) { + if (item === match[1]) { + return ''; + } } + return item; + }; + awesome.minChars = 1; + if (tags.length) { + awesome.list = tags; + } + + return awesome; +} - /** - * Confirmation message before deletion. - */ - var deleteLinks = document.querySelectorAll('.confirm-delete'); - [].forEach.call(deleteLinks, function(deleteLink) { - deleteLink.addEventListener('click', function(event) { - if(! confirm(document.getElementById('translation-delete-link').innerHTML)) { - event.preventDefault(); - } - }); +/** + * Update awesomplete list of tag for all elements matching the given selector + * + * @param selector CSS selector + * @param tags Array of tags + * @param instances List of existing awesomplete instances + */ +function updateAwesompleteList(selector, tags, instances) { + if (instances.length === 0) { + // First load: create Awesomplete instances + const elements = document.querySelectorAll(selector); + [...elements].forEach((element) => { + instances.push(createAwesompleteInstance(element, tags)); }); - - /** - * Close alerts - */ - var closeLinks = document.querySelectorAll('.pure-alert-close'); - [].forEach.call(closeLinks, function(closeLink) { - closeLink.addEventListener('click', function(event) { - var alert = getParentByClass(event.target, 'pure-alert-closable'); - alert.style.display = 'none'; - }); + } else { + // Update awesomplete tag list + instances.map((item) => { + item.list = tags; + return item; }); + } + return instances; +} - /** - * New version dismiss. - * Hide the message for one week using localStorage. - */ - var newVersionDismiss = document.getElementById('new-version-dismiss'); - var newVersionMessage = document.querySelector('.new-version-message'); - if (newVersionMessage != null - && localStorage.getItem('newVersionDismiss') != null - && parseInt(localStorage.getItem('newVersionDismiss')) + 7*24*60*60*1000 > (new Date()).getTime() - ) { - newVersionMessage.style.display = 'none'; - } - if (newVersionDismiss != null) { - newVersionDismiss.addEventListener('click', function () { - localStorage.setItem('newVersionDismiss', (new Date()).getTime()); - }); +/** + * Add the class 'hidden' to city options not attached to the current selected continent. + * + * @param cities List of