]>
git.immae.eu Git - github/shaarli/Shaarli.git/blob - tpl/default/js/shaarli.js
1 /** @licstart The following is the entire license notice for the
2 * JavaScript code in this page.
4 * Copyright: (c) 2011-2015 Sébastien SAUVAGE <sebsauvage@sebsauvage.net>
5 * (c) 2011-2017 The Shaarli Community, see AUTHORS
7 * This software is provided 'as-is', without any express or implied warranty.
8 * In no event will the authors be held liable for any damages arising from
9 * the use of this software.
11 * Permission is granted to anyone to use this software for any purpose,
12 * including commercial applications, and to alter it and redistribute it
13 * freely, subject to the following restrictions:
15 * 1. The origin of this software must not be misrepresented; you must not
16 * claim that you wrote the original software. If you use this software
17 * in a product, an acknowledgment in the product documentation would
18 * be appreciated but is not required.
20 * 2. Altered source versions must be plainly marked as such, and must
21 * not be misrepresented as being the original software.
23 * 3. This notice may not be removed or altered from any source distribution.
25 * @licend The above is the entire license notice
26 * for the JavaScript code in this page.
29 window
.onload = function () {
32 * Retrieve an element up in the tree from its class name.
34 function getParentByClass(el
, className
) {
35 var p
= el
.parentNode
;
36 if (p
== null || p
.classList
.contains(className
)) {
39 return getParentByClass(p
, className
);
44 * Handle responsive menu.
45 * Source: http://purecss.io/layouts/tucked-menu-vertical/
47 (function (window
, document
) {
48 var menu
= document
.getElementById('shaarli-menu'),
49 WINDOW_CHANGE_EVENT
= ('onorientationchange' in window
) ? 'orientationchange':'resize';
51 function toggleHorizontal() {
53 document
.getElementById('shaarli-menu').querySelectorAll('.menu-transform'),
55 el
.classList
.toggle('pure-menu-horizontal');
60 function toggleMenu() {
61 // set timeout so that the panel has a chance to roll up
62 // before the menu switches states
63 if (menu
.classList
.contains('open')) {
64 setTimeout(toggleHorizontal
, 500);
69 menu
.classList
.toggle('open');
70 document
.getElementById('menu-toggle').classList
.toggle('x');
73 function closeMenu() {
74 if (menu
.classList
.contains('open')) {
79 document
.getElementById('menu-toggle').addEventListener('click', function (e
) {
83 window
.addEventListener(WINDOW_CHANGE_EVENT
, closeMenu
);
84 })(this, this.document
);
87 * Fold/Expand shaares description and thumbnail.
89 var foldAllButtons
= document
.getElementsByClassName('fold-all');
90 var foldButtons
= document
.getElementsByClassName('fold-button');
92 [].forEach
.call(foldButtons
, function (foldButton
) {
93 // Retrieve description
94 var description
= null;
96 var linklistItem
= getParentByClass(foldButton
, 'linklist-item');
97 if (linklistItem
!= null) {
98 description
= linklistItem
.querySelector('.linklist-item-description');
99 thumbnail
= linklistItem
.querySelector('.linklist-item-thumbnail');
100 if (description
!= null || thumbnail
!= null) {
101 foldButton
.style
.display
= 'inline';
105 foldButton
.addEventListener('click', function (event
) {
106 event
.preventDefault();
107 toggleFold(event
.target
, description
, thumbnail
);
111 if (foldAllButtons
!= null) {
112 [].forEach
.call(foldAllButtons
, function (foldAllButton
) {
113 foldAllButton
.addEventListener('click', function (event
) {
114 event
.preventDefault();
115 var state
= foldAllButton
.firstElementChild
.getAttribute('class').indexOf('down') != -1 ? 'down' : 'up';
116 [].forEach
.call(foldButtons
, function (foldButton
) {
117 if (foldButton
.firstElementChild
.classList
.contains('fa-chevron-up') && state
== 'down'
118 || foldButton
.firstElementChild
.classList
.contains('fa-chevron-down') && state
== 'up'
122 // Retrieve description
123 var description
= null;
124 var thumbnail
= null;
125 var linklistItem
= getParentByClass(foldButton
, 'linklist-item');
126 if (linklistItem
!= null) {
127 description
= linklistItem
.querySelector('.linklist-item-description');
128 thumbnail
= linklistItem
.querySelector('.linklist-item-thumbnail');
129 if (description
!= null || thumbnail
!= null) {
130 foldButton
.style
.display
= 'inline';
134 toggleFold(foldButton
.firstElementChild
, description
, thumbnail
);
136 foldAllButton
.firstElementChild
.classList
.toggle('fa-chevron-down');
137 foldAllButton
.firstElementChild
.classList
.toggle('fa-chevron-up');
142 function toggleFold(button
, description
, thumb
)
144 // Switch fold/expand - up = fold
145 if (button
.classList
.contains('fa-chevron-up')) {
146 button
.title
= 'Expand';
147 if (description
!= null) {
148 description
.style
.display
= 'none';
151 thumb
.style
.display
= 'none';
155 button
.title
= 'Fold';
156 if (description
!= null) {
157 description
.style
.display
= 'block';
160 thumb
.style
.display
= 'block';
163 button
.classList
.toggle('fa-chevron-down');
164 button
.classList
.toggle('fa-chevron-up');
168 * Confirmation message before deletion.
170 var deleteLinks
= document
.querySelectorAll('.confirm-delete');
171 [].forEach
.call(deleteLinks
, function(deleteLink
) {
172 deleteLink
.addEventListener('click', function(event
) {
173 if(! confirm('Are you sure you want to delete this link ?')) {
174 event
.preventDefault();
182 var closeLinks
= document
.querySelectorAll('.pure-alert-close');
183 [].forEach
.call(closeLinks
, function(closeLink
) {
184 closeLink
.addEventListener('click', function(event
) {
185 var alert
= getParentByClass(event
.target
, 'pure-alert-closable');
186 alert
.style
.display
= 'none';
191 * New version dismiss.
192 * Hide the message for one week using localStorage.
194 var newVersionDismiss
= document
.getElementById('new-version-dismiss');
195 var newVersionMessage
= document
.querySelector('.new-version-message');
196 if (newVersionMessage
!= null
197 && localStorage
.getItem('newVersionDismiss') != null
198 && parseInt(localStorage
.getItem('newVersionDismiss')) + 7*24*60*60*1000 > (new Date()).getTime()
200 newVersionMessage
.style
.display
= 'none';
202 if (newVersionDismiss
!= null) {
203 newVersionDismiss
.addEventListener('click', function () {
204 localStorage
.setItem('newVersionDismiss', (new Date()).getTime());
208 var hiddenReturnurl
= document
.getElementsByName('returnurl');
209 if (hiddenReturnurl
!= null) {
210 hiddenReturnurl
.value
= window
.location
.href
;
214 * Autofocus text fields
217 let autofocusElements
= document
.querySelectorAll('.autofocus');
218 for (let autofocusElement
of autofocusElements
) {
219 if (autofocusElement
.value
== '') {
220 autofocusElement
.focus();
226 * Handle sub menus/forms
228 var openers
= document
.getElementsByClassName('subheader-opener');
229 if (openers
!= null) {
230 [].forEach
.call(openers
, function(opener
) {
231 opener
.addEventListener('click', function(event
) {
232 event
.preventDefault();
234 var id
= opener
.getAttribute('data-open-id');
235 var sub
= document
.getElementById(id
);
238 [].forEach
.call(document
.getElementsByClassName('subheader-form'), function (element
) {
239 if (element
!= sub
) {
240 removeClass(element
, 'open')
244 sub
.classList
.toggle('open');
250 function removeClass(element
, classname
) {
251 element
.className
= element
.className
.replace(new RegExp('(?:^|\\s)'+ classname
+ '(?:\\s|$)'), ' ');
255 * Remove CSS target padding (for fixed bar)
257 if (location
.hash
!= '') {
258 var anchor
= document
.querySelector(location
.hash
);
259 if (anchor
!= null) {
260 var padsize
= anchor
.clientHeight
;
261 console
.log(document
.querySelector(location
.hash
).clientHeight
);
262 this.window
.scroll(0, this.window
.scrollY
- padsize
);
263 anchor
.style
.paddingTop
= 0;
270 var description
= document
.getElementById('lf_description');
271 var observe = function (element
, event
, handler
) {
272 element
.addEventListener(event
, handler
, false);
276 description
.style
.height
= 'auto';
277 description
.style
.height
= description
.scrollHeight
+10+'px';
279 /* 0-timeout to get the already changed text */
280 function delayedResize () {
281 window
.setTimeout(resize
, 0);
283 observe(description
, 'change', resize
);
284 observe(description
, 'cut', delayedResize
);
285 observe(description
, 'paste', delayedResize
);
286 observe(description
, 'drop', delayedResize
);
287 observe(description
, 'keydown', delayedResize
);
292 if (description
!= null) {
294 // Submit editlink form with CTRL + Enter in the text area.
295 description
.addEventListener('keydown', function (event
) {
296 if (event
.ctrlKey
&& event
.keyCode
=== 13) {
297 document
.getElementById('button-save-edit').click();
304 * FIXME! way too hackish
306 var toRemove
= document
.getElementById('timezone-remove');
307 if (toRemove
!= null) {
308 var firstSelect
= toRemove
.getElementsByTagName('select')[0];
309 var secondSelect
= toRemove
.getElementsByTagName('select')[1];
310 toRemove
.parentNode
.removeChild(toRemove
);
311 var toAdd
= document
.getElementById('timezone-add');
312 var newTimezone
= '<span class="timezone-continent">Continent ' + firstSelect
.outerHTML
+ '</span>';
313 newTimezone
+= ' <span class="timezone-country">Country ' + secondSelect
.outerHTML
+ '</span>';
314 toAdd
.innerHTML
= newTimezone
;
318 * Awesomplete trigger.
320 var tags
= document
.getElementById('lf_tags');
322 awesompleteUniqueTag('#lf_tags');
328 var picwall
= document
.getElementById('picwall_container');
329 if (picwall
!= null) {
330 var bLazy
= new Blazy();
336 var bookmarkletLinks
= document
.querySelectorAll('.bookmarklet-link');
337 var bkmMessage
= document
.getElementById('bookmarklet-alert');
338 [].forEach
.call(bookmarkletLinks
, function(link
) {
339 link
.addEventListener('click', function(event
) {
340 event
.preventDefault();
341 alert(bkmMessage
.value
);
348 var ffButton
= document
.getElementById('ff-social-button');
349 if (ffButton
!= null) {
350 ffButton
.addEventListener('click', function(event
) {
351 activateFirefoxSocial(event
.target
);
358 var orderPA
= document
.querySelectorAll('.order');
359 [].forEach
.call(orderPA
, function(link
) {
360 link
.addEventListener('click', function(event
) {
361 event
.preventDefault();
362 if (event
.target
.classList
.contains('order-up')) {
363 return orderUp(event
.target
.parentNode
.parentNode
.getAttribute('data-order'));
364 } else if (event
.target
.classList
.contains('order-down')) {
365 return orderDown(event
.target
.parentNode
.parentNode
.getAttribute('data-order'));
371 function activateFirefoxSocial(node
) {
372 var loc
= location
.href
;
373 var baseURL
= loc
.substring(0, loc
.lastIndexOf("/"));
375 // Keeping the data separated (ie. not in the DOM) so that it's maintainable and diffable.
377 name: "{$shaarlititle}",
378 description: "The personal, minimalist, super-fast, database free, bookmarking service by the Shaarli community.",
382 iconURL: baseURL
+ "/images/favicon.ico",
383 icon32URL: baseURL
+ "/images/favicon.ico",
384 icon64URL: baseURL
+ "/images/favicon.ico",
386 shareURL: baseURL
+ "{noparse}?post=%{url}&title=%{title}&description=%{text}&source=firefoxsocialapi{/noparse}",
389 node
.setAttribute("data-service", JSON
.stringify(data
));
391 var activate
= new CustomEvent("ActivateSocialFeature");
392 node
.dispatchEvent(activate
);