aboutsummaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/shaarli.js411
1 files changed, 411 insertions, 0 deletions
diff --git a/js/shaarli.js b/js/shaarli.js
new file mode 100644
index 0000000..4d47fcd
--- /dev/null
+++ b/js/shaarli.js
@@ -0,0 +1,411 @@
+/** @licstart The following is the entire license notice for the
+ * JavaScript code in this page.
+ *
+ * Copyright: (c) 2011-2015 Sébastien SAUVAGE <sebsauvage@sebsauvage.net>
+ * (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.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * @licend The above is the entire license notice
+ * for the JavaScript code in this page.
+ */
+
+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);
+ }
+
+
+ /**
+ * 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);
+ });
+ });
+
+ 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');
+ });
+ });
+ }
+
+ function toggleFold(button, description, thumb)
+ {
+ // Switch fold/expand - up = fold
+ if (button.classList.contains('fa-chevron-up')) {
+ button.title = 'Expand';
+ if (description != null) {
+ description.style.display = 'none';
+ }
+ if (thumb != null) {
+ thumb.style.display = 'none';
+ }
+ }
+ else {
+ button.title = 'Fold';
+ 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');
+ }
+
+ /**
+ * Confirmation message before deletion.
+ */
+ var deleteLinks = document.querySelectorAll('.confirm-delete');
+ [].forEach.call(deleteLinks, function(deleteLink) {
+ deleteLink.addEventListener('click', function(event) {
+ if(! confirm('Are you sure you want to delete this link ?')) {
+ event.preventDefault();
+ }
+ });
+ });
+
+ /**
+ * 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';
+ });
+ });
+
+ /**
+ * 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());
+ });
+ }
+
+ var hiddenReturnurl = document.getElementsByName('returnurl');
+ if (hiddenReturnurl != null) {
+ hiddenReturnurl.value = window.location.href;
+ }
+
+ /**
+ * Autofocus text fields
+ */
+ // ES6 syntax
+ let autofocusElements = document.querySelectorAll('.autofocus');
+ for (let autofocusElement of autofocusElements) {
+ if (autofocusElement.value == '') {
+ autofocusElement.focus();
+ break;
+ }
+ }
+
+ /**
+ * Handle sub menus/forms
+ */
+ var openers = document.getElementsByClassName('subheader-opener');
+ if (openers != null) {
+ [].forEach.call(openers, function(opener) {
+ opener.addEventListener('click', function(event) {
+ event.preventDefault();
+
+ var id = opener.getAttribute('data-open-id');
+ var sub = document.getElementById(id);
+
+ if (sub != null) {
+ [].forEach.call(document.getElementsByClassName('subheader-form'), function (element) {
+ if (element != sub) {
+ removeClass(element, 'open')
+ }
+ });
+
+ sub.classList.toggle('open');
+ }
+ });
+ });
+ }
+
+ function removeClass(element, classname) {
+ element.className = element.className.replace(new RegExp('(?:^|\\s)'+ classname + '(?:\\s|$)'), ' ');
+ }
+
+ /**
+ * Remove CSS target padding (for fixed bar)
+ */
+ if (location.hash != '') {
+ var anchor = document.getElementById(location.hash.substr(1));
+ if (anchor != null) {
+ var padsize = anchor.clientHeight;
+ this.window.scroll(0, this.window.scrollY - padsize);
+ anchor.style.paddingTop = 0;
+ }
+ }
+
+ /**
+ * Text area resizer
+ */
+ var description = document.getElementById('lf_description');
+ var observe = function (element, event, handler) {
+ element.addEventListener(event, handler, false);
+ };
+ function init () {
+ function resize () {
+ description.style.height = 'auto';
+ description.style.height = description.scrollHeight+10+'px';
+ }
+ /* 0-timeout to get the already changed text */
+ function delayedResize () {
+ window.setTimeout(resize, 0);
+ }
+ observe(description, 'change', resize);
+ observe(description, 'cut', delayedResize);
+ observe(description, 'paste', delayedResize);
+ observe(description, 'drop', delayedResize);
+ observe(description, 'keydown', delayedResize);
+
+ resize();
+ }
+
+ if (description != null) {
+ init();
+ // Submit editlink form with CTRL + Enter in the text area.
+ description.addEventListener('keydown', function (event) {
+ if (event.ctrlKey && event.keyCode === 13) {
+ document.getElementById('button-save-edit').click();
+ }
+ });
+ }
+
+ /**
+ * Awesomplete trigger.
+ */
+ var tags = document.getElementById('lf_tags');
+ if (tags != null) {
+ awesompleteUniqueTag('#lf_tags');
+ }
+
+ /**
+ * bLazy trigger
+ */
+ var picwall = document.getElementById('picwall_container');
+ if (picwall != null) {
+ var bLazy = new Blazy();
+ }
+
+ /**
+ * Bookmarklet alert
+ */
+ var bookmarkletLinks = document.querySelectorAll('.bookmarklet-link');
+ var bkmMessage = document.getElementById('bookmarklet-alert');
+ [].forEach.call(bookmarkletLinks, function(link) {
+ link.addEventListener('click', function(event) {
+ event.preventDefault();
+ alert(bkmMessage.value);
+ });
+ });
+
+ /**
+ * Firefox Social
+ */
+ var ffButton = document.getElementById('ff-social-button');
+ if (ffButton != null) {
+ ffButton.addEventListener('click', function(event) {
+ activateFirefoxSocial(event.target);
+ });
+ }
+
+ /**
+ * Plugin admin order
+ */
+ var orderPA = document.querySelectorAll('.order');
+ [].forEach.call(orderPA, function(link) {
+ link.addEventListener('click', function(event) {
+ event.preventDefault();
+ if (event.target.classList.contains('order-up')) {
+ return orderUp(event.target.parentNode.parentNode.getAttribute('data-order'));
+ } else if (event.target.classList.contains('order-down')) {
+ return orderDown(event.target.parentNode.parentNode.getAttribute('data-order'));
+ }
+ });
+ });
+
+ var continent = document.getElementById('continent');
+ var city = document.getElementById('city');
+ if (continent != null && city != null) {
+ continent.addEventListener('change', function(event) {
+ hideTimezoneCities(city, continent.options[continent.selectedIndex].value, true);
+ });
+ hideTimezoneCities(city, continent.options[continent.selectedIndex].value, false);
+ }
+};
+
+function activateFirefoxSocial(node) {
+ var loc = location.href;
+ var baseURL = loc.substring(0, loc.lastIndexOf("/"));
+
+ // Keeping the data separated (ie. not in the DOM) so that it's maintainable and diffable.
+ var data = {
+ name: "{$shaarlititle}",
+ description: "The personal, minimalist, super-fast, database free, bookmarking service by the Shaarli community.",
+ author: "Shaarli",
+ version: "1.0.0",
+
+ iconURL: baseURL + "/images/favicon.ico",
+ icon32URL: baseURL + "/images/favicon.ico",
+ icon64URL: baseURL + "/images/favicon.ico",
+
+ shareURL: baseURL + "{noparse}?post=%{url}&title=%{title}&description=%{text}&source=firefoxsocialapi{/noparse}",
+ homepageURL: baseURL
+ };
+ node.setAttribute("data-service", JSON.stringify(data));
+
+ var activate = new CustomEvent("ActivateSocialFeature");
+ node.dispatchEvent(activate);
+}
+
+/**
+ * Add the class 'hidden' to city options not attached to the current selected continent.
+ *
+ * @param cities List of <option> elements
+ * @param currentContinent Current selected continent
+ * @param reset Set to true to reset the selected value
+ */
+function hideTimezoneCities(cities, currentContinent, reset = false) {
+ var first = true;
+ [].forEach.call(cities, function(option) {
+ if (option.getAttribute('data-continent') != currentContinent) {
+ option.className = 'hidden';
+ } else {
+ option.className = '';
+ if (reset === true && first === true) {
+ option.setAttribute('selected', 'selected');
+ first = false;
+ }
+ }
+ });
+}