]> git.immae.eu Git - github/shaarli/Shaarli.git/blame - assets/default/js/base.js
ESLint
[github/shaarli/Shaarli.git] / assets / default / js / base.js
CommitLineData
a33c5653 1import Awesomplete from 'awesomplete';
4cf3564d 2import he from 'he';
b9b41d25 3
82e3bb5f
A
4/**
5 * Find a parent element according to its tag and its attributes
6 *
7 * @param element Element where to start the search
8 * @param tagName Expected parent tag name
9 * @param attributes Associative array of expected attributes (name=>value).
10 *
11 * @returns Found element or null.
12 */
a33c5653 13function findParent(element, tagName, attributes) {
9192a48b 14 const parentMatch = (key) => attributes[key] !== '' && element.getAttribute(key).indexOf(attributes[key]) !== -1;
a33c5653
A
15 while (element) {
16 if (element.tagName.toLowerCase() === tagName) {
17 if (Object.keys(attributes).find(parentMatch)) {
18 return element;
19 }
aa4797ba 20 }
a33c5653
A
21 element = element.parentElement;
22 }
23 return null;
aa4797ba
A
24}
25
82e3bb5f
A
26/**
27 * Ajax request to refresh the CSRF token.
28 */
cd10bc23 29function refreshToken(basePath, callback) {
a33c5653 30 const xhr = new XMLHttpRequest();
764d34a7 31 xhr.open('GET', `${basePath}/admin/token`);
a33c5653 32 xhr.onload = () => {
301c7ab1
A
33 const elements = document.querySelectorAll('input[name="token"]');
34 [...elements].forEach((element) => {
301c7ab1
A
35 element.setAttribute('value', xhr.responseText);
36 });
cd10bc23
A
37
38 if (callback) {
39 callback(xhr.response);
40 }
a33c5653
A
41 };
42 xhr.send();
43}
44
b3bd8c3e 45function createAwesompleteInstance(element, separator, tags = []) {
a33c5653 46 const awesome = new Awesomplete(Awesomplete.$(element));
b3bd8c3e
A
47
48 // Tags are separated by separator
49 awesome.filter = (text, input) => Awesomplete.FILTER_CONTAINS(text, input.match(new RegExp(`[^${separator}]*$`))[0]);
a33c5653
A
50 // Insert new selected tag in the input
51 awesome.replace = (text) => {
b3bd8c3e
A
52 const before = awesome.input.value.match(new RegExp(`^.+${separator}+|`))[0];
53 awesome.input.value = `${before}${text}${separator}`;
a33c5653
A
54 };
55 // Highlight found items
b3bd8c3e 56 awesome.item = (text, input) => Awesomplete.ITEM(text, input.match(new RegExp(`[^${separator}]*$`))[0]);
a33c5653 57 // Don't display already selected items
8a1ce1da
A
58 // WARNING: pseudo classes does not seem to work with string litterals...
59 const reg = new RegExp(`([^${separator}]+)${separator}`, 'g');
a33c5653
A
60 let match;
61 awesome.data = (item, input) => {
62 while ((match = reg.exec(input))) {
63 if (item === match[1]) {
64 return '';
65 }
66 }
67 return item;
68 };
69 awesome.minChars = 1;
70 if (tags.length) {
71 awesome.list = tags;
72 }
73
74 return awesome;
aa4797ba
A
75}
76
82e3bb5f
A
77/**
78 * Update awesomplete list of tag for all elements matching the given selector
79 *
80 * @param selector CSS selector
81 * @param tags Array of tags
82 * @param instances List of existing awesomplete instances
b3bd8c3e 83 * @param separator Tags separator character
82e3bb5f 84 */
b3bd8c3e 85function updateAwesompleteList(selector, tags, instances, separator) {
a33c5653 86 if (instances.length === 0) {
82e3bb5f 87 // First load: create Awesomplete instances
a33c5653
A
88 const elements = document.querySelectorAll(selector);
89 [...elements].forEach((element) => {
b3bd8c3e 90 instances.push(createAwesompleteInstance(element, separator, tags));
a33c5653
A
91 });
92 } else {
93 // Update awesomplete tag list
94 instances.map((item) => {
95 item.list = tags;
96 return item;
97 });
98 }
99 return instances;
82e3bb5f
A
100}
101
a0737313
A
102/**
103 * Add the class 'hidden' to city options not attached to the current selected continent.
104 *
105 * @param cities List of <option> elements
106 * @param currentContinent Current selected continent
107 * @param reset Set to true to reset the selected value
108 */
a33c5653
A
109function hideTimezoneCities(cities, currentContinent, reset = null) {
110 let first = true;
111 if (reset == null) {
112 reset = false;
113 }
114 [...cities].forEach((option) => {
115 if (option.getAttribute('data-continent') !== currentContinent) {
116 option.className = 'hidden';
117 } else {
118 option.className = '';
119 if (reset === true && first === true) {
120 option.setAttribute('selected', 'selected');
121 first = false;
122 }
aa4797ba 123 }
a33c5653
A
124 });
125}
126
127/**
128 * Retrieve an element up in the tree from its class name.
129 */
130function getParentByClass(el, className) {
131 const p = el.parentNode;
132 if (p == null || p.classList.contains(className)) {
133 return p;
134 }
135 return getParentByClass(p, className);
136}
137
138function toggleHorizontal() {
139 [...document.getElementById('shaarli-menu').querySelectorAll('.menu-transform')].forEach((el) => {
140 el.classList.toggle('pure-menu-horizontal');
141 });
142}
143
144function toggleMenu(menu) {
145 // set timeout so that the panel has a chance to roll up
146 // before the menu switches states
147 if (menu.classList.contains('open')) {
148 setTimeout(toggleHorizontal, 500);
149 } else {
150 toggleHorizontal();
151 }
152 menu.classList.toggle('open');
153 document.getElementById('menu-toggle').classList.toggle('x');
154}
155
156function closeMenu(menu) {
157 if (menu.classList.contains('open')) {
158 toggleMenu(menu);
159 }
160}
161
162function toggleFold(button, description, thumb) {
163 // Switch fold/expand - up = fold
164 if (button.classList.contains('fa-chevron-up')) {
165 button.title = document.getElementById('translation-expand').innerHTML;
166 if (description != null) {
167 description.style.display = 'none';
168 }
169 if (thumb != null) {
170 thumb.style.display = 'none';
171 }
172 } else {
173 button.title = document.getElementById('translation-fold').innerHTML;
174 if (description != null) {
175 description.style.display = 'block';
176 }
177 if (thumb != null) {
178 thumb.style.display = 'block';
179 }
180 }
181 button.classList.toggle('fa-chevron-down');
182 button.classList.toggle('fa-chevron-up');
183}
184
185function removeClass(element, classname) {
186 element.className = element.className.replace(new RegExp(`(?:^|\\s)${classname}(?:\\s|$)`), ' ');
187}
188
189function init(description) {
190 function resize() {
191 /* Fix jumpy resizing: https://stackoverflow.com/a/18262927/1484919 */
9192a48b
A
192 const scrollTop = window.pageYOffset
193 || (document.documentElement || document.body.parentNode || document.body).scrollTop;
a33c5653
A
194
195 description.style.height = 'auto';
196 description.style.height = `${description.scrollHeight + 10}px`;
197
198 window.scrollTo(0, scrollTop);
199 }
200
201 /* 0-timeout to get the already changed text */
202 function delayedResize() {
203 window.setTimeout(resize, 0);
204 }
205
206 const observe = (element, event, handler) => {
207 element.addEventListener(event, handler, false);
208 };
209 observe(description, 'change', resize);
210 observe(description, 'cut', delayedResize);
211 observe(description, 'paste', delayedResize);
212 observe(description, 'drop', delayedResize);
213 observe(description, 'keydown', delayedResize);
214
215 resize();
216}
217
218(() => {
818b3193 219 const basePath = document.querySelector('input[name="js_base_path"]').value;
b3bd8c3e 220 const tagsSeparatorElement = document.querySelector('input[name="tags_separator"]');
df9aac5b 221 const tagsSeparator = tagsSeparatorElement ? tagsSeparatorElement.value || ' ' : ' ';
818b3193 222
a33c5653
A
223 /**
224 * Handle responsive menu.
225 * Source: http://purecss.io/layouts/tucked-menu-vertical/
226 */
227 const menu = document.getElementById('shaarli-menu');
228 const WINDOW_CHANGE_EVENT = ('onorientationchange' in window) ? 'orientationchange' : 'resize';
229
230 const menuToggle = document.getElementById('menu-toggle');
231 if (menuToggle != null) {
232 menuToggle.addEventListener('click', () => toggleMenu(menu));
233 }
234
235 window.addEventListener(WINDOW_CHANGE_EVENT, () => closeMenu(menu));
236
237 /**
238 * Fold/Expand shaares description and thumbnail.
239 */
240 const foldAllButtons = document.getElementsByClassName('fold-all');
241 const foldButtons = document.getElementsByClassName('fold-button');
242
243 [...foldButtons].forEach((foldButton) => {
244 // Retrieve description
245 let description = null;
246 let thumbnail = null;
247 const linklistItem = getParentByClass(foldButton, 'linklist-item');
248 if (linklistItem != null) {
249 description = linklistItem.querySelector('.linklist-item-description');
250 thumbnail = linklistItem.querySelector('.linklist-item-thumbnail');
251 if (description != null || thumbnail != null) {
252 foldButton.style.display = 'inline';
253 }
254 }
255
256 foldButton.addEventListener('click', (event) => {
257 event.preventDefault();
258 toggleFold(event.target, description, thumbnail);
259 });
260 });
261
262 if (foldAllButtons != null) {
263 [].forEach.call(foldAllButtons, (foldAllButton) => {
264 foldAllButton.addEventListener('click', (event) => {
265 event.preventDefault();
266 const state = foldAllButton.firstElementChild.getAttribute('class').indexOf('down') !== -1 ? 'down' : 'up';
267 [].forEach.call(foldButtons, (foldButton) => {
268 if ((foldButton.firstElementChild.classList.contains('fa-chevron-up') && state === 'down')
269 || (foldButton.firstElementChild.classList.contains('fa-chevron-down') && state === 'up')
270 ) {
271 return;
272 }
273 // Retrieve description
274 let description = null;
275 let thumbnail = null;
276 const linklistItem = getParentByClass(foldButton, 'linklist-item');
277 if (linklistItem != null) {
278 description = linklistItem.querySelector('.linklist-item-description');
279 thumbnail = linklistItem.querySelector('.linklist-item-thumbnail');
280 if (description != null || thumbnail != null) {
281 foldButton.style.display = 'inline';
282 }
283 }
284
285 toggleFold(foldButton.firstElementChild, description, thumbnail);
286 });
287 foldAllButton.firstElementChild.classList.toggle('fa-chevron-down');
288 foldAllButton.firstElementChild.classList.toggle('fa-chevron-up');
289 foldAllButton.title = state === 'down'
290 ? document.getElementById('translation-fold-all').innerHTML
291 : document.getElementById('translation-expand-all').innerHTML;
292 });
293 });
294 }
295
296 /**
297 * Confirmation message before deletion.
298 */
299 const deleteLinks = document.querySelectorAll('.confirm-delete');
300 [...deleteLinks].forEach((deleteLink) => {
301 deleteLink.addEventListener('click', (event) => {
5f987a64
A
302 const type = event.currentTarget.getAttribute('data-type') || 'link';
303 if (!confirm(document.getElementById(`translation-delete-${type}`).innerHTML)) {
a33c5653
A
304 event.preventDefault();
305 }
306 });
307 });
308
309 /**
310 * Close alerts
311 */
312 const closeLinks = document.querySelectorAll('.pure-alert-close');
313 [...closeLinks].forEach((closeLink) => {
314 closeLink.addEventListener('click', (event) => {
315 const alert = getParentByClass(event.target, 'pure-alert-closable');
316 alert.style.display = 'none';
317 });
318 });
319
320 /**
321 * New version dismiss.
322 * Hide the message for one week using localStorage.
323 */
324 const newVersionDismiss = document.getElementById('new-version-dismiss');
325 const newVersionMessage = document.querySelector('.new-version-message');
326 if (newVersionMessage != null
327 && localStorage.getItem('newVersionDismiss') != null
328 && parseInt(localStorage.getItem('newVersionDismiss'), 10) + (7 * 24 * 60 * 60 * 1000) > (new Date()).getTime()
329 ) {
330 newVersionMessage.style.display = 'none';
331 }
332 if (newVersionDismiss != null) {
333 newVersionDismiss.addEventListener('click', () => {
334 localStorage.setItem('newVersionDismiss', (new Date()).getTime().toString());
335 });
336 }
337
338 const hiddenReturnurl = document.getElementsByName('returnurl');
339 if (hiddenReturnurl != null) {
340 hiddenReturnurl.value = window.location.href;
341 }
342
343 /**
344 * Autofocus text fields
345 */
346 const autofocusElements = document.querySelectorAll('.autofocus');
347 let breakLoop = false;
348 [].forEach.call(autofocusElements, (autofocusElement) => {
349 if (autofocusElement.value === '' && !breakLoop) {
350 autofocusElement.focus();
351 breakLoop = true;
352 }
353 });
354
355 /**
356 * Handle sub menus/forms
357 */
358 const openers = document.getElementsByClassName('subheader-opener');
359 if (openers != null) {
360 [...openers].forEach((opener) => {
361 opener.addEventListener('click', (event) => {
362 event.preventDefault();
363
364 const id = opener.getAttribute('data-open-id');
365 const sub = document.getElementById(id);
366
367 if (sub != null) {
368 [...document.getElementsByClassName('subheader-form')].forEach((element) => {
369 if (element !== sub) {
370 removeClass(element, 'open');
a0737313 371 }
a33c5653
A
372 });
373
374 sub.classList.toggle('open');
a0737313 375 }
a33c5653 376 });
a0737313 377 });
a33c5653
A
378 }
379
380 /**
381 * Remove CSS target padding (for fixed bar)
382 */
383 if (location.hash !== '') {
384 const anchor = document.getElementById(location.hash.substr(1));
385 if (anchor != null) {
386 const padsize = anchor.clientHeight;
387 window.scroll(0, window.scrollY - padsize);
388 anchor.style.paddingTop = '0';
389 }
390 }
391
392 /**
393 * Text area resizer
394 */
395 const description = document.getElementById('lf_description');
396
397 if (description != null) {
398 init(description);
399 // Submit editlink form with CTRL + Enter in the text area.
400 description.addEventListener('keydown', (event) => {
401 if (event.ctrlKey && event.keyCode === 13) {
402 document.getElementById('button-save-edit').click();
403 }
404 });
405 }
406
407 /**
408 * Bookmarklet alert
409 */
410 const bookmarkletLinks = document.querySelectorAll('.bookmarklet-link');
411 const bkmMessage = document.getElementById('bookmarklet-alert');
412 [].forEach.call(bookmarkletLinks, (link) => {
413 link.addEventListener('click', (event) => {
414 event.preventDefault();
415 alert(bkmMessage.value);
416 });
417 });
418
a33c5653
A
419 const continent = document.getElementById('continent');
420 const city = document.getElementById('city');
421 if (continent != null && city != null) {
422 continent.addEventListener('change', () => {
423 hideTimezoneCities(city, continent.options[continent.selectedIndex].value, true);
424 });
425 hideTimezoneCities(city, continent.options[continent.selectedIndex].value, false);
426 }
427
428 /**
429 * Bulk actions
430 */
fc574e64 431 const linkCheckboxes = document.querySelectorAll('.link-checkbox');
a33c5653
A
432 const bar = document.getElementById('actions');
433 [...linkCheckboxes].forEach((checkbox) => {
434 checkbox.style.display = 'inline-block';
fc574e64
A
435 checkbox.addEventListener('change', () => {
436 const linkCheckedCheckboxes = document.querySelectorAll('.link-checkbox:checked');
a33c5653
A
437 const count = [...linkCheckedCheckboxes].length;
438 if (count === 0 && bar.classList.contains('open')) {
439 bar.classList.toggle('open');
440 } else if (count > 0 && !bar.classList.contains('open')) {
441 bar.classList.toggle('open');
442 }
443 });
444 });
445
446 const deleteButton = document.getElementById('actions-delete');
447 const token = document.getElementById('token');
448 if (deleteButton != null && token != null) {
449 deleteButton.addEventListener('click', (event) => {
450 event.preventDefault();
451
452 const links = [];
fc574e64 453 const linkCheckedCheckboxes = document.querySelectorAll('.link-checkbox:checked');
a33c5653
A
454 [...linkCheckedCheckboxes].forEach((checkbox) => {
455 links.push({
456 id: checkbox.value,
457 title: document.querySelector(`.linklist-item[data-id="${checkbox.value}"] .linklist-link`).innerHTML,
458 });
459 });
460
461 let message = `Are you sure you want to delete ${links.length} links?\n`;
462 message += 'This action is IRREVERSIBLE!\n\nTitles:\n';
463 const ids = [];
464 links.forEach((item) => {
465 message += ` - ${item.title}\n`;
466 ids.push(item.id);
467 });
468
469 if (window.confirm(message)) {
9c75f877 470 window.location = `${basePath}/admin/shaare/delete?id=${ids.join('+')}&token=${token.value}`;
a33c5653
A
471 }
472 });
473 }
474
8d03f705
A
475 const changeVisibilityButtons = document.querySelectorAll('.actions-change-visibility');
476 if (changeVisibilityButtons != null && token != null) {
477 [...changeVisibilityButtons].forEach((button) => {
478 button.addEventListener('click', (event) => {
479 event.preventDefault();
480 const visibility = event.target.getAttribute('data-visibility');
481
482 const links = [];
483 const linkCheckedCheckboxes = document.querySelectorAll('.link-checkbox:checked');
484 [...linkCheckedCheckboxes].forEach((checkbox) => {
485 links.push({
486 id: checkbox.value,
487 title: document.querySelector(`.linklist-item[data-id="${checkbox.value}"] .linklist-link`).innerHTML,
488 });
489 });
490
9192a48b
A
491 const ids = links.map((item) => item.id);
492 window.location = (
493 `${basePath}/admin/shaare/visibility?token=${token.value}&newVisibility=${visibility}&id=${ids.join('+')}`
494 );
8d03f705
A
495 });
496 });
497 }
498
fc574e64
A
499 /**
500 * Select all button
501 */
502 const selectAllButtons = document.querySelectorAll('.select-all-button');
503 [...selectAllButtons].forEach((selectAllButton) => {
504 selectAllButton.addEventListener('click', (e) => {
505 e.preventDefault();
506 const checked = selectAllButton.classList.contains('filter-off');
507 [...selectAllButtons].forEach((selectAllButton2) => {
508 selectAllButton2.classList.toggle('filter-off');
509 selectAllButton2.classList.toggle('filter-on');
510 });
511 [...linkCheckboxes].forEach((linkCheckbox) => {
512 linkCheckbox.checked = checked;
513 linkCheckbox.dispatchEvent(new Event('change'));
514 });
515 });
516 });
517
a33c5653
A
518 /**
519 * Tag list operations
520 *
521 * TODO: support error code in the backend for AJAX requests
522 */
523 const tagList = document.querySelector('input[name="taglist"]');
524 let existingTags = tagList ? tagList.value.split(' ') : [];
525 let awesomepletes = [];
526
527 // Display/Hide rename form
528 const renameTagButtons = document.querySelectorAll('.rename-tag');
529 [...renameTagButtons].forEach((rename) => {
530 rename.addEventListener('click', (event) => {
531 event.preventDefault();
532 const block = findParent(event.target, 'div', { class: 'tag-list-item' });
533 const form = block.querySelector('.rename-tag-form');
534 if (form.style.display === 'none' || form.style.display === '') {
535 form.style.display = 'block';
536 } else {
537 form.style.display = 'none';
538 }
539 block.querySelector('input').focus();
540 });
541 });
542
543 // Rename a tag with an AJAX request
544 const renameTagSubmits = document.querySelectorAll('.validate-rename-tag');
545 [...renameTagSubmits].forEach((rename) => {
546 rename.addEventListener('click', (event) => {
547 event.preventDefault();
548 const block = findParent(event.target, 'div', { class: 'tag-list-item' });
549 const input = block.querySelector('.rename-tag-input');
550 const totag = input.value.replace('/"/g', '\\"');
551 if (totag.trim() === '') {
552 return;
553 }
554 const refreshedToken = document.getElementById('token').value;
555 const fromtag = block.getAttribute('data-tag');
72fbbcd6 556 const fromtagUrl = block.getAttribute('data-tag-url');
a33c5653 557 const xhr = new XMLHttpRequest();
9c75f877 558 xhr.open('POST', `${basePath}/admin/tags`);
a33c5653
A
559 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
560 xhr.onload = () => {
561 if (xhr.status !== 200) {
562 alert(`An error occurred. Return code: ${xhr.status}`);
563 location.reload();
564 } else {
565 block.setAttribute('data-tag', totag);
72fbbcd6 566 block.setAttribute('data-tag-url', encodeURIComponent(totag));
a33c5653
A
567 input.setAttribute('name', totag);
568 input.setAttribute('value', totag);
569 findParent(input, 'div', { class: 'rename-tag-form' }).style.display = 'none';
4cf3564d 570 block.querySelector('a.tag-link').innerHTML = he.encode(totag);
818b3193
A
571 block
572 .querySelector('a.tag-link')
573 .setAttribute('href', `${basePath}/?searchtags=${encodeURIComponent(totag)}`);
72fbbcd6
A
574 block
575 .querySelector('a.count')
576 .setAttribute('href', `${basePath}/add-tag/${encodeURIComponent(totag)}`);
818b3193
A
577 block
578 .querySelector('a.rename-tag')
9c75f877 579 .setAttribute('href', `${basePath}/admin/tags?fromtag=${encodeURIComponent(totag)}`);
a33c5653
A
580
581 // Refresh awesomplete values
9192a48b 582 existingTags = existingTags.map((tag) => (tag === fromtag ? totag : tag));
b3bd8c3e 583 awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes, tagsSeparator);
a33c5653
A
584 }
585 };
72fbbcd6 586 xhr.send(`renametag=1&fromtag=${fromtagUrl}&totag=${encodeURIComponent(totag)}&token=${refreshedToken}`);
818b3193 587 refreshToken(basePath);
a33c5653
A
588 });
589 });
590
591 // Validate input with enter key
592 const renameTagInputs = document.querySelectorAll('.rename-tag-input');
593 [...renameTagInputs].forEach((rename) => {
594 rename.addEventListener('keypress', (event) => {
595 if (event.keyCode === 13) { // enter
596 findParent(event.target, 'div', { class: 'tag-list-item' }).querySelector('.validate-rename-tag').click();
597 }
598 });
599 });
600
601 // Delete a tag with an AJAX query (alert popup confirmation)
602 const deleteTagButtons = document.querySelectorAll('.delete-tag');
603 [...deleteTagButtons].forEach((rename) => {
604 rename.style.display = 'inline';
605 rename.addEventListener('click', (event) => {
606 event.preventDefault();
607 const block = findParent(event.target, 'div', { class: 'tag-list-item' });
608 const tag = block.getAttribute('data-tag');
72fbbcd6 609 const tagUrl = block.getAttribute('data-tag-url');
4fa9a3c5 610 const refreshedToken = document.getElementById('token').value;
a33c5653
A
611
612 if (confirm(`Are you sure you want to delete the tag "${tag}"?`)) {
613 const xhr = new XMLHttpRequest();
9c75f877 614 xhr.open('POST', `${basePath}/admin/tags`);
a33c5653
A
615 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
616 xhr.onload = () => {
617 block.remove();
618 };
72fbbcd6 619 xhr.send(`deletetag=1&fromtag=${tagUrl}&token=${refreshedToken}`);
818b3193 620 refreshToken(basePath);
a33c5653 621
9192a48b 622 existingTags = existingTags.filter((tagItem) => tagItem !== tag);
b3bd8c3e 623 awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes, tagsSeparator);
a33c5653
A
624 }
625 });
626 });
627
628 const autocompleteFields = document.querySelectorAll('input[data-multiple]');
629 [...autocompleteFields].forEach((autocompleteField) => {
b3bd8c3e 630 awesomepletes.push(createAwesompleteInstance(autocompleteField, tagsSeparator));
a33c5653 631 });
cd10bc23
A
632
633 const exportForm = document.querySelector('#exportform');
634 if (exportForm != null) {
635 exportForm.addEventListener('submit', (event) => {
636 event.preventDefault();
637
638 refreshToken(basePath, () => {
639 event.target.submit();
640 });
641 });
642 }
5d8de758
A
643
644 const bulkCreationButton = document.querySelector('.addlink-batch-show-more-block');
645 if (bulkCreationButton != null) {
646 const toggleBulkCreationVisibility = (showMoreBlockElement, formElement) => {
647 if (bulkCreationButton.classList.contains('pure-u-0')) {
648 showMoreBlockElement.classList.remove('pure-u-0');
649 formElement.classList.add('pure-u-0');
650 } else {
651 showMoreBlockElement.classList.add('pure-u-0');
652 formElement.classList.remove('pure-u-0');
653 }
654 };
655
656 const bulkCreationForm = document.querySelector('.addlink-batch-form-block');
657
658 toggleBulkCreationVisibility(bulkCreationButton, bulkCreationForm);
659 bulkCreationButton.querySelector('a').addEventListener('click', (e) => {
660 e.preventDefault();
661 toggleBulkCreationVisibility(bulkCreationButton, bulkCreationForm);
662 });
25e90d8d
A
663
664 // Force to send falsy value if the checkbox is not checked.
665 const privateButton = bulkCreationForm.querySelector('input[type="checkbox"][name="private"]');
666 const privateHiddenButton = bulkCreationForm.querySelector('input[type="hidden"][name="private"]');
667 privateButton.addEventListener('click', () => {
668 privateHiddenButton.disabled = !privateHiddenButton.disabled;
669 });
670 privateHiddenButton.disabled = privateButton.checked;
5d8de758 671 }
a33c5653 672})();