aboutsummaryrefslogtreecommitdiffhomepage
path: root/tpl/default
diff options
context:
space:
mode:
Diffstat (limited to 'tpl/default')
-rw-r--r--tpl/default/changetag.html4
-rw-r--r--tpl/default/css/shaarli.css128
-rw-r--r--tpl/default/editlink.html9
-rw-r--r--tpl/default/includes.html2
-rw-r--r--tpl/default/js/shaarli.js265
-rw-r--r--tpl/default/linklist.html51
-rw-r--r--tpl/default/linklist.paging.html11
-rw-r--r--tpl/default/page.footer.html5
-rw-r--r--tpl/default/page.header.html40
-rw-r--r--tpl/default/tag.cloud.html69
-rw-r--r--tpl/default/tag.list.html89
-rw-r--r--tpl/default/tag.sort.html8
-rw-r--r--tpl/default/tagcloud.html42
-rw-r--r--tpl/default/tools.html25
14 files changed, 608 insertions, 140 deletions
diff --git a/tpl/default/changetag.html b/tpl/default/changetag.html
index 8d263a16..49dd20d9 100644
--- a/tpl/default/changetag.html
+++ b/tpl/default/changetag.html
@@ -11,7 +11,7 @@
11 <h2 class="window-title">{"Manage tags"|t}</h2> 11 <h2 class="window-title">{"Manage tags"|t}</h2>
12 <form method="POST" action="#" name="changetag" id="changetag"> 12 <form method="POST" action="#" name="changetag" id="changetag">
13 <div> 13 <div>
14 <input type="text" name="fromtag" placeholder="{'Tag'|t}" 14 <input type="text" name="fromtag" placeholder="{'Tag'|t}" value="{$fromtag}"
15 list="tagsList" autocomplete="off" class="awesomplete autofocus" data-minChars="1"> 15 list="tagsList" autocomplete="off" class="awesomplete autofocus" data-minChars="1">
16 <datalist id="tagsList"> 16 <datalist id="tagsList">
17 {loop="$tags"}<option>{$key}</option>{/loop} 17 {loop="$tags"}<option>{$key}</option>{/loop}
@@ -31,6 +31,8 @@
31 <input type="submit" value="{'Delete'|t}" name="deletetag" class="button button-red confirm-delete"> 31 <input type="submit" value="{'Delete'|t}" name="deletetag" class="button button-red confirm-delete">
32 </div> 32 </div>
33 </form> 33 </form>
34
35 <p>You can also edit tags in the <a href="?do=taglist&sort=usage">tag list</a>.</p>
34 </div> 36 </div>
35</div> 37</div>
36{include="page.footer"} 38{include="page.footer"}
diff --git a/tpl/default/css/shaarli.css b/tpl/default/css/shaarli.css
index 73fade5f..e1868c59 100644
--- a/tpl/default/css/shaarli.css
+++ b/tpl/default/css/shaarli.css
@@ -211,7 +211,7 @@ body, .pure-g [class*="pure-u"] {
211 } 211 }
212} 212}
213 213
214#search, #search-linklist { 214#search, #search-linklist, #search-tagcloud {
215 text-align: center; 215 text-align: center;
216 width: 100%; 216 width: 100%;
217} 217}
@@ -226,6 +226,12 @@ body, .pure-g [class*="pure-u"] {
226 border-radius: 2px; 226 border-radius: 2px;
227 color: #252525; 227 color: #252525;
228} 228}
229@media screen and (max-width: 64em) {
230 .searchform {
231 max-width: 260px;
232 margin: 0 auto;
233 }
234}
229 235
230/* because chrome */ 236/* because chrome */
231#search input[type="text"]::-webkit-input-placeholder, 237#search input[type="text"]::-webkit-input-placeholder,
@@ -234,47 +240,58 @@ body, .pure-g [class*="pure-u"] {
234} 240}
235 241
236#search button, 242#search button,
243#search-tagcloud button,
237#search-linklist button { 244#search-linklist button {
238 background: transparent; 245 padding: 4px 8px 6px 8px;
246 background-color: #1B926C;
247 color: #f5f5f5;
239 border: none; 248 border: none;
249 border-radius: 2px;
240} 250}
241 251
242#search button { 252#search-tagcloud button {
243 color: #f5f5f5; 253 width: 90%;
244} 254}
245 255
246#search-linklist button { 256@media screen and (max-width: 64em) {
247 color: #252525; 257 #search-linklist button {
258 width: 100%;
259 }
260 #search-linklist .awesomplete {
261 margin: 5px 0;
262 }
248} 263}
249 264
250#search button:hover, 265#search button:hover,
251#search-linklist button:hover { 266#search-linklist button:hover,
252 color: #fff; 267#search-tagcloud button:hover {
268 color: #d0d0d0;
253} 269}
254 270
271#search,
255#search-linklist { 272#search-linklist {
256 padding: 5px 0; 273 padding: 6px 0;
257} 274}
258 275
259@media screen and (min-width: 64em) {
260 #search .searchform,
261 #search-linklist .searchform {
262 margin-right: 25px;
263 text-align: right;
264 }
265
266 #search .tagfilter,
267 #search-linklist .tagfilter {
268 margin-left: 25px;
269 text-align: left;
270 }
271}
272@media screen and (max-width: 64em) { 276@media screen and (max-width: 64em) {
273 #search, #search * { 277 #search, #search * {
274 visibility: hidden; 278 visibility: hidden;
275 } 279 }
276} 280}
277 281
282.subheader-form a.button {
283 color: #f5f5f5;
284 font-weight: bold;
285 text-decoration: none;
286 border: 2px solid #f5f5f5;
287 border-radius: 5px;
288 padding: 3px 10px;
289}
290
291.linklist-item-editbuttons .delete-checkbox {
292 display: none;
293}
294
278#header-login-form input[type="text"], #header-login-form input[type="password"] { 295#header-login-form input[type="text"], #header-login-form input[type="password"] {
279 width: 200px; 296 width: 200px;
280} 297}
@@ -304,7 +321,6 @@ body, .pure-g [class*="pure-u"] {
304} 321}
305 322
306.subheader-form input[type="text"], .subheader-form input[type="password"], .subheader-form .remember-me { 323.subheader-form input[type="text"], .subheader-form input[type="password"], .subheader-form .remember-me {
307 margin: 0 0 5px 0;
308 padding: 5px 5px 3px 15px; 324 padding: 5px 5px 3px 15px;
309 height: 20px; 325 height: 20px;
310 width: 20%; 326 width: 20%;
@@ -522,8 +538,8 @@ body, .pure-g [class*="pure-u"] {
522 color: #1b926c; 538 color: #1b926c;
523} 539}
524 540
525.linklist-item-title .linklist-link:visited { 541.linklist-item-title a:visited .linklist-link {
526 color: #1b926c; 542 color: #555555;
527} 543}
528 544
529.linklist-item-title a:hover, .linklist-item-title .linklist-link:hover{ 545.linklist-item-title a:hover, .linklist-item-title .linklist-link:hover{
@@ -734,10 +750,11 @@ body, .pure-g [class*="pure-u"] {
734.page-form a { 750.page-form a {
735 color: #1b926c; 751 color: #1b926c;
736 font-weight: bold; 752 font-weight: bold;
753 text-decoration: none;
737} 754}
738 755
739.page-form p { 756.page-form p {
740 padding: 0 10px; 757 padding: 5px 10px;
741 margin: 0; 758 margin: 0;
742} 759}
743 760
@@ -975,6 +992,14 @@ form[name="linkform"].page-form {
975} 992}
976 993
977/** 994/**
995 * EDIT LINK
996 */
997#editlinkform .created-date {
998 color: #767676;
999 margin-bottom: 10px;
1000}
1001
1002/**
978 * LOGIN 1003 * LOGIN
979 */ 1004 */
980#login-form .remember-me { 1005#login-form .remember-me {
@@ -1053,7 +1078,7 @@ form[name="linkform"].page-form {
1053} 1078}
1054 1079
1055#cloudtag, #cloudtag a { 1080#cloudtag, #cloudtag a {
1056 color: #000; 1081 color: #252525;
1057 text-decoration: none; 1082 text-decoration: none;
1058} 1083}
1059 1084
@@ -1062,6 +1087,42 @@ form[name="linkform"].page-form {
1062} 1087}
1063 1088
1064/** 1089/**
1090 * TAG LIST
1091 */
1092#taglist {
1093 padding: 0 10px;
1094}
1095
1096#taglist a {
1097 color: #252525;
1098 text-decoration: none;
1099}
1100
1101#taglist .count {
1102 display: inline-block;
1103 width: 35px;
1104 text-align: right;
1105 color: #7f7f7f;
1106}
1107
1108#taglist .rename-tag-form {
1109 display: none;
1110}
1111
1112#taglist .delete-tag {
1113 color: #ac2925;
1114 display: none;
1115}
1116
1117#taglist .rename-tag {
1118 color: #0b5ea6;
1119}
1120
1121#taglist .validate-rename-tag {
1122 color: #1b926c;
1123}
1124
1125/**
1065 * Picture wall CSS 1126 * Picture wall CSS
1066 */ 1127 */
1067#picwall_container { 1128#picwall_container {
@@ -1210,3 +1271,16 @@ form[name="linkform"].page-form {
1210.pure-button { 1271.pure-button {
1211 -moz-user-select: auto; 1272 -moz-user-select: auto;
1212} 1273}
1274
1275.tag-sort {
1276 margin-top: 30px;
1277 text-align: center;
1278}
1279
1280.tag-sort a {
1281 display: inline-block;
1282 margin: 0 15px;
1283 color: white;
1284 text-decoration: none;
1285 font-weight: bold;
1286}
diff --git a/tpl/default/editlink.html b/tpl/default/editlink.html
index 354499a4..d03fd72f 100644
--- a/tpl/default/editlink.html
+++ b/tpl/default/editlink.html
@@ -8,11 +8,15 @@
8 <div id="editlinkform" class="pure-g"> 8 <div id="editlinkform" class="pure-g">
9 <div class="pure-u-lg-1-5 pure-u-1-24"></div> 9 <div class="pure-u-lg-1-5 pure-u-1-24"></div>
10 <form method="post" name="linkform" class="page-form pure-u-lg-3-5 pure-u-22-24 page-form page-form-light"> 10 <form method="post" name="linkform" class="page-form pure-u-lg-3-5 pure-u-22-24 page-form page-form-light">
11 <h2 class="window-title">{'Shaare'|t}</h2> 11 <h2 class="window-title">
12 {if="!$link_is_new"}{'Edit'|t}{/if}
13 {'Shaare'|t}
14 </h2>
12 <input type="hidden" name="lf_linkdate" value="{$link.linkdate}"> 15 <input type="hidden" name="lf_linkdate" value="{$link.linkdate}">
13 {if="isset($link.id)"} 16 {if="isset($link.id)"}
14 <input type="hidden" name="lf_id" value="{$link.id}"> 17 <input type="hidden" name="lf_id" value="{$link.id}">
15 {/if} 18 {/if}
19 {if="!$link_is_new"}<div class="created-date">{'Created:'|t} {$link.created|format_date}</div>{/if}
16 <div> 20 <div>
17 <label for="lf_url">{'URL'|t}</label> 21 <label for="lf_url">{'URL'|t}</label>
18 </div> 22 </div>
@@ -55,7 +59,8 @@
55 59
56 60
57 <div class="submit-buttons center"> 61 <div class="submit-buttons center">
58 <input type="submit" value="{'Save'|t}" name="save_edit" class="" id="button-save-edit"> 62 <input type="submit" name="save_edit" class="" id="button-save-edit"
63 value="{if="$link_is_new"}{'Save'|t}{else}{'Apply Changes'|t}{/if}">
59 {if="!$link_is_new"} 64 {if="!$link_is_new"}
60 <a href="?delete_link&amp;lf_linkdate={$link.id}&amp;token={$token}" 65 <a href="?delete_link&amp;lf_linkdate={$link.id}&amp;token={$token}"
61 title="" name="delete_link" class="button button-red confirm-delete"> 66 title="" name="delete_link" class="button button-red confirm-delete">
diff --git a/tpl/default/includes.html b/tpl/default/includes.html
index 91c6ca3b..0350ef66 100644
--- a/tpl/default/includes.html
+++ b/tpl/default/includes.html
@@ -11,7 +11,7 @@
11<link type="text/css" rel="stylesheet" href="css/font-awesome.min.css" /> 11<link type="text/css" rel="stylesheet" href="css/font-awesome.min.css" />
12<link type="text/css" rel="stylesheet" href="inc/awesomplete.css#" /> 12<link type="text/css" rel="stylesheet" href="inc/awesomplete.css#" />
13<link type="text/css" rel="stylesheet" href="css/shaarli.css" /> 13<link type="text/css" rel="stylesheet" href="css/shaarli.css" />
14{if="is_file('inc/user.css')"} 14{if="is_file('data/user.css')"}
15 <link type="text/css" rel="stylesheet" href="data/user.css#" /> 15 <link type="text/css" rel="stylesheet" href="data/user.css#" />
16{/if} 16{/if}
17{loop="$plugins_includes.css_files"} 17{loop="$plugins_includes.css_files"}
diff --git a/tpl/default/js/shaarli.js b/tpl/default/js/shaarli.js
index 4d47fcd0..4f49affa 100644
--- a/tpl/default/js/shaarli.js
+++ b/tpl/default/js/shaarli.js
@@ -216,14 +216,14 @@ window.onload = function () {
216 /** 216 /**
217 * Autofocus text fields 217 * Autofocus text fields
218 */ 218 */
219 // ES6 syntax 219 var autofocusElements = document.querySelectorAll('.autofocus');
220 let autofocusElements = document.querySelectorAll('.autofocus'); 220 var breakLoop = false;
221 for (let autofocusElement of autofocusElements) { 221 [].forEach.call(autofocusElements, function(autofocusElement) {
222 if (autofocusElement.value == '') { 222 if (autofocusElement.value == '' && ! breakLoop) {
223 autofocusElement.focus(); 223 autofocusElement.focus();
224 break; 224 breakLoop = true;
225 } 225 }
226 } 226 });
227 227
228 /** 228 /**
229 * Handle sub menus/forms 229 * Handle sub menus/forms
@@ -357,16 +357,256 @@ window.onload = function () {
357 var continent = document.getElementById('continent'); 357 var continent = document.getElementById('continent');
358 var city = document.getElementById('city'); 358 var city = document.getElementById('city');
359 if (continent != null && city != null) { 359 if (continent != null && city != null) {
360 continent.addEventListener('change', function(event) { 360 continent.addEventListener('change', function (event) {
361 hideTimezoneCities(city, continent.options[continent.selectedIndex].value, true); 361 hideTimezoneCities(city, continent.options[continent.selectedIndex].value, true);
362 }); 362 });
363 hideTimezoneCities(city, continent.options[continent.selectedIndex].value, false); 363 hideTimezoneCities(city, continent.options[continent.selectedIndex].value, false);
364 } 364 }
365
366 /**
367 * Bulk actions
368 */
369 var linkCheckboxes = document.querySelectorAll('.delete-checkbox');
370 var bar = document.getElementById('actions');
371 [].forEach.call(linkCheckboxes, function(checkbox) {
372 checkbox.style.display = 'block';
373 checkbox.addEventListener('click', function(event) {
374 var count = 0;
375 var linkCheckedCheckboxes = document.querySelectorAll('.delete-checkbox:checked');
376 [].forEach.call(linkCheckedCheckboxes, function(checkbox) {
377 count++;
378 });
379 if (count == 0 && bar.classList.contains('open')) {
380 bar.classList.toggle('open');
381 } else if (count > 0 && ! bar.classList.contains('open')) {
382 bar.classList.toggle('open');
383 }
384 });
385 });
386
387 var deleteButton = document.getElementById('actions-delete');
388 var token = document.querySelector('input[type="hidden"][name="token"]');
389 if (deleteButton != null && token != null) {
390 deleteButton.addEventListener('click', function(event) {
391 event.preventDefault();
392
393 var links = [];
394 var linkCheckedCheckboxes = document.querySelectorAll('.delete-checkbox:checked');
395 [].forEach.call(linkCheckedCheckboxes, function(checkbox) {
396 links.push({
397 'id': checkbox.value,
398 'title': document.querySelector('.linklist-item[data-id="'+ checkbox.value +'"] .linklist-link').innerHTML
399 });
400 });
401
402 var message = 'Are you sure you want to delete '+ links.length +' links?\n';
403 message += 'This action is IRREVERSIBLE!\n\nTitles:\n';
404 var ids = '';
405 links.forEach(function(item) {
406 message += ' - '+ item['title'] +'\n';
407 ids += item['id'] +'+';
408 });
409
410 if (window.confirm(message)) {
411 window.location = '?delete_link&lf_linkdate='+ ids +'&token='+ token.value;
412 }
413 });
414 }
415
416 /**
417 * Tag list operations
418 *
419 * TODO: support error code in the backend for AJAX requests
420 */
421 var tagList = document.querySelector('input[name="taglist"]');
422 var existingTags = tagList ? tagList.value.split(' ') : [];
423 var awesomepletes = [];
424
425 // Display/Hide rename form
426 var renameTagButtons = document.querySelectorAll('.rename-tag');
427 [].forEach.call(renameTagButtons, function(rename) {
428 rename.addEventListener('click', function(event) {
429 event.preventDefault();
430 var block = findParent(event.target, 'div', {'class': 'tag-list-item'});
431 var form = block.querySelector('.rename-tag-form');
432 if (form.style.display == 'none' || form.style.display == '') {
433 form.style.display = 'block';
434 } else {
435 form.style.display = 'none';
436 }
437 block.querySelector('input').focus();
438 });
439 });
440
441 // Rename a tag with an AJAX request
442 var renameTagSubmits = document.querySelectorAll('.validate-rename-tag');
443 [].forEach.call(renameTagSubmits, function(rename) {
444 rename.addEventListener('click', function(event) {
445 event.preventDefault();
446 var block = findParent(event.target, 'div', {'class': 'tag-list-item'});
447 var input = block.querySelector('.rename-tag-input');
448 var totag = input.value.replace('/"/g', '\\"');
449 if (totag.trim() == '') {
450 return;
451 }
452 var fromtag = block.getAttribute('data-tag');
453 var token = document.getElementById('token').value;
454
455 xhr = new XMLHttpRequest();
456 xhr.open('POST', '?do=changetag');
457 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
458 xhr.onload = function() {
459 if (xhr.status !== 200) {
460 alert('An error occurred. Return code: '+ xhr.status);
461 location.reload();
462 } else {
463 block.setAttribute('data-tag', totag);
464 input.setAttribute('name', totag);
465 input.setAttribute('value', totag);
466 findParent(input, 'div', {'class': 'rename-tag-form'}).style.display = 'none';
467 block.querySelector('a.tag-link').innerHTML = htmlEntities(totag);
468 block.querySelector('a.tag-link').setAttribute('href', '?searchtags='+ encodeURIComponent(totag));
469 block.querySelector('a.rename-tag').setAttribute('href', '?do=changetag&fromtag='+ encodeURIComponent(totag));
470
471 // Refresh awesomplete values
472 for (var key in existingTags) {
473 if (existingTags[key] == fromtag) {
474 existingTags[key] = totag;
475 }
476 }
477 awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes);
478 }
479 };
480 xhr.send('renametag=1&fromtag='+ encodeURIComponent(fromtag) +'&totag='+ encodeURIComponent(totag) +'&token='+ token);
481 refreshToken();
482 });
483 });
484
485 // Validate input with enter key
486 var renameTagInputs = document.querySelectorAll('.rename-tag-input');
487 [].forEach.call(renameTagInputs, function(rename) {
488
489 rename.addEventListener('keypress', function(event) {
490 if (event.keyCode === 13) { // enter
491 findParent(event.target, 'div', {'class': 'tag-list-item'}).querySelector('.validate-rename-tag').click();
492 }
493 });
494 });
495
496 // Delete a tag with an AJAX query (alert popup confirmation)
497 var deleteTagButtons = document.querySelectorAll('.delete-tag');
498 [].forEach.call(deleteTagButtons, function(rename) {
499 rename.style.display = 'inline';
500 rename.addEventListener('click', function(event) {
501 event.preventDefault();
502 var block = findParent(event.target, 'div', {'class': 'tag-list-item'});
503 var tag = block.getAttribute('data-tag');
504 var token = document.getElementById('token').value;
505
506 if (confirm('Are you sure you want to delete the tag "'+ tag +'"?')) {
507 xhr = new XMLHttpRequest();
508 xhr.open('POST', '?do=changetag');
509 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
510 xhr.onload = function() {
511 block.remove();
512 };
513 xhr.send(encodeURI('deletetag=1&fromtag='+ tag +'&token='+ token));
514 refreshToken();
515 }
516 });
517 });
518
519 updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes);
365}; 520};
366 521
522/**
523 * Find a parent element according to its tag and its attributes
524 *
525 * @param element Element where to start the search
526 * @param tagName Expected parent tag name
527 * @param attributes Associative array of expected attributes (name=>value).
528 *
529 * @returns Found element or null.
530 */
531function findParent(element, tagName, attributes)
532{
533 while (element) {
534 if (element.tagName.toLowerCase() == tagName) {
535 var match = true;
536 for (var key in attributes) {
537 if (! element.hasAttribute(key)
538 || (attributes[key] != '' && element.getAttribute(key).indexOf(attributes[key]) == -1)
539 ) {
540 match = false;
541 break;
542 }
543 }
544
545 if (match) {
546 return element;
547 }
548 }
549 element = element.parentElement;
550 }
551 return null;
552}
553
554/**
555 * Ajax request to refresh the CSRF token.
556 */
557function refreshToken()
558{
559 var xhr = new XMLHttpRequest();
560 xhr.open('GET', '?do=token');
561 xhr.onload = function() {
562 var token = document.getElementById('token');
563 token.setAttribute('value', xhr.responseText);
564 };
565 xhr.send();
566}
567
568/**
569 * Update awesomplete list of tag for all elements matching the given selector
570 *
571 * @param selector CSS selector
572 * @param tags Array of tags
573 * @param instances List of existing awesomplete instances
574 */
575function updateAwesompleteList(selector, tags, instances)
576{
577 // First load: create Awesomplete instances
578 if (instances.length == 0) {
579 var elements = document.querySelectorAll(selector);
580 [].forEach.call(elements, function (element) {
581 instances.push(new Awesomplete(
582 element,
583 {'list': tags}
584 ));
585 });
586 } else {
587 // Update awesomplete tag list
588 for (var key in instances) {
589 instances[key].list = tags;
590 }
591 }
592 return instances;
593}
594
595/**
596 * html_entities in JS
597 *
598 * @see http://stackoverflow.com/questions/18749591/encode-html-entities-in-javascript
599 */
600function htmlEntities(str)
601{
602 return str.replace(/[\u00A0-\u9999<>\&]/gim, function(i) {
603 return '&#'+i.charCodeAt(0)+';';
604 });
605}
606
367function activateFirefoxSocial(node) { 607function activateFirefoxSocial(node) {
368 var loc = location.href; 608 var loc = location.href;
369 var baseURL = loc.substring(0, loc.lastIndexOf("/")); 609 var baseURL = loc.substring(0, loc.lastIndexOf("/") + 1);
370 610
371 // Keeping the data separated (ie. not in the DOM) so that it's maintainable and diffable. 611 // Keeping the data separated (ie. not in the DOM) so that it's maintainable and diffable.
372 var data = { 612 var data = {
@@ -379,7 +619,7 @@ function activateFirefoxSocial(node) {
379 icon32URL: baseURL + "/images/favicon.ico", 619 icon32URL: baseURL + "/images/favicon.ico",
380 icon64URL: baseURL + "/images/favicon.ico", 620 icon64URL: baseURL + "/images/favicon.ico",
381 621
382 shareURL: baseURL + "{noparse}?post=%{url}&title=%{title}&description=%{text}&source=firefoxsocialapi{/noparse}", 622 shareURL: baseURL + "?post=%{url}&title=%{title}&description=%{text}&source=firefoxsocialapi",
383 homepageURL: baseURL 623 homepageURL: baseURL
384 }; 624 };
385 node.setAttribute("data-service", JSON.stringify(data)); 625 node.setAttribute("data-service", JSON.stringify(data));
@@ -395,9 +635,12 @@ function activateFirefoxSocial(node) {
395 * @param currentContinent Current selected continent 635 * @param currentContinent Current selected continent
396 * @param reset Set to true to reset the selected value 636 * @param reset Set to true to reset the selected value
397 */ 637 */
398function hideTimezoneCities(cities, currentContinent, reset = false) { 638function hideTimezoneCities(cities, currentContinent) {
399 var first = true; 639 var first = true;
400 [].forEach.call(cities, function(option) { 640 if (reset == null) {
641 reset = false;
642 }
643 [].forEach.call(cities, function (option) {
401 if (option.getAttribute('data-continent') != currentContinent) { 644 if (option.getAttribute('data-continent') != currentContinent) {
402 option.className = 'hidden'; 645 option.className = 'hidden';
403 } else { 646 } else {
diff --git a/tpl/default/linklist.html b/tpl/default/linklist.html
index 57ef4567..685821e3 100644
--- a/tpl/default/linklist.html
+++ b/tpl/default/linklist.html
@@ -15,32 +15,25 @@
15 {/if} 15 {/if}
16</div> 16</div>
17 17
18<input type="hidden" name="token" value="{$token}">
19
18<div id="search-linklist"> 20<div id="search-linklist">
19 21
20 <div class="pure-g"> 22 <form method="GET" class="pure-form searchform" name="searchform">
21 <div class="pure-u-1 pure-u-lg-1-2"> 23 <input type="text" tabindex="1" name="searchterm" class="searchterm" placeholder="{'Search text'|t}"
22 <form method="GET" class="searchform" name="searchform"> 24 {if="!empty($search_term)"}
23 <input type="text" tabindex="1" name="searchterm" placeholder="{'Search text'|t}" 25 value="{$search_term}"
24 {if="!empty($search_term)"} 26 {/if}
25 value="{$search_term}" 27 >
26 {/if} 28 <input type="text" tabindex="2" name="searchtags" class="searchtags" placeholder="{'Filter by tag'|t}"
27 > 29 {if="!empty($search_tags)"}
28 <button type="submit" class="search-button"><i class="fa fa-search"></i></button> 30 value="{$search_tags}"
29 </form> 31 {/if}
30 </div> 32 autocomplete="off" data-multiple data-autofirst data-minChars="1"
31 <div class="pure-u-1 pure-u-lg-1-2"> 33 data-list="{loop="$tags"}{$key}, {/loop}"
32 <form method="GET" class="tagfilter" name="tagfilter"> 34 >
33 <input type="text" tabindex="2" name="searchtags" placeholder="{'Filter by tag'|t}" 35 <button type="submit" class="search-button"><i class="fa fa-search"></i></button>
34 {if="!empty($search_tags)"} 36 </form>
35 value="{$search_tags}"
36 {/if}
37 autocomplete="off" data-multiple data-autofirst data-minChars="1"
38 data-list="{loop="$tags"}{$key}, {/loop}"
39 >
40 <button type="submit" class="search-button"><i class="fa fa-search"></i></button>
41 </form>
42 </div>
43 </div>
44</div> 37</div>
45 38
46{loop="$plugins_header.fields_toolbar"} 39{loop="$plugins_header.fields_toolbar"}
@@ -89,7 +82,7 @@
89 <div id="searchcriteria">{'Nothing found.'|t}</div> 82 <div id="searchcriteria">{'Nothing found.'|t}</div>
90 </div> 83 </div>
91 </div> 84 </div>
92 {elseif="!empty($search_term) or !empty($search_tags) or !empty($visibility)"} 85 {elseif="!empty($search_term) or $search_tags !== '' or !empty($visibility) or $untaggedonly"}
93 <div class="pure-g pure-alert pure-alert-success search-result"> 86 <div class="pure-g pure-alert pure-alert-success search-result">
94 <div class="pure-u-2-24"></div> 87 <div class="pure-u-2-24"></div>
95 <div class="pure-u-20-24"> 88 <div class="pure-u-20-24">
@@ -112,6 +105,11 @@
112 {$visibility|t} 105 {$visibility|t}
113 </span> 106 </span>
114 {/if} 107 {/if}
108 {if="$untaggedonly"}
109 <span class="label label-private">
110 {'without any tag'|t}
111 </span>
112 {/if}
115 </div> 113 </div>
116 </div> 114 </div>
117 {/if} 115 {/if}
@@ -121,7 +119,7 @@
121 <div class="pure-u-lg-20-24 pure-u-22-24"> 119 <div class="pure-u-lg-20-24 pure-u-22-24">
122 {loop="links"} 120 {loop="links"}
123 <div class="anchor" id="{$value.shorturl}"></div> 121 <div class="anchor" id="{$value.shorturl}"></div>
124 <div class="linklist-item{if="$value.class"} {$value.class}{/if}"> 122 <div class="linklist-item linklist-item{if="$value.class"} {$value.class}{/if}" data-id="{$value.id}">
125 123
126 <div class="linklist-item-title"> 124 <div class="linklist-item-title">
127 {if="isLoggedIn()"} 125 {if="isLoggedIn()"}
@@ -129,6 +127,7 @@
129 {if="$value.private"} 127 {if="$value.private"}
130 <span class="label label-private">{'Private'|t}</span> 128 <span class="label label-private">{'Private'|t}</span>
131 {/if} 129 {/if}
130 <input type="checkbox" class="delete-checkbox" value="{$value.id}">
132 <!-- FIXME! JS translation --> 131 <!-- FIXME! JS translation -->
133 <a href="?edit_link={$value.id}" title="{'Edit'|t}"><i class="fa fa-pencil-square-o edit-link"></i></a> 132 <a href="?edit_link={$value.id}" title="{'Edit'|t}"><i class="fa fa-pencil-square-o edit-link"></i></a>
134 <a href="#" title="{'Fold'|t}" class="fold-button"><i class="fa fa-chevron-up"></i></a> 133 <a href="#" title="{'Fold'|t}" class="fold-button"><i class="fa fa-chevron-up"></i></a>
diff --git a/tpl/default/linklist.paging.html b/tpl/default/linklist.paging.html
index d8c1e76e..41e9fa34 100644
--- a/tpl/default/linklist.paging.html
+++ b/tpl/default/linklist.paging.html
@@ -6,10 +6,13 @@
6 {'Filters'|t} 6 {'Filters'|t}
7 </span> 7 </span>
8 {if="isLoggedIn()"} 8 {if="isLoggedIn()"}
9 <a href="?privateonly" title="{'Filter private links'|t}" 9 <a href="?privateonly" title="{'Filter private links'|t}"
10 class={if="$privateonly"}"filter-on"{else}"filter-off"{/if} 10 class={if="$privateonly"}"filter-on"{else}"filter-off"{/if}
11 ><i class="fa fa-key"></i></a> 11 ><i class="fa fa-key"></i></a>
12 {/if} 12 {/if}
13 <a href="?untaggedonly" title="{'Filter untagged links'|t}"
14 class={if="$untaggedonly"}"filter-on"{else}"filter-off"{/if}
15 ><i class="fa fa-tag"></i></a>
13 <a href="#" class="filter-off fold-all pure-u-lg-0" title="Fold all"> 16 <a href="#" class="filter-off fold-all pure-u-lg-0" title="Fold all">
14 <i class="fa fa-chevron-up"></i> 17 <i class="fa fa-chevron-up"></i>
15 </a> 18 </a>
@@ -55,4 +58,4 @@
55 </a> 58 </a>
56 </div> 59 </div>
57 </div> 60 </div>
58</div> \ No newline at end of file 61</div>
diff --git a/tpl/default/page.footer.html b/tpl/default/page.footer.html
index 77fc65dd..94f771a2 100644
--- a/tpl/default/page.footer.html
+++ b/tpl/default/page.footer.html
@@ -9,13 +9,16 @@
9 {/if} 9 {/if}
10 &middot; 10 &middot;
11 The personal, minimalist, super-fast, database free, bookmarking service by the Shaarli community &middot; 11 The personal, minimalist, super-fast, database free, bookmarking service by the Shaarli community &middot;
12 <a href="doc/Home.html" rel="nofollow">Documentation</a> 12 <a href="doc/html/index.html" rel="nofollow">Documentation</a>
13 {loop="$plugins_footer.text"} 13 {loop="$plugins_footer.text"}
14 {$value} 14 {$value}
15 {/loop} 15 {/loop}
16 </div> 16 </div>
17 <div class="pure-u-2-24"></div> 17 <div class="pure-u-2-24"></div>
18</div> 18</div>
19
20<input type="hidden" name="token" value="{$token}" id="token" />
21
19{loop="$plugins_footer.endofpage"} 22{loop="$plugins_footer.endofpage"}
20 {$value} 23 {$value}
21{/loop} 24{/loop}
diff --git a/tpl/default/page.header.html b/tpl/default/page.header.html
index 9388ef79..2411703c 100644
--- a/tpl/default/page.header.html
+++ b/tpl/default/page.header.html
@@ -97,28 +97,26 @@
97 97
98<div id="content"> 98<div id="content">
99 <div id="search" class="subheader-form"> 99 <div id="search" class="subheader-form">
100 <form method="GET" class="pure-form searchform" name="searchform">
101 <input type="text" tabindex="1" id="searchform_value" name="searchterm" placeholder="{'Search text'|t}"
102 {if="!empty($search_term)"}
103 value="{$search_term}"
104 {/if}
105 >
106 <input type="text" tabindex="2" name="searchtags" id="tagfilter_value" placeholder="{'Filter by tag'|t}"
107 {if="!empty($search_tags)"}
108 value="{$search_tags}"
109 {/if}
110 autocomplete="off" data-multiple data-autofirst data-minChars="1"
111 data-list="{loop="$tags"}{$key}, {/loop}"
112 >
113 <button type="submit" class="search-button"><i class="fa fa-search"></i></button>
114 </form>
115 </div>
116 <div id="actions" class="subheader-form">
100 <div class="pure-g"> 117 <div class="pure-g">
101 <div class="pure-u-1 pure-u-lg-1-2"> 118 <div class="pure-u-1">
102 <form method="GET" class="searchform" name="searchform"> 119 <a href="" id="actions-delete" class="button">Delete</a>
103 <input type="text" tabindex="1" id="searchform_value" name="searchterm" placeholder="{'Search text'|t}"
104 {if="!empty($search_term)"}
105 value="{$search_term}"
106 {/if}
107 >
108 <button type="submit" class="search-button"><i class="fa fa-search"></i></button>
109 </form>
110 </div>
111 <div class="pure-u-1 pure-u-lg-1-2">
112 <form method="GET" class="tagfilter" name="tagfilter">
113 <input type="text" tabindex="2" name="searchtags" id="tagfilter_value" placeholder="{'Filter by tag'|t}"
114 {if="!empty($search_tags)"}
115 value="{$search_tags}"
116 {/if}
117 autocomplete="off" data-multiple data-autofirst data-minChars="1"
118 data-list="{loop="$tags"}{$key}, {/loop}"
119 >
120 <button type="submit" class="search-button"><i class="fa fa-search"></i></button>
121 </form>
122 </div> 120 </div>
123 </div> 121 </div>
124 </div> 122 </div>
diff --git a/tpl/default/tag.cloud.html b/tpl/default/tag.cloud.html
new file mode 100644
index 00000000..96b357a3
--- /dev/null
+++ b/tpl/default/tag.cloud.html
@@ -0,0 +1,69 @@
1<!DOCTYPE html>
2<html>
3<head>
4 {include="includes"}
5</head>
6<body>
7{include="page.header"}
8
9{include="tag.sort"}
10
11<div class="pure-g">
12 <div class="pure-u-lg-1-6 pure-u-1-24"></div>
13 <div class="pure-u-lg-2-3 pure-u-22-24 page-form page-visitor">
14 {$countTags=count($tags)}
15 <h2 class="window-title">{'Tag cloud'|t} - {$countTags} {'tags'|t}</h2>
16 {if="!empty($search_tags)"}
17 <p class="enter">
18 <a href="?searchtags={$search_tags|urlencode}">{'List all links with those tags'|t}</a>
19 </p>
20 {/if}
21
22 <div id="search-tagcloud" class="pure-g">
23 <div class="pure-u-lg-1-4"></div>
24 <div class="pure-u-1 pure-u-lg-1-2">
25 <form method="GET">
26 <input type="hidden" name="do" value="tagcloud">
27 <input type="text" name="searchtags" placeholder="{'Filter by tag'|t}"
28 {if="!empty($search_tags)"}
29 value="{$search_tags}"
30 {/if}
31 autocomplete="off" data-multiple data-autofirst data-minChars="1"
32 data-list="{loop="$tags"}{$key}, {/loop}"
33 >
34 <button type="submit" class="search-button"><i class="fa fa-search"></i></button>
35 </form>
36 </div>
37 <div class="pure-u-lg-1-4"></div>
38 </div>
39
40 <div id="plugin_zone_start_tagcloud" class="plugin_zone">
41 {loop="$plugin_start_zone"}
42 {$value}
43 {/loop}
44 </div>
45
46 <div id="cloudtag">
47 {loop="tags"}
48 <a href="?searchtags={$key|urlencode} {$search_tags|urlencode}" style="font-size:{$value.size}em;">{$key}</a
49 ><a href="?addtag={$key|urlencode}" title="{'Filter by tag'|t}" class="count">{$value.count}</a>
50 {loop="$value.tag_plugin"}
51 {$value}
52 {/loop}
53 {/loop}
54 </div>
55
56 <div id="plugin_zone_end_tagcloud" class="plugin_zone">
57 {loop="$plugin_end_zone"}
58 {$value}
59 {/loop}
60 </div>
61 </div>
62</div>
63
64{include="tag.sort"}
65
66{include="page.footer"}
67</body>
68</html>
69
diff --git a/tpl/default/tag.list.html b/tpl/default/tag.list.html
new file mode 100644
index 00000000..a3e741d3
--- /dev/null
+++ b/tpl/default/tag.list.html
@@ -0,0 +1,89 @@
1<!DOCTYPE html>
2<html>
3<head>
4 {include="includes"}
5</head>
6<body>
7{include="page.header"}
8
9{include="tag.sort"}
10
11<div class="pure-g">
12 <div class="pure-u-lg-1-6 pure-u-1-24"></div>
13 <div class="pure-u-lg-2-3 pure-u-22-24 page-form page-visitor">
14 {$countTags=count($tags)}
15 <h2 class="window-title">{'Tag list'|t} - {$countTags} {'tags'|t}</h2>
16 {if="!empty($search_tags)"}
17 <p class="center">
18 <a href="?searchtags={$search_tags|urlencode}">{'List all links with those tags'|t}</a>
19 </p>
20 {/if}
21
22 <div id="search-tagcloud" class="pure-g">
23 <div class="pure-u-lg-1-4"></div>
24 <div class="pure-u-1 pure-u-lg-1-2">
25 <form method="GET">
26 <input type="hidden" name="do" value="taglist">
27 <input type="text" name="searchtags" placeholder="{'Filter by tag'|t}"
28 {if="!empty($search_tags)"}
29 value="{$search_tags}"
30 {/if}
31 autocomplete="off" data-multiple data-autofirst data-minChars="1"
32 data-list="{loop="$tags"}{$key}, {/loop}"
33 >
34 <button type="submit" class="search-button"><i class="fa fa-search"></i></button>
35 </form>
36 </div>
37 <div class="pure-u-lg-1-4"></div>
38 </div>
39
40 <div id="plugin_zone_start_tagcloud" class="plugin_zone">
41 {loop="$plugin_start_zone"}
42 {$value}
43 {/loop}
44 </div>
45
46 <div id="taglist">
47 {loop="tags"}
48 <div class="tag-list-item pure-g" data-tag="{$key}">
49 <div class="pure-u-1">
50 {if="isLoggedIn()===true"}
51 <a href="#" class="delete-tag"><i class="fa fa-trash"></i></a>&nbsp;&nbsp;
52 <a href="?do=changetag&fromtag={$key|urlencode}" class="rename-tag">
53 <i class="fa fa-pencil-square-o {$key}"></i>
54 </a>
55 {/if}
56
57 <a href="?addtag={$key|urlencode}" title="{'Filter by tag'|t}" class="count">{$value}</a>
58 <a href="?searchtags={$key|urlencode} {$search_tags|urlencode}" class="tag-link">{$key}</a>
59
60 {loop="$value.tag_plugin"}
61 {$value}
62 {/loop}
63 </div>
64 {if="isLoggedIn()===true"}
65 <div class="rename-tag-form pure-u-1">
66 <input type="text" name="{$key}" value="{$key}" class="rename-tag-input" />
67 <a href="#" class="validate-rename-tag"><i class="fa fa-check"></i></a>
68 </div>
69 {/if}
70 </div>
71 {/loop}
72 </div>
73
74 <div id="plugin_zone_end_tagcloud" class="plugin_zone">
75 {loop="$plugin_end_zone"}
76 {$value}
77 {/loop}
78 </div>
79 </div>
80</div>
81
82{if="isLoggedIn()===true"}
83 <input type="hidden" name="taglist" value="{loop="$tags"}{$key} {/loop}"
84{/if}
85
86{include="page.footer"}
87</body>
88</html>
89
diff --git a/tpl/default/tag.sort.html b/tpl/default/tag.sort.html
new file mode 100644
index 00000000..89acda0d
--- /dev/null
+++ b/tpl/default/tag.sort.html
@@ -0,0 +1,8 @@
1<div class="pure-g">
2 <div class="pure-u-1 pure-alert pure-alert-success tag-sort">
3 {'Sort by:'|t}
4 <a href="?do=tagcloud" title="cloud">{'Cloud'|t}</a> &middot;
5 <a href="?do=taglist&sort=usage" title="cloud">{'Most used'|t}</a> &middot;
6 <a href="?do=taglist&sort=alpha" title="cloud">{'Alphabetical'|t}</a>
7 </div>
8</div> \ No newline at end of file
diff --git a/tpl/default/tagcloud.html b/tpl/default/tagcloud.html
deleted file mode 100644
index 53c31748..00000000
--- a/tpl/default/tagcloud.html
+++ /dev/null
@@ -1,42 +0,0 @@
1<!DOCTYPE html>
2<html>
3<head>
4 {include="includes"}
5</head>
6<body>
7{include="page.header"}
8
9<div class="pure-g">
10 <div class="pure-u-lg-1-6 pure-u-1-24"></div>
11 <div class="pure-u-lg-2-3 pure-u-22-24 page-form page-visitor">
12 {$countTags=count($tags)}
13 <h2 class="window-title">{'Tag cloud'|t} - {$countTags} {'tags'|t}</h2>
14
15 <div id="plugin_zone_start_tagcloud" class="plugin_zone">
16 {loop="$plugin_start_zone"}
17 {$value}
18 {/loop}
19 </div>
20
21 <div id="cloudtag">
22 {loop="tags"}
23 <a href="?searchtags={$key|urlencode}" style="font-size:{$value.size}em;">{$key}</a
24 ><span class="count">{$value.count}</span>
25 {loop="$value.tag_plugin"}
26 {$value}
27 {/loop}
28 {/loop}
29 </div>
30
31 <div id="plugin_zone_end_tagcloud" class="plugin_zone">
32 {loop="$plugin_end_zone"}
33 {$value}
34 {/loop}
35 </div>
36 </div>
37</div>
38
39{include="page.footer"}
40</body>
41</html>
42
diff --git a/tpl/default/tools.html b/tpl/default/tools.html
index baa033af..35173d17 100644
--- a/tpl/default/tools.html
+++ b/tpl/default/tools.html
@@ -72,10 +72,15 @@
72 function(){ 72 function(){
73 var%20url%20=%20location.href; 73 var%20url%20=%20location.href;
74 var%20title%20=%20document.title%20||%20url; 74 var%20title%20=%20document.title%20||%20url;
75 var%20desc=document.getSelection().toString();
76 if(desc.length>4000){
77 desc=desc.substr(0,4000)+'...';
78 alert('{function="str_replace(' ', '%20', t('The selected text is too long, it will be truncated.'))"}');
79 }
75 window.open( 80 window.open(
76 '{$pageabsaddr}?post='%20+%20encodeURIComponent(url)+ 81 '{$pageabsaddr}?post='%20+%20encodeURIComponent(url)+
77 '&amp;title='%20+%20encodeURIComponent(title)+ 82 '&amp;title='%20+%20encodeURIComponent(title)+
78 '&amp;description='%20+%20encodeURIComponent(document.getSelection())+ 83 '&amp;description='%20+%20encodeURIComponent(desc)+
79 '&amp;source=bookmarklet','_blank','menubar=no,height=800,width=600,toolbar=no,scrollbars=yes,status=no,dialog=1' 84 '&amp;source=bookmarklet','_blank','menubar=no,height=800,width=600,toolbar=no,scrollbars=yes,status=no,dialog=1'
80 ); 85 );
81 } 86 }
@@ -86,8 +91,21 @@
86 <div class="tools-item"> 91 <div class="tools-item">
87 <a title="{'Drag this link to your bookmarks toolbar or right-click it and Bookmark This Link'|t}, 92 <a title="{'Drag this link to your bookmarks toolbar or right-click it and Bookmark This Link'|t},
88 {'Then click ✚Add Note button anytime to start composing a private Note (text post) to your Shaarli'|t}" 93 {'Then click ✚Add Note button anytime to start composing a private Note (text post) to your Shaarli'|t}"
89 href="?private=1&amp;post=" 94 class="bookmarklet-link"
90 class="bookmarklet-link"> 95 href="javascript:(
96 function(){
97 var%20desc=document.getSelection().toString();
98 if(desc.length>4000){
99 desc=desc.substr(0,4000)+'...';
100 alert("{function="str_replace(' ', '%20', t('The selected text is too long, it will be truncated.'))"}");
101 }
102 window.open(
103 '{$pageabsaddr}?private=1&amp;post='+
104 '&amp;description='%20+%20encodeURIComponent(desc)+
105 '&amp;source=bookmarklet','_blank','menubar=no,height=800,width=600,toolbar=no,scrollbars=yes,status=no,dialog=1'
106 );
107 }
108 )();">
91 <span class="pure-button pure-u-lg-2-3 pure-u-3-4">✚ {'Add Note'|t}</span> 109 <span class="pure-button pure-u-lg-2-3 pure-u-3-4">✚ {'Add Note'|t}</span>
92 </a> 110 </a>
93 </div> 111 </div>
@@ -146,4 +164,3 @@
146 value="{'Drag this link to your bookmarks toolbar, or right-click it and choose Bookmark This Link'|t}"> 164 value="{'Drag this link to your bookmarks toolbar, or right-click it and choose Bookmark This Link'|t}">
147</body> 165</body>
148</html> 166</html>
149