Update for Shaarli 0.12.2

This commit is contained in:
Knah Tsaeb 2023-05-25 11:13:43 +02:00
parent 23a5fc1eef
commit 2c1f0981d9
76 changed files with 9219 additions and 4126 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

718
assets/myShaarli/js/base.js Normal file
View File

@ -0,0 +1,718 @@
import Awesomplete from 'awesomplete';
import he from 'he';
/**
* Find a parent element according to its tag and its attributes
*
* @param element Element where to start the search
* @param tagName Expected parent tag name
* @param attributes Associative array of expected attributes (name=>value).
*
* @returns Found element or null.
*/
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;
}
/**
* 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 (callback) {
callback(xhr.response);
}
};
xhr.send();
}
function createAwesompleteInstance(element, separator, tags = []) {
const awesome = new Awesomplete(Awesomplete.$(element));
// Tags are separated by separator. Ignore leading search flags
awesome.filter = (text, input) => {
let filterFunc = Awesomplete.FILTER_CONTAINS;
let term = input.match(new RegExp(`[^${separator}]*$`))[0];
const termFlagged = term.replace(/^[-~+]/, '');
if (term !== termFlagged) {
term = termFlagged;
filterFunc = Awesomplete.FILTER_STARTSWITH;
}
return filterFunc(text, term);
};
// Insert new selected tag in the input
awesome.replace = (text) => {
const before = awesome.input.value.match(new RegExp(`^(.+${separator}+)?[-~+]?|`))[0];
awesome.input.value = `${before}${text}${separator}`;
};
// Highlight found items
awesome.item = (text, input) => Awesomplete.ITEM(text, input.match(new RegExp(`[^${separator}]*$`))[0]);
// Don't display already selected items
// WARNING: pseudo classes does not seem to work with string litterals...
const reg = new RegExp(`([^${separator}]+)${separator}`, '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;
}
/**
* 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
* @param separator Tags separator character
*/
function updateAwesompleteList(selector, tags, instances, separator) {
if (instances.length === 0) {
// First load: create Awesomplete instances
const elements = document.querySelectorAll(selector);
[...elements].forEach((element) => {
instances.push(createAwesompleteInstance(element, separator, tags));
});
} else {
// Update awesomplete tag list
instances.map((item) => {
item.list = tags;
return item;
});
}
return instances;
}
/**
* 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 = null) {
let first = true;
if (reset == null) {
reset = false;
}
[...cities].forEach((option) => {
if (option.getAttribute('data-continent') !== currentContinent) {
option.className = 'hidden';
} else {
option.className = '';
if (reset === true && first === true) {
option.setAttribute('selected', 'selected');
first = false;
}
}
});
}
/**
* Retrieve an element up in the tree from its class name.
*/
function getParentByClass(el, className) {
const p = el.parentNode;
if (p == null || p.classList.contains(className)) {
return p;
}
return getParentByClass(p, className);
}
function toggleHorizontal() {
[...document.getElementById('shaarli-menu').querySelectorAll('.menu-transform')].forEach((el) => {
el.classList.toggle('pure-menu-horizontal');
});
}
function toggleMenu(menu) {
// 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(menu) {
if (menu.classList.contains('open')) {
toggleMenu(menu);
}
}
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 removeClass(element, classname) {
element.className = element.className.replace(new RegExp(`(?:^|\\s)${classname}(?:\\s|$)`), ' ');
}
function init(description) {
function resize() {
/* Fix jumpy resizing: https://stackoverflow.com/a/18262927/1484919 */
const scrollTop = window.pageYOffset
|| (document.documentElement || document.body.parentNode || document.body).scrollTop;
description.style.height = 'auto';
description.style.height = `${description.scrollHeight + 10}px`;
window.scrollTo(0, scrollTop);
}
/* 0-timeout to get the already changed text */
function delayedResize() {
window.setTimeout(resize, 0);
}
const observe = (element, event, handler) => {
element.addEventListener(event, handler, false);
};
observe(description, 'change', resize);
observe(description, 'cut', delayedResize);
observe(description, 'paste', delayedResize);
observe(description, 'drop', delayedResize);
observe(description, 'keydown', delayedResize);
resize();
}
(() => {
const basePath = document.querySelector('input[name="js_base_path"]').value;
const tagsSeparatorElement = document.querySelector('input[name="tags_separator"]');
const tagsSeparator = tagsSeparatorElement ? tagsSeparatorElement.value || ' ' : ' ';
/**
* Handle responsive menu.
* Source: http://purecss.io/layouts/tucked-menu-vertical/
*/
const menu = document.getElementById('shaarli-menu');
const WINDOW_CHANGE_EVENT = ('onorientationchange' in window) ? 'orientationchange' : 'resize';
const menuToggle = document.getElementById('menu-toggle');
if (menuToggle != null) {
menuToggle.addEventListener('click', () => toggleMenu(menu));
}
window.addEventListener(WINDOW_CHANGE_EVENT, () => closeMenu(menu));
/**
* Fold/Expand shaares description and thumbnail.
*/
const foldAllButtons = document.getElementsByClassName('fold-all');
const foldButtons = document.getElementsByClassName('fold-button');
[...foldButtons].forEach((foldButton) => {
// Retrieve description
let description = null;
let thumbnail = null;
const 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', (event) => {
event.preventDefault();
toggleFold(event.target, description, thumbnail);
});
});
if (foldAllButtons != null) {
[].forEach.call(foldAllButtons, (foldAllButton) => {
foldAllButton.addEventListener('click', (event) => {
event.preventDefault();
const state = foldAllButton.firstElementChild.getAttribute('class').indexOf('down') !== -1 ? 'down' : 'up';
[].forEach.call(foldButtons, (foldButton) => {
if ((foldButton.firstElementChild.classList.contains('fa-chevron-up') && state === 'down')
|| (foldButton.firstElementChild.classList.contains('fa-chevron-down') && state === 'up')
) {
return;
}
// Retrieve description
let description = null;
let thumbnail = null;
const 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;
});
});
}
/**
* Confirmation message before deletion.
*/
const deleteLinks = document.querySelectorAll('.confirm-delete');
[...deleteLinks].forEach((deleteLink) => {
deleteLink.addEventListener('click', (event) => {
const type = event.currentTarget.getAttribute('data-type') || 'link';
if (!confirm(document.getElementById(`translation-delete-${type}`).innerHTML)) {
event.preventDefault();
}
});
});
/**
* Close alerts
*/
const closeLinks = document.querySelectorAll('.pure-alert-close');
[...closeLinks].forEach((closeLink) => {
closeLink.addEventListener('click', (event) => {
const alert = getParentByClass(event.target, 'pure-alert-closable');
alert.style.display = 'none';
});
});
/**
* New version dismiss.
* Hide the message for one week using localStorage.
*/
const newVersionDismiss = document.getElementById('new-version-dismiss');
const newVersionMessage = document.querySelector('.new-version-message');
if (newVersionMessage != null
&& localStorage.getItem('newVersionDismiss') != null
&& parseInt(localStorage.getItem('newVersionDismiss'), 10) + (7 * 24 * 60 * 60 * 1000) > (new Date()).getTime()
) {
newVersionMessage.style.display = 'none';
}
if (newVersionDismiss != null) {
newVersionDismiss.addEventListener('click', () => {
localStorage.setItem('newVersionDismiss', (new Date()).getTime().toString());
});
}
const hiddenReturnurl = document.getElementsByName('returnurl');
if (hiddenReturnurl != null) {
hiddenReturnurl.value = window.location.href;
}
/**
* Autofocus text fields
*/
const autofocusElements = document.querySelectorAll('.autofocus');
let breakLoop = false;
[].forEach.call(autofocusElements, (autofocusElement) => {
if (autofocusElement.value === '' && !breakLoop) {
autofocusElement.focus();
breakLoop = true;
}
});
/**
* Handle sub menus/forms
*/
const openers = document.getElementsByClassName('subheader-opener');
if (openers != null) {
[...openers].forEach((opener) => {
opener.addEventListener('click', (event) => {
event.preventDefault();
const id = opener.getAttribute('data-open-id');
const sub = document.getElementById(id);
if (sub != null) {
[...document.getElementsByClassName('subheader-form')].forEach((element) => {
if (element !== sub) {
removeClass(element, 'open');
}
});
sub.classList.toggle('open');
const autofocus = sub.querySelector('.autofocus');
if (autofocus) {
autofocus.focus();
}
}
});
});
}
/**
* Remove CSS target padding (for fixed bar)
*/
if (location.hash !== '') {
const anchor = document.getElementById(location.hash.substr(1));
if (anchor != null) {
const padsize = anchor.clientHeight;
window.scroll(0, window.scrollY - padsize);
anchor.style.paddingTop = '0';
}
}
/**
* Text area resizer
*/
const description = document.getElementById('lf_description');
if (description != null) {
init(description);
// Submit editlink form with CTRL + Enter in the text area.
description.addEventListener('keydown', (event) => {
if (event.ctrlKey && event.keyCode === 13) {
document.getElementById('button-save-edit').click();
}
});
}
/**
* Bookmarklet alert
*/
const bookmarkletLinks = document.querySelectorAll('.bookmarklet-link');
const bkmMessage = document.getElementById('bookmarklet-alert');
[].forEach.call(bookmarkletLinks, (link) => {
link.addEventListener('click', (event) => {
event.preventDefault();
alert(bkmMessage.value);
});
});
const continent = document.getElementById('continent');
const city = document.getElementById('city');
if (continent != null && city != null) {
continent.addEventListener('change', () => {
hideTimezoneCities(city, continent.options[continent.selectedIndex].value, true);
});
hideTimezoneCities(city, continent.options[continent.selectedIndex].value, false);
}
/**
* Bulk actions
*/
const linkCheckboxes = document.querySelectorAll('.link-checkbox');
const bar = document.getElementById('actions');
[...linkCheckboxes].forEach((checkbox) => {
checkbox.style.display = 'inline-block';
checkbox.addEventListener('change', () => {
const linkCheckedCheckboxes = document.querySelectorAll('.link-checkbox:checked');
const count = [...linkCheckedCheckboxes].length;
if (count === 0 && bar.classList.contains('open')) {
bar.classList.toggle('open');
} else if (count > 0 && !bar.classList.contains('open')) {
bar.classList.toggle('open');
}
});
});
const deleteButton = document.getElementById('actions-delete');
const token = document.getElementById('token');
if (deleteButton != null && token != null) {
deleteButton.addEventListener('click', (event) => {
event.preventDefault();
const links = [];
const linkCheckedCheckboxes = document.querySelectorAll('.link-checkbox:checked');
[...linkCheckedCheckboxes].forEach((checkbox) => {
links.push({
id: checkbox.value,
title: document.querySelector(`.linklist-item[data-id="${checkbox.value}"] .linklist-link`).innerHTML,
});
});
let message = `Are you sure you want to delete ${links.length} links?\n`;
message += 'This action is IRREVERSIBLE!\n\nTitles:\n';
const ids = [];
links.forEach((item) => {
message += ` - ${item.title}\n`;
ids.push(item.id);
});
if (window.confirm(message)) {
window.location = `${basePath}/admin/shaare/delete?id=${ids.join('+')}&token=${token.value}`;
}
});
}
const changeVisibilityButtons = document.querySelectorAll('.actions-change-visibility');
if (changeVisibilityButtons != null && token != null) {
[...changeVisibilityButtons].forEach((button) => {
button.addEventListener('click', (event) => {
event.preventDefault();
const visibility = event.target.getAttribute('data-visibility');
const links = [];
const linkCheckedCheckboxes = document.querySelectorAll('.link-checkbox:checked');
[...linkCheckedCheckboxes].forEach((checkbox) => {
links.push({
id: checkbox.value,
title: document.querySelector(`.linklist-item[data-id="${checkbox.value}"] .linklist-link`).innerHTML,
});
});
const ids = links.map((item) => item.id);
window.location = (
`${basePath}/admin/shaare/visibility?token=${token.value}&newVisibility=${visibility}&id=${ids.join('+')}`
);
});
});
}
['add', 'delete'].forEach((action) => {
const subHeader = document.getElementById(`bulk-tag-action-${action}`);
if (subHeader) {
subHeader.querySelectorAll('a.button').forEach((link) => {
if (!link.classList.contains('action')) {
return;
}
subHeader.querySelector('input[name="tag"]').addEventListener('keypress', (event) => {
if (event.keyCode === 13) { // enter
link.click();
}
});
link.addEventListener('click', (event) => {
event.preventDefault();
const ids = [];
const linkCheckedCheckboxes = document.querySelectorAll('.link-checkbox:checked');
[...linkCheckedCheckboxes].forEach((checkbox) => {
ids.push(checkbox.value);
});
subHeader.querySelector('input[name="id"]').value = ids.join(' ');
subHeader.querySelector('form').submit();
});
});
}
});
/**
* Select all button
*/
const selectAllButtons = document.querySelectorAll('.select-all-button');
[...selectAllButtons].forEach((selectAllButton) => {
selectAllButton.addEventListener('click', (e) => {
e.preventDefault();
const checked = selectAllButton.classList.contains('filter-off');
[...selectAllButtons].forEach((selectAllButton2) => {
selectAllButton2.classList.toggle('filter-off');
selectAllButton2.classList.toggle('filter-on');
});
[...linkCheckboxes].forEach((linkCheckbox) => {
linkCheckbox.checked = checked;
linkCheckbox.dispatchEvent(new Event('change'));
});
});
});
/**
* Tag list operations
*
* TODO: support error code in the backend for AJAX requests
*/
const tagList = document.querySelector('input[name="taglist"]');
let existingTags = tagList ? tagList.value.split(' ') : [];
let awesomepletes = [];
// Display/Hide rename form
const renameTagButtons = document.querySelectorAll('.rename-tag');
[...renameTagButtons].forEach((rename) => {
rename.addEventListener('click', (event) => {
event.preventDefault();
const block = findParent(event.target, 'div', { class: 'tag-list-item' });
const form = block.querySelector('.rename-tag-form');
if (form.style.display === 'none' || form.style.display === '') {
form.style.display = 'block';
} else {
form.style.display = 'none';
}
block.querySelector('input').focus();
});
});
// Rename a tag with an AJAX request
const renameTagSubmits = document.querySelectorAll('.validate-rename-tag');
[...renameTagSubmits].forEach((rename) => {
rename.addEventListener('click', (event) => {
event.preventDefault();
const block = findParent(event.target, 'div', { class: 'tag-list-item' });
const input = block.querySelector('.rename-tag-input');
const totag = input.value.replace('/"/g', '\\"');
if (totag.trim() === '') {
return;
}
const refreshedToken = document.getElementById('token').value;
const fromtag = block.getAttribute('data-tag');
const fromtagUrl = block.getAttribute('data-tag-url');
const xhr = new XMLHttpRequest();
xhr.open('POST', `${basePath}/admin/tags`);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = () => {
if (xhr.status !== 200) {
alert(`An error occurred. Return code: ${xhr.status}`);
location.reload();
} else {
block.setAttribute('data-tag', totag);
block.setAttribute('data-tag-url', encodeURIComponent(totag));
input.setAttribute('name', totag);
input.setAttribute('value', totag);
findParent(input, 'div', { class: 'rename-tag-form' }).style.display = 'none';
block.querySelector('a.tag-link').innerHTML = he.encode(totag);
block
.querySelector('a.tag-link')
.setAttribute('href', `${basePath}/?searchtags=${encodeURIComponent(totag)}`);
block
.querySelector('a.count')
.setAttribute('href', `${basePath}/add-tag/${encodeURIComponent(totag)}`);
block
.querySelector('a.rename-tag')
.setAttribute('href', `${basePath}/admin/tags?fromtag=${encodeURIComponent(totag)}`);
// Refresh awesomplete values
existingTags = existingTags.map((tag) => (tag === fromtag ? totag : tag));
awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes, tagsSeparator);
}
};
xhr.send(`renametag=1&fromtag=${fromtagUrl}&totag=${encodeURIComponent(totag)}&token=${refreshedToken}`);
refreshToken(basePath);
});
});
// Validate input with enter key
const renameTagInputs = document.querySelectorAll('.rename-tag-input');
[...renameTagInputs].forEach((rename) => {
rename.addEventListener('keypress', (event) => {
if (event.keyCode === 13) { // enter
findParent(event.target, 'div', { class: 'tag-list-item' }).querySelector('.validate-rename-tag').click();
}
});
});
// Delete a tag with an AJAX query (alert popup confirmation)
const deleteTagButtons = document.querySelectorAll('.delete-tag');
[...deleteTagButtons].forEach((rename) => {
rename.style.display = 'inline';
rename.addEventListener('click', (event) => {
event.preventDefault();
const block = findParent(event.target, 'div', { class: 'tag-list-item' });
const tag = block.getAttribute('data-tag');
const tagUrl = block.getAttribute('data-tag-url');
const refreshedToken = document.getElementById('token').value;
if (confirm(`Are you sure you want to delete the tag "${tag}"?`)) {
const xhr = new XMLHttpRequest();
xhr.open('POST', `${basePath}/admin/tags`);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = () => {
block.remove();
};
xhr.send(`deletetag=1&fromtag=${tagUrl}&token=${refreshedToken}`);
refreshToken(basePath);
existingTags = existingTags.filter((tagItem) => tagItem !== tag);
awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes, tagsSeparator);
}
});
});
const autocompleteFields = document.querySelectorAll('input[data-multiple]');
[...autocompleteFields].forEach((autocompleteField) => {
awesomepletes.push(createAwesompleteInstance(autocompleteField, tagsSeparator));
});
const exportForm = document.querySelector('#exportform');
if (exportForm != null) {
exportForm.addEventListener('submit', (event) => {
event.preventDefault();
refreshToken(basePath, () => {
event.target.submit();
});
});
}
const bulkCreationButton = document.querySelector('.addlink-batch-show-more-block');
if (bulkCreationButton != null) {
const toggleBulkCreationVisibility = (showMoreBlockElement, formElement) => {
if (bulkCreationButton.classList.contains('pure-u-0')) {
showMoreBlockElement.classList.remove('pure-u-0');
formElement.classList.add('pure-u-0');
} else {
showMoreBlockElement.classList.add('pure-u-0');
formElement.classList.remove('pure-u-0');
}
};
const bulkCreationForm = document.querySelector('.addlink-batch-form-block');
toggleBulkCreationVisibility(bulkCreationButton, bulkCreationForm);
bulkCreationButton.querySelector('a').addEventListener('click', (e) => {
e.preventDefault();
toggleBulkCreationVisibility(bulkCreationButton, bulkCreationForm);
});
// Force to send falsy value if the checkbox is not checked.
const privateButton = bulkCreationForm.querySelector('input[type="checkbox"][name="private"]');
const privateHiddenButton = bulkCreationForm.querySelector('input[type="hidden"][name="private"]');
privateButton.addEventListener('click', () => {
privateHiddenButton.disabled = !privateHiddenButton.disabled;
});
privateHiddenButton.disabled = privateButton.checked;
}
})();

View File

@ -0,0 +1,81 @@
/**
* Change the position counter of a row.
*
* @param elem Element Node to change.
* @param toPos int New position.
*/
function changePos(elem, toPos) {
const elemName = elem.getAttribute('data-line');
elem.setAttribute('data-order', toPos);
const hiddenInput = document.querySelector(`[name="order_${elemName}"]`);
hiddenInput.setAttribute('value', toPos);
}
/**
* Move a row up or down.
*
* @param pos Element Node to move.
* @param move int Move: +1 (down) or -1 (up)
*/
function changeOrder(pos, move) {
const newpos = parseInt(pos, 10) + move;
let lines = document.querySelectorAll(`[data-order="${pos}"]`);
const changelines = document.querySelectorAll(`[data-order="${newpos}"]`);
// If we go down reverse lines to preserve the rows order
if (move > 0) {
lines = [].slice.call(lines).reverse();
}
for (let i = 0; i < lines.length; i += 1) {
const parent = changelines[0].parentNode;
changePos(lines[i], newpos);
changePos(changelines[i], parseInt(pos, 10));
const changeItem = move < 0 ? changelines[0] : changelines[changelines.length - 1].nextSibling;
parent.insertBefore(lines[i], changeItem);
}
}
/**
* Move a row up in the table.
*
* @param pos int row counter.
*
* @return false
*/
function orderUp(pos) {
if (pos !== 0) {
changeOrder(pos, -1);
}
}
/**
* Move a row down in the table.
*
* @param pos int row counter.
*
* @returns false
*/
function orderDown(pos) {
const lastpos = parseInt(document.querySelector('[data-order]:last-child').getAttribute('data-order'), 10);
if (pos !== lastpos) {
changeOrder(pos, 1);
}
}
(() => {
/**
* Plugin admin order
*/
const orderPA = document.querySelectorAll('.order');
[...orderPA].forEach((link) => {
link.addEventListener('click', (event) => {
event.preventDefault();
if (event.target.classList.contains('order-up')) {
orderUp(parseInt(event.target.parentNode.parentNode.getAttribute('data-order'), 10));
} else if (event.target.classList.contains('order-down')) {
orderDown(parseInt(event.target.parentNode.parentNode.getAttribute('data-order'), 10));
}
});
});
})();

File diff suppressed because it is too large Load Diff

View File

@ -1,102 +0,0 @@
## Markdown Shaarli plugin
Convert all your shaares description to HTML formatted Markdown.
[Read more about Markdown syntax](http://daringfireball.net/projects/markdown/syntax).
Markdown processing is done with [Parsedown library](https://github.com/erusev/parsedown).
### Installation
As a default plugin, it should already be in `tpl/plugins/` directory.
If not, download and unpack it there.
The directory structure should look like:
```
--- plugins
|--- markdown
|--- help.html
|--- markdown.css
|--- markdown.meta
|--- markdown.php
|--- README.md
```
To enable the plugin, just check it in the plugin administration page.
You can also add `markdown` to your list of enabled plugins in `data/config.json.php`
(`general.enabled_plugins` list).
This should look like:
```
"general": {
"enabled_plugins": [
"markdown",
[...]
],
}
```
Parsedown parsing library is imported using Composer. If you installed Shaarli using `git`,
or the `master` branch, run
composer update --no-dev --prefer-dist
### No Markdown tag
If the tag `nomarkdown` is set for a shaare, it won't be converted to Markdown syntax.
> Note: this is a special tag, so it won't be displayed in link list.
### HTML escape
By default, HTML tags are escaped. You can enable HTML tags rendering
by setting `security.markdwon_escape` to `false` in `data/config.json.php`:
```json
{
"security": {
"markdown_escape": false
}
}
```
With this setting, Markdown support HTML tags. For example:
> <strong>strong</strong><strike>strike</strike>
Will render as:
> <strong>strong</strong><strike>strike</strike>
**Warning:**
* This setting might present **security risks** (XSS) on shared instances, even though tags
such as script, iframe, etc should be disabled.
* If you want to shaare HTML code, it is necessary to use inline code or code blocks.
* If your shaared descriptions contained HTML tags before enabling the markdown plugin,
enabling it might break your page.
### Known issue
#### Redirector
If you're using a redirector, you *need* to add a space after a link,
otherwise the rest of the line will be `urlencode`.
```
[link](http://domain.tld)-->test
```
Will consider `http://domain.tld)-->test` as URL.
Instead, add an additional space.
```
[link](http://domain.tld) -->test
```
> Won't fix because a `)` is a valid part of an URL.

View File

@ -1,5 +0,0 @@
<div class="md_help">
%s
<a href="http://daringfireball.net/projects/markdown/syntax" title="%s">
%s</a>.
</div>

View File

@ -1,173 +0,0 @@
/**
* Credit to Simon Laroche <https://github.com/simonlc/Markdown-CSS>
* whom created the CSS which this file is based on.
* License: Unlicense <http://unlicense.org/>
*/
.markdown p{
margin:0.75em 0;
}
.markdown img{
max-width:100%;
}
.markdown h1, .markdown h2, .markdown h3, .markdown h4, .markdown h5, .markdown h6{
font-weight:normal;
font-style:normal;
line-height:1em;
margin:0.75em 0;
}
.markdown h4, .markdown h5, .markdown h6{ font-weight: bold; }
.markdown h1{ font-size:2.5em; }
.markdown h2{ font-size:2em; }
.markdown h3{ font-size:1.5em; }
.markdown h4{ font-size:1.2em; }
.markdown h5{ font-size:1em; }
.markdown h6{ font-size:0.9em; }
.markdown blockquote{
color:#666666;
padding-left: 3em;
border-left: 0.5em #EEE solid;
margin:0.75em 0;
}
.markdown hr { display: block; height: 2px; border: 0; border-top: 1px solid #aaa;border-bottom: 1px solid #eee; margin: 1em 0; padding: 0; }
.markdown pre, .markdown code, .markdown kbd, .markdown samp {
font-family: monospace, 'courier new';
font-size: 0.98em;
}
.markdown pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; }
.markdown b, .markdown strong { font-weight: bold; }
.markdown dfn, .markdown em { font-style: italic; }
.markdown ins { background: #ff9; color: #000; text-decoration: none; }
.markdown mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; }
.markdown sub, .markdown sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
.markdown sup { top: -0.5em; }
.markdown sub { bottom: -0.25em; }
.markdown ul, .markdown ol { margin: 1em 0; padding: 0 0 0 2em; }
.markdown li p:last-child { margin:0 }
.markdown dd { margin: 0 0 0 2em; }
.markdown img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; }
.markdown table { border-collapse: collapse; border-spacing: 0; }
.markdown td { vertical-align: top; }
@media only screen and (min-width: 480px) {
.markdown {font-size:0.9em;}
}
@media only screen and (min-width: 768px) {
.markdown {font-size:1em;}
}
#linklist .markdown li {
padding: 0;
border: none;
background: none;
}
#linklist .markdown ul li {
list-style: circle;
}
#linklist .markdown ol li {
list-style: decimal;
}
.markdown table {
padding: 0;
}
.markdown table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0;
}
.markdown table tr:nth-child(2n) {
background-color: #f8f8f8;
}
.markdown table tr th {
font-weight: bold;
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px;
}
.markdown table tr td {
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px;
}
.markdown table tr th :first-child, .markdown table tr td :first-child {
margin-top: 0;
}
.markdown table tr th :last-child, table tr td :last-child {
margin-bottom: 0;
}
.markdown pre {
background-color: #eee;
padding: 4px 9px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
overflow: auto;
box-shadow: 0 -1px 0 #e5e5e5,0 0 1px rgba(0,0,0,0.12),0 1px 2px rgba(0,0,0,0.24);
}
.markdown pre code {
color: black;
font-family: 'Consolas', 'Monaco', 'Andale Mono', monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
line-height: 1.7;
font-size: 11.5px;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
.markdown :not(pre) code {
background-color: #eee;
padding: 1px 3px;
border-radius: 1px;
box-shadow: 0 -1px 0 #e5e5e5,0 0 1px rgba(0,0,0,0.12),0 1px 1px rgba(0,0,0,0.24);
}
#pageheader .md_help {
color: white;
}
/*
Remove header links style
*/
#pageheader .md_help a {
color: lightgray;
font-weight: bold;
text-decoration: underline;
background: none;
box-shadow: none;
padding: 0;
margin: 0;
}
#pageheader .md_help a:hover {
color: white;
}

View File

@ -1,4 +0,0 @@
description="Render shaare description with Markdown syntax.<br><strong>Warning</strong>:
If your shaared descriptions contained HTML tags before enabling the markdown plugin,
enabling it might break your page.
See the <a href=\"https://github.com/shaarli/Shaarli/tree/master/plugins/markdown#html-rendering\">README</a>."

View File

@ -1,365 +0,0 @@
<?php
/**
* Plugin Markdown.
*
* Shaare's descriptions are parsed with Markdown.
*/
use Shaarli\Config\ConfigManager;
use Shaarli\Plugin\PluginManager;
use Shaarli\Router;
/*
* If this tag is used on a shaare, the description won't be processed by Parsedown.
*/
define('NO_MD_TAG', 'nomarkdown');
/**
* Parse linklist descriptions.
*
* @param array $data linklist data.
* @param ConfigManager $conf instance.
*
* @return mixed linklist data parsed in markdown (and converted to HTML).
*/
function hook_markdown_render_linklist($data, $conf)
{
foreach ($data['links'] as &$value) {
if (!empty($value['tags']) && noMarkdownTag($value['tags'])) {
$value = stripNoMarkdownTag($value);
continue;
}
$value['description_src'] = $value['description'];
$value['description'] = process_markdown(
$value['description'],
$conf->get('security.markdown_escape', true),
$conf->get('security.allowed_protocols')
);
}
return $data;
}
/**
* Parse feed linklist descriptions.
*
* @param array $data linklist data.
* @param ConfigManager $conf instance.
*
* @return mixed linklist data parsed in markdown (and converted to HTML).
*/
function hook_markdown_render_feed($data, $conf)
{
foreach ($data['links'] as &$value) {
if (!empty($value['tags']) && noMarkdownTag($value['tags'])) {
$value = stripNoMarkdownTag($value);
continue;
}
$value['description'] = reverse_feed_permalink($value['description']);
$value['description'] = process_markdown(
$value['description'],
$conf->get('security.markdown_escape', true),
$conf->get('security.allowed_protocols')
);
}
return $data;
}
/**
* Parse daily descriptions.
*
* @param array $data daily data.
* @param ConfigManager $conf instance.
*
* @return mixed daily data parsed in markdown (and converted to HTML).
*/
function hook_markdown_render_daily($data, $conf)
{
//var_dump($data);die;
// Manipulate columns data
foreach ($data['linksToDisplay'] as &$value) {
if (!empty($value['tags']) && noMarkdownTag($value['tags'])) {
$value = stripNoMarkdownTag($value);
continue;
}
$value['formatedDescription'] = process_markdown(
$value['formatedDescription'],
$conf->get('security.markdown_escape', true),
$conf->get('security.allowed_protocols')
);
}
return $data;
}
/**
* Check if noMarkdown is set in tags.
*
* @param string $tags tag list
*
* @return bool true if markdown should be disabled on this link.
*/
function noMarkdownTag($tags)
{
return preg_match('/(^|\s)'. NO_MD_TAG .'(\s|$)/', $tags);
}
/**
* Remove the no-markdown meta tag so it won't be displayed.
*
* @param array $link Link data.
*
* @return array Updated link without no markdown tag.
*/
function stripNoMarkdownTag($link)
{
if (! empty($link['taglist'])) {
$offset = array_search(NO_MD_TAG, $link['taglist']);
if ($offset !== false) {
unset($link['taglist'][$offset]);
}
}
if (!empty($link['tags'])) {
str_replace(NO_MD_TAG, '', $link['tags']);
}
return $link;
}
/**
* When link list is displayed, include markdown CSS.
*
* @param array $data includes data.
*
* @return mixed - includes data with markdown CSS file added.
*/
function hook_markdown_render_includes($data)
{
if ($data['_PAGE_'] == Router::$PAGE_LINKLIST
|| $data['_PAGE_'] == Router::$PAGE_DAILY
|| $data['_PAGE_'] == Router::$PAGE_EDITLINK
) {
$data['css_files'][] = PluginManager::$PLUGINS_PATH . '/markdown/markdown.css';
}
return $data;
}
/**
* Hook render_editlink.
* Adds an help link to markdown syntax.
*
* @param array $data data passed to plugin
*
* @return array altered $data.
*/
function hook_markdown_render_editlink($data)
{
// Load help HTML into a string
$txt = file_get_contents(PluginManager::$PLUGINS_PATH .'/markdown/help.html');
$translations = [
t('Description will be rendered with'),
t('Markdown syntax documentation'),
t('Markdown syntax'),
];
$data['edit_link_plugin'][] = vsprintf($txt, $translations);
// Add no markdown 'meta-tag' in tag list if it was never used, for autocompletion.
if (! in_array(NO_MD_TAG, $data['tags'])) {
$data['tags'][NO_MD_TAG] = 0;
}
return $data;
}
/**
* Remove HTML links auto generated by Shaarli core system.
* Keeps HREF attributes.
*
* @param string $description input description text.
*
* @return string $description without HTML links.
*/
function reverse_text2clickable($description)
{
$descriptionLines = explode(PHP_EOL, $description);
$descriptionOut = '';
$codeBlockOn = false;
$lineCount = 0;
foreach ($descriptionLines as $descriptionLine) {
// Detect line of code: starting with 4 spaces,
// except lists which can start with +/*/- or `2.` after spaces.
$codeLineOn = preg_match('/^ +(?=[^\+\*\-])(?=(?!\d\.).)/', $descriptionLine) > 0;
// Detect and toggle block of code
if (!$codeBlockOn) {
$codeBlockOn = preg_match('/^```/', $descriptionLine) > 0;
} elseif (preg_match('/^```/', $descriptionLine) > 0) {
$codeBlockOn = false;
}
$hashtagTitle = ' title="Hashtag [^"]+"';
// Reverse `inline code` hashtags.
$descriptionLine = preg_replace(
'!(`[^`\n]*)<a href="[^ ]*"'. $hashtagTitle .'>([^<]+)</a>([^`\n]*`)!m',
'$1$2$3',
$descriptionLine
);
// Reverse all links in code blocks, only non hashtag elsewhere.
$hashtagFilter = (!$codeBlockOn && !$codeLineOn) ? '(?!'. $hashtagTitle .')': '(?:'. $hashtagTitle .')?';
$descriptionLine = preg_replace(
'#<a href="[^ ]*"'. $hashtagFilter .'>([^<]+)</a>#m',
'$1',
$descriptionLine
);
// Make hashtag links markdown ready, otherwise the links will be ignored with escape set to true
if (!$codeBlockOn && !$codeLineOn) {
$descriptionLine = preg_replace(
'#<a href="([^ ]*)"'. $hashtagTitle .'>([^<]+)</a>#m',
'[$2]($1)',
$descriptionLine
);
}
$descriptionOut .= $descriptionLine;
if ($lineCount++ < count($descriptionLines) - 1) {
$descriptionOut .= PHP_EOL;
}
}
return $descriptionOut;
}
/**
* Remove <br> tag to let markdown handle it.
*
* @param string $description input description text.
*
* @return string $description without <br> tags.
*/
function reverse_nl2br($description)
{
return preg_replace('!<br */?>!im', '', $description);
}
/**
* Remove HTML spaces '&nbsp;' auto generated by Shaarli core system.
*
* @param string $description input description text.
*
* @return string $description without HTML links.
*/
function reverse_space2nbsp($description)
{
return preg_replace('/(^| )&nbsp;/m', '$1 ', $description);
}
function reverse_feed_permalink($description)
{
return preg_replace('@&#8212; <a href="([^"]+)" title="[^"]+">(\w+)</a>$@im', '&#8212; [$2]($1)', $description);
}
/**
* Replace not whitelisted protocols with http:// in given description.
*
* @param string $description input description text.
* @param array $allowedProtocols list of allowed protocols.
*
* @return string $description without malicious link.
*/
function filter_protocols($description, $allowedProtocols)
{
return preg_replace_callback(
'#]\((.*?)\)#is',
function ($match) use ($allowedProtocols) {
return ']('. whitelist_protocols($match[1], $allowedProtocols) .')';
},
$description
);
}
/**
* Remove dangerous HTML tags (tags, iframe, etc.).
* Doesn't affect <code> content (already escaped by Parsedown).
*
* @param string $description input description text.
*
* @return string given string escaped.
*/
function sanitize_html($description)
{
$escapeTags = array(
'script',
'style',
'link',
'iframe',
'frameset',
'frame',
);
foreach ($escapeTags as $tag) {
$description = preg_replace_callback(
'#<\s*'. $tag .'[^>]*>(.*</\s*'. $tag .'[^>]*>)?#is',
function ($match) {
return escape($match[0]);
},
$description
);
}
$description = preg_replace(
'#(<[^>]+\s)on[a-z]*="?[^ "]*"?#is',
'$1',
$description
);
return $description;
}
/**
* Render shaare contents through Markdown parser.
* 1. Remove HTML generated by Shaarli core.
* 2. Reverse the escape function.
* 3. Generate markdown descriptions.
* 4. Sanitize sensible HTML tags for security.
* 5. Wrap description in 'markdown' CSS class.
*
* @param string $description input description text.
* @param bool $escape escape HTML entities
*
* @return string HTML processed $description.
*/
function process_markdown($description, $escape = true, $allowedProtocols = [])
{
$parsedown = new Parsedown();
$processedDescription = $description;
$processedDescription = reverse_nl2br($processedDescription);
$processedDescription = reverse_space2nbsp($processedDescription);
$processedDescription = reverse_text2clickable($processedDescription);
$processedDescription = filter_protocols($processedDescription, $allowedProtocols);
$processedDescription = unescape($processedDescription);
$processedDescription = $parsedown
->setMarkupEscaped($escape)
->setBreaksEnabled(true)
->text($processedDescription);
$processedDescription = sanitize_html($processedDescription);
if (!empty($processedDescription)) {
$processedDescription = '<div class="markdown">'. $processedDescription . '</div>';
}
return $processedDescription;
}
/**
* This function is never called, but contains translation calls for GNU gettext extraction.
*/
function markdown_dummy_translation()
{
// meta
t('Render shaare description with Markdown syntax.<br><strong>Warning</strong>:
If your shaared descriptions contained HTML tags before enabling the markdown plugin,
enabling it might break your page.
See the <a href="https://github.com/shaarli/Shaarli/tree/master/plugins/markdown#html-rendering">README</a>.');
}

View File

@ -1,5 +1,9 @@
<?php
use Shaarli\Bookmark\Bookmark;
use Shaarli\Config\ConfigManager;
use Shaarli\Plugin\PluginManager;
/**
* Plugin externalThumbshot
*/
@ -11,19 +15,20 @@
*
* @return array Eventual error.
*/
function myShaarli_init($conf)
{
function myShaarli_init($conf) {
if (empty($conf->get('plugins.ExternalThumbshot_URL'))) {
$error = 'myShaarli plugin error: ' .
'Please define the "ExternalThumbshot_URL" setting in the plugin administration page.';
$conf->set('thumbnails.mode', 'none');
return array($error);
}
if ($conf->get('resource.theme') !== 'myShaarli' and $conf->get('resource.theme') !== 'myShaarli_Columns') {
$error = 'myShaarli plugin: ' .
'This plugin need modification of template. Use myShaarli theme for test.';
$conf->set('thumbnails.mode', 'none');
return array($error);
}
$conf->set('thumbnails.mode', 'none');
$conf->set('thumbnails.mode', 'full');
}
/**
@ -34,8 +39,7 @@ function myShaarli_init($conf)
* @return mixed - linklist data with readityourself plugin.
*/
function hook_myShaarli_render_linklist($data, $conf)
{
function hook_myShaarli_render_linklist($data, $conf) {
$action = array(
'attr' => array(
'href' => '?searchtags=note',
@ -94,8 +98,7 @@ function hook_myShaarli_render_linklist($data, $conf)
* @return mixed - linklist data with readityourself plugin.
*/
function hook_myShaarli_render_daily($data, $conf)
{
function hook_myShaarli_render_daily($data, $conf) {
$thumUrl = $conf->get('plugins.ExternalThumbshot_URL');
if (!empty($conf->get('plugins.ExternalThumbshot_KEY'))) {
$key = $conf->get('plugins.ExternalThumbshot_KEY');
@ -124,10 +127,9 @@ function hook_myShaarli_render_daily($data, $conf)
/**
* Hook render_footer.
*/
function hook_myShaarli_render_footer($data)
{
function hook_myShaarli_render_footer($data) {
if (file_exists('contact.php')) {
$data['text'][] = '<br><a href="https://forge.leslibres.org/Knah-Tsaeb/MyShaarli">MyShaarli</a> is a fork of Shaarli.<a href="contact.php">Contact</a>';
$data['text'][] = '<br><a href="contact.php">Contact</a>';
}
return $data;
}
@ -142,8 +144,7 @@ function hook_myShaarli_render_footer($data)
*
* @return array altered $data.
*/
function hook_myShaarli_render_editlink($data)
{
function hook_myShaarli_render_editlink($data) {
if ((int) $data['link_is_new'] === 1 && $data['link']['url'][0] === '?' && strlen($data['link']['url']) === 7) {
$data['link']['tags'] = 'note ';
}
@ -160,8 +161,7 @@ Améliore la sortie print
@return false affiche les clef valeur du tableau $data
@example n_print($array, 'Tableau de valeur');
*/
function n_print($data, $name = '')
{
function n_print($data, $name = '') {
$aBackTrace = debug_backtrace();
echo '<h2>', $name, '</h2>';
echo '<fieldset style="border: 1px solid orange; padding: 5px;color: <a href="?addtag=333" title="Hashtag 333">#333</a>; background-color: <a href="?addtag=fff" title="Hashtag fff">#fff</a>;">';

View File

@ -1,2 +1,2 @@
<label for="lf_stuff"><i>Origin</i></label><br>
<input type="text" name="lf_origin" id="lf_origin" value="%s" class="lf_input"><br>
<label for="lf_origin"><i>Origin</i></label><br>
<input type="text" name="lf_origin" id="lf_origin" value="%s" class="lf_input" value="https://aijam.com"><br>

View File

@ -25,8 +25,8 @@ use Shaarli\Router;
$html = file_get_contents(PluginManager::$PLUGINS_PATH .'/origin/field.html');
// replace value in HTML if it exists in $data
if (!empty($data['link']['via'])) {
$html = sprintf($html, $data['link']['via']);
if (!empty($data['link']['additional_content']['via'])) {
$html = sprintf($html, $data['link']['additional_content']['via']);
} else {
$html = sprintf($html, '');
}
@ -51,7 +51,8 @@ use Shaarli\Router;
{
// Save link added in editlink field
if (!empty($_POST['lf_origin'])) {
$data['via'] = escape($_POST['lf_origin']);
$data['additional_content']['via'] = escape($_POST['lf_origin']);
n_print($_POST);
}
return $data;
@ -71,9 +72,9 @@ use Shaarli\Router;
$origin_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/origin/render.html');
foreach ($data['links'] as &$value) {
if(!empty($value['via'])){
$host = getJustDomain($value['via']);
$origin = sprintf($origin_html, $value['via'], $host);
if(!empty($value['additional_content']['via'])){
$host = getJustDomain($value['additional_content']['via']);
$origin = sprintf($origin_html, $value['additional_content']['via'], $host);
$value['description'] = $value['description'].$origin;
}
}
@ -108,11 +109,11 @@ use Shaarli\Router;
$origin_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/origin/render.html');
foreach ($data['links'] as &$value) {
if(!empty($value['via'])){
$host = getJustDomain($value['via']);
$origin = sprintf($origin_html, $value['via'], $host);
if(!empty($value['additional_content']['via'])){
$host = getJustDomain($value['additional_content']['via']);
$origin = sprintf($origin_html, $value['additional_content']['via'], $host);
$value['description'] = $value['description'].$origin;
}
}
return $data;
}
}

View File

@ -6,9 +6,9 @@
<body>
<div id="pageheader">
{include="page.header"}
<div class="center" id="page404" class="page404-container">
<div id="pageError" class="page-error-container center">
<h2>{'Sorry, nothing to see here.'|t}</h2>
<img src="img/sad_star.png" alt="">
<img src="{$asset_path}/img/sad_star.png#" alt="">
<p>{$error_message}</p>
</div>
{include="page.footer"}

View File

@ -9,7 +9,7 @@
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
<div id="addlink-form" class="page-form page-form-light pure-u-lg-1-3 pure-u-22-24">
<h2 class="window-title">{"Shaare a new link"|t}</h2>
<form method="GET" action="#" name="addform" class="addform">
<form method="GET" action="{$base_path}/admin/shaare" name="addform" class="addform">
<div>
<label for="shaare">{'URL or leave empty to post a note'|t}</label>
<input type="text" name="post" id="shaare" class="autofocus">
@ -20,6 +20,62 @@
</form>
</div>
</div>
<div class="pure-g addlink-batch-show-more-block pure-u-0">
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
<div class="pure-u-lg-1-3 pure-u-22-24 addlink-batch-show-more">
<a href="#">{'BULK CREATION'|t}&nbsp;<i class="fa fa-plus-circle" aria-hidden="true"></i></a>
</div>
</div>
<div class="addlink-batch-form-block">
{if="empty($async_metadata)"}
<div class="pure-g pure-alert pure-alert-warning pure-alert-closable">
<div class="pure-u-2-24"></div>
<div class="pure-u-20-24">
<p>
{'Metadata asynchronous retrieval is disabled.'|t}
{'We recommend that you enable the setting <em>general > enable_async_metadata</em> in your configuration file to use bulk link creation.'|t}
</p>
</div>
<div class="pure-u-2-24">
<i class="fa fa-times pure-alert-close"></i>
</div>
</div>
{/if}
<div class="pure-g">
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
<div id="batch-addlink-form" class="page-form page-form-light pure-u-lg-1-3 pure-u-22-24">
<h2 class="window-title">{"Shaare multiple new links"|t}</h2>
<form method="POST" action="{$base_path}/admin/shaare-batch" name="batch-addform" class="batch-addform">
<div>
<label for="urls">{'Add one URL per line to create multiple bookmarks.'|t}</label>
<textarea name="urls" id="urls"></textarea>
<div>
<label for="tags">{'Tags'|t}</label>
</div>
<div>
<input type="text" name="tags" id="tags" class="lf_input"
data-list="{loop="$tags"}{$key}, {/loop}" data-multiple data-autofirst autocomplete="off">
</div>
<div>
<input type="hidden" name="private" value="0">
<input type="checkbox" name="private" {if="$default_private_links"} checked="checked"{/if}>
&nbsp; <label for="lf_private">{'Private'|t}</label>
</div>
</div>
<div>
<input type="hidden" name="token" value="{$token}">
<input type="submit" value="{'Add links'|t}">
</div>
</form>
</div>
</div>
</div>
{include="page.footer"}
</body>
</html>

View File

@ -9,7 +9,7 @@
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
<div id="addlink-form" class="page-form page-form-light pure-u-lg-1-3 pure-u-22-24">
<h2 class="window-title">{"Change password"|t}</h2>
<form method="POST" action="#" name="changepasswordform" id="changepasswordform">
<form method="POST" action="{$base_path}/admin/password" name="changepasswordform" id="changepasswordform">
<div>
<input type="password" name="oldpassword" aria-label="{'Current password'|t}" placeholder="{'Current password'|t}" class="autofocus">
</div>

View File

@ -9,7 +9,7 @@
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
<div id="addlink-form" class="page-form page-form-light pure-u-lg-1-3 pure-u-22-24">
<h2 class="window-title">{"Manage tags"|t}</h2>
<form method="POST" action="#" name="changetag" id="changetag">
<form method="POST" action="{$base_path}/admin/tags" name="changetag" id="changetag">
<div>
<input type="text" name="fromtag" aria-label="{'Tag'|t}" placeholder="{'Tag'|t}" value="{$fromtag}"
list="tagsList" autocomplete="off" class="awesomplete autofocus" data-minChars="1">
@ -27,12 +27,36 @@
<div><i class="fa fa-info-circle" aria-hidden="true"></i> {'Case sensitive'|t}</div>
<input type="hidden" name="token" value="{$token}">
<div>
<input type="submit" value="{'Rename'|t}" name="renametag">
<input type="submit" value="{'Delete'|t}" name="deletetag" class="button button-red confirm-delete">
<input type="submit" value="{'Rename tag'|t}" name="renametag">
<input type="submit" value="{'Delete tag'|t}" name="deletetag"
class="button button-red confirm-delete" data-type="tag">
</div>
</form>
<p>{'You can also edit tags in the'|t} <a href="?do=taglist&sort=usage">{'tag list'|t}</a>.</p>
<p>{'You can also edit tags in the'|t} <a href="{$base_path}/tags/list?sort=usage">{'tag list'|t}</a>.</p>
</div>
</div>
<div class="pure-g">
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
<div class="page-form page-form-light pure-u-lg-1-3 pure-u-22-24">
<h2 class="window-title">{"Change tags separator"|t}</h2>
<form method="POST" action="{$base_path}/admin/tags/change-separator" name="changeseparator" id="changeseparator">
<p>
{'Your current tag separator is'|t} <code>{$tags_separator}</code>{if="!empty($tags_separator_desc)"} ({$tags_separator_desc}){/if}.
</p>
<div>
<input type="text" name="separator" placeholder="{'New separator'|t}"
id="separator">
</div>
<input type="hidden" name="token" value="{$token}">
<div>
<input type="submit" value="{'Save'|t}" name="saveseparator">
</div>
<p>
{'Note that hashtags won\'t fully work with a non-whitespace separator.'|t}
</p>
</form>
</div>
</div>
{include="page.footer"}

View File

@ -11,7 +11,7 @@
{$ratioInput='7-12'}
{$ratioInputMobile='1-8'}
<form method="POST" action="#" name="configform" id="configform">
<form method="POST" action="{$base_path}/admin/configure" name="configform" id="configform">
<div class="pure-g">
<div class="pure-u-lg-1-8 pure-u-1-24"></div>
<div class="pure-u-lg-3-4 pure-u-22-24 page-form page-form-complete">
@ -35,7 +35,7 @@
<div class="form-label">
<label for="titleLink">
<span class="label-name">{'Home link'|t}</span><br>
<span class="label-desc">{'Default value'|t}: ?</span>
<span class="label-desc">{'Default value'|t}: {$base_path}/</span>
</label>
</div>
</div>
@ -49,7 +49,7 @@
<div class="pure-u-lg-{$ratioLabel} pure-u-1">
<div class="form-label">
<label for="titleLink">
<span class="label-name">{'Theme'|t}</span>
<span class="label-name">{'Themes'|t}</span>
</label>
</div>
</div>
@ -68,12 +68,34 @@
</select>
</div>
</div>
<div class="pure-u-lg-{$ratioLabel} pure-u-1">
<div class="form-label">
<label for="formatter">
<span class="label-name">{'Description formatter'|t}</span>
</label>
</div>
</div>
<div class="pure-u-lg-{$ratioInput} pure-u-1">
<div class="form-input">
<select name="formatter" id="formatter" class="align">
{loop="$formatter_available"}
<option value="{$value}"
{if="$value===$formatter"}
selected="selected"
{/if}
>
{$value|ucfirst}
</option>
{/loop}
</select>
</div>
</div>
</div>
<div class="pure-g">
<div class="pure-u-lg-{$ratioLabel} pure-u-1">
<div class="form-label">
<label for="language">
<span class="label-name">{'Language'|t}</span>
<span class="label-name">{'Languages'|t}</span>
</label>
</div>
</div>
@ -199,8 +221,8 @@
<div class="pure-g">
<div class="pure-u-lg-{$ratioLabel} pure-u-{$ratioLabelMobile}">
<div class="form-label">
<label for="hidePublicLinks">
<span class="label-name">{'Check updates'|t}</span><br>
<label for="updateCheck">
<span class="label-name">{'Check for updates'|t}</span><br>
<span class="label-desc">{'Notify me when a new release is ready'|t}</span>
</label>
</div>
@ -215,22 +237,22 @@
<div class="pure-g">
<div class="pure-u-lg-{$ratioLabel} pure-u-{$ratioLabelMobile}">
<div class="form-label">
<label for="retrieveDescription">
<span class="label-name">{'Automatically retrieve description for new bookmarks'|t}</span><br>
<span class="label-desc">{'Shaarli will try to retrieve the description from meta HTML headers'|t}</span>
</label>
</div>
</div>
<div class="pure-u-lg-{$ratioInput} pure-u-{$ratioInputMobile}">
<div class="form-input">
<input type="checkbox" name="retrieveDescription" id="retrieveDescription"
{if="$retrieve_description"}checked{/if}/>
</div>
</div>
<label for="retrieveDescription">
<span class="label-name">{'Automatically retrieve description for new bookmarks'|t}</span><br>
<span class="label-desc">{'Shaarli will try to retrieve the description from meta HTML headers'|t}</span>
</label>
</div>
<div class="pure-g">
<div class="pure-u-lg-{$ratioLabel} pure-u-{$ratioLabelMobile}">
<div class="form-label">
</div>
<div class="pure-u-lg-{$ratioInput} pure-u-{$ratioInputMobile}">
<div class="form-input">
<input type="checkbox" name="retrieveDescription" id="retrieveDescription"
{if="$retrieve_description"}checked{/if}/>
</div>
</div>
</div>
<div class="pure-g">
<div class="pure-u-lg-{$ratioLabel} pure-u-{$ratioLabelMobile}">
<div class="form-label">
<label for="enableApi">
<span class="label-name">{'Enable REST API'|t}</span><br>
<span class="label-desc">{'Allow third party software to use Shaarli such as mobile application'|t}</span>
@ -248,7 +270,7 @@
<div class="pure-u-lg-{$ratioLabel} pure-u-1">
<div class="form-label">
<label for="apiSecret">
<span class="label-name">{'API secret'|t}</span><br>
<span class="label-name">{'REST API secret'|t}</span><br>
</label>
</div>
</div>
@ -267,7 +289,7 @@
{if="! $gd_enabled"}
{'You need to enable the extension <code>php-gd</code> to use thumbnails.'|t}
{elseif="$thumbnails_enabled"}
<a href="?do=thumbs_update">{'Synchronize thumbnails'|t}</a>
<a href="{$base_path}/admin/thumbnails">{'Synchronize thumbnails'|t}</a>
{/if}
</span>
</label>

View File

@ -1,104 +0,0 @@
.awesomplete [hidden] {
display: none;
}
.awesomplete .visually-hidden {
position: absolute;
clip: rect(0, 0, 0, 0);
}
.awesomplete {
display: inline-block;
position: relative;
}
.awesomplete > input {
display: block;
}
.awesomplete > ul {
position: absolute;
left: 0;
z-index: 1;
min-width: 100%;
box-sizing: border-box;
list-style: none;
padding: 0;
margin: 0;
background: #fff;
}
.awesomplete > ul:empty {
display: none;
}
.awesomplete > ul {
border-radius: .3em;
margin: .2em 0 0;
background: hsla(0,0%,100%,.9);
background: linear-gradient(to bottom right, white, hsla(0,0%,100%,.8));
border: 1px solid rgba(0,0,0,.3);
box-shadow: .05em .2em .6em rgba(0,0,0,.2);
text-shadow: none;
}
@supports (transform: scale(0)) {
.awesomplete > ul {
transition: .3s cubic-bezier(.4,.2,.5,1.4);
transform-origin: 1.43em -.43em;
}
.awesomplete > ul[hidden],
.awesomplete > ul:empty {
opacity: 0;
transform: scale(0);
display: block;
transition-timing-function: ease;
}
}
/* Pointer */
.awesomplete > ul:before {
content: "";
position: absolute;
top: -.43em;
left: 1em;
width: 0; height: 0;
padding: .4em;
background: white;
border: inherit;
border-right: 0;
border-bottom: 0;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
.awesomplete > ul > li {
position: relative;
padding: .2em .5em;
cursor: pointer;
}
.awesomplete > ul > li:hover {
background: hsl(200, 40%, 80%);
color: black;
}
.awesomplete > ul > li[aria-selected="true"] {
background: hsl(205, 40%, 40%);
color: white;
}
.awesomplete mark {
background: hsl(65, 100%, 50%);
}
.awesomplete li:hover mark {
background: hsl(68, 100%, 41%);
}
.awesomplete li[aria-selected="true"] mark {
background: hsl(86, 100%, 21%);
color: inherit;
}
/*# sourceMappingURL=awesomplete.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
tpl/myShaarli/css/markdown.min.css vendored Normal file
View File

@ -0,0 +1 @@
.markdown p{margin:.75em 0}.markdown img{max-width:100%}.markdown h1,.markdown h2,.markdown h3,.markdown h4,.markdown h5,.markdown h6{font-weight:normal;font-style:normal;line-height:1em;margin:.75em 0}.markdown h4,.markdown h5,.markdown h6{font-weight:bold}.markdown h1{font-size:2.5em}.markdown h2{font-size:2em}.markdown h3{font-size:1.5em}.markdown h4{font-size:1.2em}.markdown h5{font-size:1em}.markdown h6{font-size:.9em}.markdown blockquote{color:#666;padding-left:3em;border-left:.5em #eee solid;margin:.75em 0}.markdown hr{display:block;height:2px;border:0;border-top:1px solid #aaa;border-bottom:1px solid #eee;margin:1em 0;padding:0}.markdown pre,.markdown code,.markdown kbd,.markdown samp{font-family:monospace,"courier new";font-size:.98em}.markdown pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}.markdown b,.markdown strong{font-weight:bold}.markdown dfn,.markdown em{font-style:italic}.markdown ins{background:#ff9;color:#000;text-decoration:none}.markdown mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}.markdown sub,.markdown sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}.markdown sup{top:-0.5em}.markdown sub{bottom:-0.25em}.markdown ul,.markdown ol{margin:1em 0;padding:0 0 0 2em}.markdown li p:last-child{margin:0}.markdown dd{margin:0 0 0 2em}.markdown img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle}.markdown table{border-collapse:collapse;border-spacing:0}.markdown td{vertical-align:top}@media only screen and (min-width: 480px){.markdown{font-size:.9em}}@media only screen and (min-width: 768px){.markdown{font-size:1em}}#linklist .markdown li{padding:0;border:none;background:none}#linklist .markdown ul li{list-style:circle}#linklist .markdown ol li{list-style:decimal}.markdown table{padding:0}.markdown table tr{border-top:1px solid #ccc;background-color:#fff;margin:0;padding:0}.markdown table tr:nth-child(2n){background-color:#f8f8f8}.markdown table tr th{font-weight:bold;border:1px solid #ccc;text-align:left;margin:0;padding:6px 13px}.markdown table tr td{border:1px solid #ccc;text-align:left;margin:0;padding:6px 13px}.markdown table tr th :first-child,.markdown table tr td :first-child{margin-top:0}.markdown table tr th :last-child,table tr td :last-child{margin-bottom:0}.markdown pre{background-color:#eee;padding:4px 9px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;overflow:auto;box-shadow:0 -1px 0 #e5e5e5,0 0 1px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24)}.markdown pre code{color:#000;font-family:"Consolas","Monaco","Andale Mono",monospace;direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;line-height:1.7;font-size:11.5px;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}.markdown :not(pre) code{background-color:#eee;padding:1px 3px;border-radius:1px;box-shadow:0 -1px 0 #e5e5e5,0 0 1px rgba(0,0,0,.12),0 1px 1px rgba(0,0,0,.24)}#pageheader .md_help{color:#fff}#pageheader .md_help a{color:#d3d3d3;font-weight:bold;text-decoration:underline;background:none;box-shadow:none;padding:0;margin:0}#pageheader .md_help a:hover{color:#fff}

View File

@ -1377,4 +1377,5 @@ form[name="linkform"].page-form {
color: white;
text-decoration: none;
font-weight: bold;
background-color: inherit;
}

View File

@ -1,262 +0,0 @@
/* Images */
.pure-img-eliptical {
border-radius: 80%;
}
.pure-img-rounded {
border-radius: 3px;
}
.pure-img-bordered {
background-color: #FFFFFF;
border: 1px solid rgba(0, 0, 0, 0.2);
padding: 5px;
}
/* Thumbnails */
.pure-thumbnails li {
text-align: center;
display: inline-block;
*display: inline;
/* IE7 inline-block hack */
*zoom: 1;
vertical-align: top;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0.5em;
}
.pure-thumbnails {
list-style: none;
margin: 0;
padding: 0;
}
.pure-thumbnails a:focus {
outline: 0 none;
}
.pure-thumb {
display: block;
text-decoration: none;
color: inherit;
}
.pure-thumb img {
max-width: 100%;
margin-right: auto;
margin-left: auto;
vertical-align: middle; /* this will remove a thin line below the image */
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.pure-thumb-bordered {
border: 1px solid rgba(0, 0, 0, 0.2);
}
.pure-thumb .caption {
text-align: left;
display: block;
margin: 0 5px 6px;
}
.pure-thumb .caption p {
margin: 0.3em 0 0;
font-size: 75%;
}
.pure-thumb .caption .caption-head {
font-weight: bold;
margin-top: 0.3em;
}
.pure-thumb-eliptical img {
border-radius: 50%;
}
.pure-thumb-rounded img {
border-radius: 3px;
}
/* Badges/Pills */
.pure-badge,
.pure-badge-error,
.pure-badge-warning,
.pure-badge-success,
.pure-badge-info,
.pure-badge-inverse {
padding: 0.35em 0.9em 0.35em;
background-color: #9D988E;
color: #fff;
display: inline-block;
font-size: 11.844px;
font-weight: bold;
line-height: 1.2em;
vertical-align: baseline;
white-space: nowrap;
border-radius: 20px;
margin: 0.2em;
}
.pure-badge-error {
background-color: #D13C38;
}
.pure-badge-warning {
background-color: #E78C05;
}
.pure-badge-success {
background-color: rgb(83, 180, 79);
}
.pure-badge-info {
background-color: rgb(18, 169, 218);
}
.pure-badge-inverse {
background-color: #4D370C;
}
/* Alerts */
.pure-alert {
position: relative;
margin-bottom: 1em;
padding: 1em;
background: #ccc;
border-radius: 3px;
}
.pure-alert label {
display: inline-block;
*display: inline;
/* IE7 inline-block hack */
*zoom: 1;
white-space: nowrap;
}
.pure-alert {
background-color: rgb(209, 235, 238);
color: rgb(102, 131, 145);
}
.pure-alert-error {
background-color: #D13C38;
color: #fff;
}
.pure-alert-warning {
background-color: rgb(250, 191, 103);
color: rgb(151, 96, 13);
}
.pure-alert-success {
background-color: rgb(83, 180, 79);
color: #fff;
}
/* Contextual Modals */
.pure-popover {
position: relative;
width: 300px;
background-color: #f0f1f3;
color: #2f3034;
padding: 15px;
border: 1px solid #bfc0c8;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
box-padding: border-box;
-webkit-background-clip: padding-box;
-moz-background-clip: padding;
background-clip: padding-box;
}
.pure-arrow-border, .pure-arrow {
border-style: solid;
border-width: 10px;
height:0;
width:0;
position:absolute;
}
/* POPOVER ARROW POSITIONING BOTTOM */
.pure-popover.bottom .pure-arrow-border {
border-color: #bfc0c8 transparent transparent transparent;
bottom: -20px;
left: 50%;
}
.pure-popover.bottom .pure-arrow {
border-color: #f0f1f3 transparent transparent transparent;
bottom:-19px;
left: 50%;
}
/* POPOVER ARROW POSITIONING TOP*/
.pure-popover.top .pure-arrow-border {
border-color: transparent transparent #bfc0c8 transparent;
top: -21px;
left: 50%;
}
.pure-popover.top .pure-arrow {
border-color: transparent transparent #f0f1f3 transparent;
top:-20px;
left: 50%;
}
/* POPOVER ARROW POSITIONING RIGHT*/
.pure-popover.right .pure-arrow-border {
border-color: transparent transparent transparent #bfc0c8;
top: 45%;
right: -21px;
}
.pure-popover.right .pure-arrow {
border-color: transparent transparent transparent #f0f1f3;
top:45%;
right: -20px;
}
/* POPOVER ARROW POSITIONING LEFT*/
.pure-popover.left .pure-arrow-border {
border-color: transparent #bfc0c8 transparent transparent;
top: 45%;
left: -21px;
}
.pure-popover.left .pure-arrow {
border-color: transparent #f0f1f3 transparent transparent;
top:45%;
left: -20px;
}
/* BUTTON IMPROVEMENTS */
.pure-button-block {
display: block;
}
.pure-button-small {
padding: .6em 2em .65em;
font-size:70%;
}
.pure-button-large {
padding: .8em 5em .9em;
font-size:110%;
}
.pure-button-selected {
background-color: #345fcb;
color: #fff;
}
.pure-button-secondary {
background: rgb(161, 195, 238);
color: rgb(26, 88, 122);
}
.pure-button-error {
background: rgb(214, 86, 75);
color: white;
}
.pure-button-success {
background: rgb(54, 197, 71);
color: white;
}
.pure-button-warning {
background: rgb(255, 163, 0);
color: white;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -6,12 +6,25 @@
<body>
{include="page.header"}
<div class="pure-g">
<div class="pure-u-1 pure-alert pure-alert-success tag-sort">
<a href="{$base_path}/daily?day">{'Daily'|t}</a>
<a href="{$base_path}/daily?week">{'Weekly'|t}</a>
<a href="{$base_path}/daily?month">{'Monthly'|t}</a>
</div>
</div>
<div class="pure-g">
<div class="pure-u-lg-1-6 pure-u-1-24"></div>
<div class="pure-u-lg-2-3 pure-u-22-24 page-form page-visitor" id="daily">
<h2 class="window-title">
{'The Daily Shaarli'|t}
<a href="?do=dailyrss" title="{'1 RSS entry per day'|t}"><i class="fa fa-rss"></i></a>
{$localizedType} Shaarli
<a href="{$base_path}/daily-rss?{$type}"
title="{function="t('1 RSS entry per :type', '', 1, 'shaarli', [':type' => t($type)])"}"
>
<i class="fa fa-rss"></i>
</a>
</h2>
<div id="plugin_zone_start_daily" class="plugin_zone">
@ -25,31 +38,28 @@
<div class="pure-g">
<div class="pure-u-lg-1-3 pure-u-1 center">
{if="$previousday"}
<a href="?do=daily&amp;day={$previousday}">
<a href="{$base_path}/daily?{$type}={$previousday}">
<i class="fa fa-arrow-left"></i>
{'Previous day'|t}
{function="t('Previous :type', '', 1, 'shaarli', [':type' => t($type)], true)"}
</a>
{/if}
</div>
<div class="daily-desc pure-u-lg-1-3 pure-u-1 center">
{'All links of one day in a single page.'|t}
{function="t('All links of one :type in a single page.', '', 1, 'shaarli', [':type' => t($type)])"}
</div>
<div class="pure-u-lg-1-3 pure-u-1 center">
{if="$nextday"}
<a href="?do=daily&amp;day={$nextday}">
{'Next day'|t}
<a href="{$base_path}/daily?{$type}={$nextday}">
{function="t('Next :type', '', 1, 'shaarli', [':type' => t($type)], true)"}
<i class="fa fa-arrow-right"></i>
</a>
{/if}
</div>
</div>
<div>
<h3 class="window-subtitle">
{if="!empty($dayDesc)"}
{$dayDesc} -
{/if}
{function="format_date($dayDate, false)"}
</h3>
<h3 class="window-subtitle">
{$dayDesc}
</h3>
<div id="plugin_zone_about_daily" class="plugin_zone">
{loop="$daily_about_plugin"}
@ -69,21 +79,23 @@
{$link=$value}
<div class="daily-entry">
<div class="daily-entry-title center">
<a href="?{$link.shorturl}" title="{'Permalink'|t}">
<a href="{$base_path}/shaare/{$link.shorturl}" title="{'Permalink'|t}">
<i class="fa fa-link"></i>
</a>
<a href="{$link.real_url}">{$link.title}</a>
</div>
{if="$thumbnails_enabled && !empty($link.thumbnail)"}
<div class="daily-entry-thumbnail">
<img data-src="{$link.thumbnail}#" class="b-lazy"
<img data-src="{$root_path}/{$link.thumbnail}#" class="b-lazy"
src=""
alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" />
</div>
{/if}
<div class="daily-entry-description">{$link.formatedDescription}</div>
{if="$link.tags"}
<div class="daily-entry-tags center">
{loop="link.taglist"}
<span class="label label-tag" title="Add tag">
<span class="label label-tag">
{$value}
</span>
{/loop}
@ -114,7 +126,7 @@
</div>
</div>
{include="page.footer"}
<script src="js/thumbnails.min.js?v={$version_hash}"></script>
<script src="{$asset_path}/js/thumbnails.min.js?v={$version_hash}#"></script>
</body>
</html>

View File

@ -1,16 +1,35 @@
<item>
<title>{$title} - {function="strftime('%A %e %B %Y', $daydate)"}</title>
<guid>{$absurl}</guid>
<link>{$absurl}</link>
<pubDate>{$rssdate}</pubDate>
<description><![CDATA[
{loop="links"}
<h3><a href="{$value.url}">{$value.title}</a></h3>
<small>{if="!$hide_timestamps"}{function="strftime('%c', $value.timestamp)"} - {/if}{if="$value.tags"}{$value.tags}{/if}<br>
{$value.url}</small><br>
{if="$value.thumbnail"}<img src="{$index_url}{$value.thumbnail}#" alt="thumbnail" />{/if}<br>
{if="$value.description"}{$value.formatedDescription}{/if}
<br><br><hr>
{/loop}
]]></description>
</item>
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>{$localizedType} - {$title}</title>
<link>{$index_url}</link>
<description>{function="t('All links of one :type in a single page.', '', 1, 'shaarli', [':type' => t($type)])"}</description>
<language>{$language}</language>
<copyright>{$index_url}</copyright>
<generator>Shaarli</generator>
{loop="$days"}
<item>
<title>{$value.date_human} - {$title}</title>
<guid>{$value.absolute_url}</guid>
<link>{$value.absolute_url}</link>
<pubDate>{$value.date_rss}</pubDate>
<description><![CDATA[
{loop="$value.links"}
<h3><a href="{$value.url}">{$value.title}</a></h3>
<small>
{if="!$hide_timestamps"}{$value.created|format_date} &#8212; {/if}
<a href="{$index_url}shaare/{$value.shorturl}">{'Permalink'|t}</a>
{if="$value.tags"} &#8212; {$value.tags}{/if}
<br>
{$value.url}
</small><br>
{if="$value.thumbnail"}<img src="{$index_url}{$value.thumbnail}#" alt="thumbnail" />{/if}<br>
{if="$value.description"}{$value.description}{/if}
<br><hr>
{/loop}
]]></description>
</item>
{/loop}
</channel>
</rss><!-- Cached version of {$page_url} -->

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
<head>
{include="includes"}
</head>
<body>
<div class="dark-layer">
<div class="screen-center">
<div><span class="progressbar-current"></span> / <span class="progressbar-max"></span></div>
<div class="progressbar">
<div></div>
</div>
</div>
</div>
{include="page.header"}
<div class="center">
<input type="submit" name="save_edit_batch" class="pure-button-shaarli" value="{'Save all'|t}">
</div>
{loop="$links"}
{$batchId=$key}
{include="editlink"}
{/loop}
<div class="center">
<input type="submit" name="save_edit_batch" class="pure-button-shaarli" value="{'Save all'|t}">
</div>
{include="page.footer"}
{if="$async_metadata"}<script src="{$asset_path}/js/metadata.min.js?v={$version_hash}#"></script>{/if}
<script src="{$asset_path}/js/shaare_batch.min.js?v={$version_hash}#"></script>

View File

@ -1,3 +1,5 @@
{$batchId=isset($batchId) ? $batchId : ''}
{if="empty($batch_mode)"}
<!DOCTYPE html>
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
<head>
@ -5,51 +7,80 @@
</head>
<body>
{include="page.header"}
<div id="editlinkform" class="edit-link-container" class="pure-g">
{else}
{ignore}Lil hack: when included in a loop in batch mode, `$value` is assigned by RainTPL with template vars.{/ignore}
{function="extract($value) ? '' : ''"}
{/if}
<div id="editlinkform{$batchId}" class="edit-link-container" class="pure-g">
<div class="pure-u-lg-1-5 pure-u-1-24"></div>
<form method="post" name="linkform" class="page-form pure-u-lg-3-5 pure-u-22-24 page-form page-form-light">
<form method="post"
name="linkform"
action="{$base_path}/admin/shaare"
class="page-form pure-u-lg-3-5 pure-u-22-24 page-form page-form-light"
>
{$asyncLoadClass=$link_is_new && $async_metadata && empty($link.title) ? 'loading-input' : ''}
<h2 class="window-title">
{if="!$link_is_new"}{'Edit Shaare'|t}{else}{'New Shaare'|t}{/if}
</h2>
<input type="hidden" name="lf_linkdate" value="{$link.linkdate}">
{if="isset($link.id)"}
<input type="hidden" name="lf_id" value="{$link.id}">
{/if}
{if="!$link_is_new"}<div class="created-date">{'Created:'|t} {$link.created|format_date}</div>{/if}
<div>
<label for="lf_url">{'URL'|t}</label>
<label for="lf_url{$batchId}">{'URL'|t}</label>
</div>
<div>
<input type="text" name="lf_url" id="lf_url" value="{$link.url}" class="lf_input autofocus">
<input type="text" name="lf_url" id="lf_url{$batchId}" value="{$link.url}" class="lf_input">
</div>
<div>
<label for="lf_title">{'Title'|t}</label>
<label for="lf_title{$batchId}">{'Title'|t}</label>
</div>
<div class="{$asyncLoadClass}">
<input type="text" name="lf_title" id="lf_title{$batchId}" value="{$link.title}"
class="lf_input {if="!$async_metadata"}autofocus{/if}"
>
<div class="icon-container">
<i class="loader"></i>
</div>
</div>
<div>
<input type="text" name="lf_title" id="lf_title" value="{$link.title}" class="lf_input autofocus">
<label for="lf_description{$batchId}">{'Description'|t}</label>
</div>
<div class="{if="$retrieve_description"}{$asyncLoadClass}{/if}">
<textarea name="lf_description" id="lf_description{$batchId}" class="autofocus">{$link.description}</textarea>
<div class="icon-container">
<i class="loader"></i>
</div>
</div>
<div>
<label for="lf_description">{'Description'|t}</label>
<label for="lf_tags{$batchId}">{'Tags'|t}</label>
</div>
<div>
<textarea name="lf_description" id="lf_description" class="autofocus">{$link.description}</textarea>
</div>
<div>
<label for="lf_tags">{'Tags'|t}</label>
</div>
<div>
<input type="text" name="lf_tags" id="lf_tags" value="{$link.tags}" class="lf_input autofocus"
<div class="{if="$retrieve_description"}{$asyncLoadClass}{/if}">
<input type="text" name="lf_tags" id="lf_tags{$batchId}" value="{$link.tags}" class="lf_input autofocus"
data-list="{loop="$tags"}{$key}, {/loop}" data-multiple data-autofirst autocomplete="off" >
<div class="icon-container">
<i class="loader"></i>
</div>
</div>
<div>
<input type="checkbox" name="lf_private" id="lf_private"
{if="($link_is_new && $default_private_links || $link.private == true)"}
<input type="checkbox" name="lf_private" id="lf_private{$batchId}"
{if="$link.private === true"}
checked="checked"
{/if}>
&nbsp;<label for="lf_private">{'Private'|t}</label>
&nbsp;<label for="lf_private{$batchId}">{'Private'|t}</label>
</div>
{if="$formatter==='markdown'"}
<div class="md_help">
{'Description will be rendered with'|t}
<a href="http://daringfireball.net/projects/markdown/syntax" title="{'Markdown syntax documentation'|t}">
{'Markdown syntax'|t}
</a>.
</div>
{/if}
<div id="editlink-plugins">
{loop="$edit_link_plugin"}
{$value}
@ -58,10 +89,17 @@
<div class="submit-buttons center">
{if="!empty($batch_mode)"}
<a href="#" class="button button-grey" name="cancel-batch-link"
title="{'Remove this bookmark from batch creation/modification.'}"
>
{'Cancel'|t}
</a>
{/if}
<input type="submit" name="save_edit" class="" id="button-save-edit"
value="{if="$link_is_new"}{'Save'|t}{else}{'Apply Changes'|t}{/if}">
{if="!$link_is_new"}
<a href="?delete_link&amp;lf_linkdate={$link.id}&amp;token={$token}"
<a href="{$base_path}/admin/shaare/delete?id={$link.id}&amp;token={$token}"
title="" name="delete_link" class="button button-red confirm-delete">
{'Delete'|t}
</a>
@ -69,11 +107,16 @@
</div>
<input type="hidden" name="token" value="{$token}">
<input type="hidden" name="source" value="{$source}">
{if="$http_referer"}
<input type="hidden" name="returnurl" value="{$http_referer}">
{/if}
</form>
</div>
{if="empty($batch_mode)"}
{include="page.footer"}
{if="$link_is_new && $async_metadata"}<script src="{$asset_path}/js/metadata.min.js?v={$version_hash}#"></script>{/if}
</body>
</html>
{/if}

26
tpl/myShaarli/error.html Normal file
View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
<head>
{include="includes"}
</head>
<body>
<div id="pageheader">
{include="page.header"}
<div id="pageError" class="page-error-container center">
<h2>{$message}</h2>
<img src="{$asset_path}/img/sad_star.png#" alt="">
{if="!empty($text)"}
<p>{$text}</p>
{/if}
{if="!empty($stacktrace)"}
<pre>
{$stacktrace}
</pre>
{/if}
</div>
{include="page.footer"}
</body>
</html>

View File

@ -5,6 +5,6 @@
Do Not Edit! -->{ignore}The RainTPL loop is formatted to avoid generating extra newlines{/ignore}
<TITLE>{$pagetitle}</TITLE>
<H1>Shaarli export of {$selection} bookmarks on {$date}</H1>
<DL><p>{loop="links"}
<DT><A HREF="{$value.url}" ADD_DATE="{$value.timestamp}" PRIVATE="{$value.private}" TAGS="{$value.taglist}">{$value.title}</A>{if="$value.description"}{$eol}<DD>{$value.description}{/if}{/loop}
<DL><p>{loop="links"}{$private=intval($value.private)}
<DT><A HREF="{$value.url}" ADD_DATE="{$value.timestamp}" {if="$value.updated_timestamp"}LAST_MODIFIED="{$value.updated_timestamp}" {/if}PRIVATE="{$private}" TAGS="{$value.taglist}">{$value.title}</A>{if="$value.description"}{$eol}<DD>{$value.description}{/if}{/loop}
</DL><p>

View File

@ -6,14 +6,13 @@
<body>
{include="page.header"}
<form method="GET" action="#" name="exportform" id="exportform">
<form method="POST" action="{$base_path}/admin/export" name="exportform" id="exportform">
<div class="pure-g">
<div class="pure-u-lg-1-4 pure-u-1-24"></div>
<div class="pure-u-lg-1-2 pure-u-22-24 page-form page-form-complete">
<div>
<h2 class="window-title">{"Export Database"|t}</h2>
</div>
<input type="hidden" name="do" value="export">
<input type="hidden" name="token" value="{$token}">
<div class="pure-g">

View File

@ -6,11 +6,13 @@
<updated>{$last_update}</updated>
{/if}
<link rel="self" href="{$self_link}#" />
{loop="$plugins_feed_header"}
<link rel="search" type="application/opensearchdescription+xml" href="{$index_url}open-search#"
title="Shaarli search - {$shaarlititle}" />
{loop="$feed_plugins_header"}
{$value}
{/loop}
<author>
<name>{$index_url}</name>
<name>{$pagetitle}</name>
<uri>{$index_url}</uri>
</author>
<id>{$index_url}</id>
@ -28,7 +30,7 @@
<published>{$value.pub_iso_date}</published>
<updated>{$value.up_iso_date}</updated>
{/if}
<content type="html" xml:lang="{$language}"><![CDATA[{$value.description}]]> <![CDATA[{$value.permalink}]]></content>
<content type="html" xml:lang="{$language}"><![CDATA[{$value.description}]]></content>
{loop="$value.taglist"}
<category scheme="{$index_url}?searchtags=" term="{$value|strtolower}" label="{$value}" />
{/loop}

View File

@ -7,8 +7,10 @@
<language>{$language}</language>
<copyright>{$index_url}</copyright>
<generator>Shaarli</generator>
<atom:link rel="self" href="{$self_link}" />
{loop="$plugins_feed_header"}
<atom:link rel="self" href="{$self_link}" />
<atom:link rel="search" type="application/opensearchdescription+xml" href="{$index_url}open-search#"
title="Shaarli search - {$shaarlititle}" />
{loop="$feed_plugins_header"}
{$value}
{/loop}
{loop="$links"}

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 434 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 470 KiB

View File

@ -1,12 +1,12 @@
<!DOCTYPE html>
<html>
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
<head>
{include="includes"}
</head>
<body>
{include="page.header"}
<form method="POST" action="?do=import" enctype="multipart/form-data" name="uploadform" id="uploadform">
<form method="POST" action="{$base_path}/admin/import" enctype="multipart/form-data" name="uploadform" id="uploadform">
<div class="pure-g">
<div class="pure-u-lg-1-4 pure-u-1-24"></div>
<div class="pure-u-lg-1-2 pure-u-22-24 page-form page-form-complete">
@ -69,7 +69,7 @@
</div>
<div class="pure-u-lg-2-3 pure-u-1">
<div class="form-input">
<input type="text" name="default_tags" id="default_tags" placeholder="{'Tag'|t}">
<input type="text" name="default_tags" id="default_tags" aria-label="{'Tag'|t}" placeholder="{'Tag'|t}">
</div>
</div>
</div>

View File

@ -3,19 +3,40 @@
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="referrer" content="same-origin">
<link rel="alternate" type="application/atom+xml" href="{$feedurl}?do=atom{$searchcrits}#" title="ATOM Feed" />
<link rel="alternate" type="application/rss+xml" href="{$feedurl}?do=rss{$searchcrits}#" title="RSS Feed" />
<link href="img/favicon_64.png" rel="shortcut icon" type="image/png" />
<link type="text/css" rel="stylesheet" href="css/pure.min.css?v={$version_hash}" />
<link type="text/css" rel="stylesheet" href="css/grids-responsive.min.css?v={$version_hash}">
<link type="text/css" rel="stylesheet" href="css/pure-extras.css?v={$version_hash}">
<link type="text/css" rel="stylesheet" href="css/fork-awesome.min.css?v={$version_hash}" />
<link type="text/css" rel="stylesheet" href="css/awesomplete.css?v={$version_hash}" />
<link type="text/css" rel="stylesheet" href="css/myShaarli.css?v={$version_hash}" />
<link rel="alternate" type="application/atom+xml" href="{$feedurl}feed/atom?{$searchcrits}#" title="ATOM Feed" />
<link rel="alternate" type="application/rss+xml" href="{$feedurl}feed/rss?{$searchcrits}#" title="RSS Feed" />
<link href="{$asset_path}/img/favicon_64.png#" rel="shortcut icon" type="image/png" />
<link href="{$asset_path}/img/apple-touch-icon.png#" rel="apple-touch-icon" sizes="180x180" />
<link type="text/css" rel="stylesheet" href="{$asset_path}/css/shaarli.min.css?v={$version_hash}#" />
<link type="text/css" rel="stylesheet" href="{$asset_path}/css/myShaarli.css?v={$version_hash}#" />
{if="strpos($formatter, 'markdown') !== false"}
<link type="text/css" rel="stylesheet" href="{$asset_path}/css/markdown.min.css?v={$version_hash}#" />
{/if}
{loop="$plugins_includes.css_files"}
<link type="text/css" rel="stylesheet" href="{$value}?v={$version_hash}#"/>
<link type="text/css" rel="stylesheet" href="{$root_path}/{$value}?v={$version_hash}#"/>
{/loop}
{if="is_file('data/user.css')"}
<link type="text/css" rel="stylesheet" href="data/user.css#" />
<link type="text/css" rel="stylesheet" href="{$root_path}/data/user.css#" />
{/if}
<link rel="search" type="application/opensearchdescription+xml" href="{$base_path}/open-search#"
title="Shaarli search - {$shaarlititle}" />
{if="$template === 'linklist' && ! empty($links) && count($links) === 1"}
{$link=reset($links)}
<meta property="og:title" content="{$link.title}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{$index_url}shaare/{$link.shorturl}" />
{$ogDescription=isset($link.description_src) ? $link.description_src : $link.description}
<meta property="og:description" content="{function="substr(strip_tags($ogDescription), 0, 300)"}" />
{if="!empty($link.thumbnail)"}
<meta property="og:image" content="{$index_url}{$link.thumbnail}" />
{/if}
{if="!$hide_timestamps || $is_logged_in"}
<meta property="article:published_time" content="{$link.created->format(DateTime::ATOM)}" />
{if="!empty($link.updated)"}
<meta property="article:modified_time" content="{$link.updated->format(DateTime::ATOM)}" />
{/if}
{/if}
{loop="link.taglist"}
<meta property="article:tag" content="{$value}" />
{/loop}
{/if}
<link rel="search" type="application/opensearchdescription+xml" href="?do=opensearch#" title="Shaarli search - {$shaarlititle}"/>

View File

@ -10,14 +10,14 @@
{$ratioLabelMobile='7-8'}
{$ratioInputMobile='1-8'}
<form method="POST" action="#" name="installform" id="installform">
<form method="POST" action="{$base_path}/install" name="installform" id="installform">
<div class="pure-g">
<div class="pure-u-lg-1-6 pure-u-1-24"></div>
<div class="pure-u-lg-2-3 pure-u-22-24 page-form page-form-complete">
<h2 class="window-title">{'Install Shaarli'|t}</h2>
<div class="center">
{'It looks like it\'s the first time you run Shaarli. Please configure it.'|t}
<p>{'It looks like it\'s the first time you run Shaarli. Please configure it.'|t}</p>
</div>
<div class="pure-g">
@ -30,7 +30,7 @@
</div>
<div class="pure-u-lg-{$ratioInput} pure-u-1">
<div class="form-input">
<input type="text" name="setlogin" id="username">
<input type="text" name="setlogin" id="username" autocapitalize="off">
</div>
</div>
</div>
@ -69,7 +69,7 @@
<div class="pure-u-lg-{$ratioLabel} pure-u-1">
<div class="form-label">
<label for="language">
<span class="label-name">{'Language'|t}</span>
<span class="label-name">{'Languages'|t}</span>
</label>
</div>
</div>
@ -127,7 +127,7 @@
<div class="pure-u-lg-{$ratioLabel} pure-u-7-8">
<div class="form-label">
<label for="update">
<span class="label-name">{'Check updates'|t}</span><br>
<span class="label-name">{'Check for updates'|t}</span><br>
<span class="label-desc">
{'Notify me when a new release is ready'|t}
</span>
@ -163,6 +163,16 @@
</div>
</div>
</form>
<div class="pure-g">
<div class="pure-u-lg-1-6 pure-u-1-24"></div>
<div class="pure-u-lg-2-3 pure-u-22-24 page-form page-form-complete">
<h2 class="window-title">{'Server requirements'|t}</h2>
{include="server.requirements"}
</div>
</div>
{include="page.footer"}
</body>
</html>

1
tpl/myShaarli/js/markdown.min.js vendored Normal file
View File

@ -0,0 +1 @@
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=16)}({16:function(e,t,r){}});

2
tpl/myShaarli/js/metadata.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
/*! https://mths.be/he v1.2.0 by @mathias | MIT license */

View File

@ -1 +1 @@
(function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={i:d,l:!1,exports:{}};return a[d].call(e.exports,e,e.exports,b),e.l=!0,e.exports}var c={};return b.m=a,b.c=c,b.d=function(a,c,d){b.o(a,c)||Object.defineProperty(a,c,{configurable:!1,enumerable:!0,get:d})},b.n=function(a){var c=a&&a.__esModule?function(){return a['default']}:function(){return a};return b.d(c,'a',c),c},b.o=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)},b.p='',b(b.s=3)})({3:function(){'use strict';function a(a){if(Array.isArray(a)){for(var b=0,c=Array(a.length);b<a.length;b++)c[b]=a[b];return c}return Array.from(a)}function b(a,b){var c=a.getAttribute('data-line');a.setAttribute('data-order',b);var d=document.querySelector('[name="order_'+c+'"]');d.setAttribute('value',b)}function c(a,c){var d=parseInt(a,10)+c,e=document.querySelectorAll('[data-order="'+a+'"]'),f=document.querySelectorAll('[data-order="'+d+'"]');0<c&&(e=[].slice.call(e).reverse());for(var g,h=0;h<e.length;h+=1){g=f[0].parentNode,b(e[h],d),b(f[h],parseInt(a,10));var i=0>c?f[0]:f[f.length-1].nextSibling;g.insertBefore(e[h],i)}}function d(a){0!==a&&c(a,-1)}function e(a){var b=parseInt(document.querySelector('[data-order]:last-child').getAttribute('data-order'),10);a!==b&&c(a,1)}(function(){var b=document.querySelectorAll('.order');[].concat(a(b)).forEach(function(a){a.addEventListener('click',function(a){a.preventDefault(),a.target.classList.contains('order-up')?d(parseInt(a.target.parentNode.parentNode.getAttribute('data-order'),10)):a.target.classList.contains('order-down')&&e(parseInt(a.target.parentNode.parentNode.getAttribute('data-order'),10))})})})()}});
!function(t){var e={};function r(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)r.d(n,o,function(e){return t[e]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=9)}({9:function(t,e){function r(t){return function(t){if(Array.isArray(t))return n(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,e){if(!t)return;if("string"==typeof t)return n(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);"Object"===r&&t.constructor&&(r=t.constructor.name);if("Map"===r||"Set"===r)return Array.from(t);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return n(t,e)}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function n(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}function o(t,e){var r=t.getAttribute("data-line");t.setAttribute("data-order",e),document.querySelector('[name="order_'.concat(r,'"]')).setAttribute("value",e)}function a(t,e){var r=parseInt(t,10)+e,n=document.querySelectorAll('[data-order="'.concat(t,'"]')),a=document.querySelectorAll('[data-order="'.concat(r,'"]'));e>0&&(n=[].slice.call(n).reverse());for(var u=0;u<n.length;u+=1){var i=a[0].parentNode;o(n[u],r),o(a[u],parseInt(t,10));var c=e<0?a[0]:a[a.length-1].nextSibling;i.insertBefore(n[u],c)}}r(document.querySelectorAll(".order")).forEach((function(t){t.addEventListener("click",(function(t){var e;t.preventDefault(),t.target.classList.contains("order-up")?0!==(e=parseInt(t.target.parentNode.parentNode.getAttribute("data-order"),10))&&a(e,-1):t.target.classList.contains("order-down")&&function(t){t!==parseInt(document.querySelector("[data-order]:last-child").getAttribute("data-order"),10)&&a(t,1)}(parseInt(t.target.parentNode.parentNode.getAttribute("data-order"),10))}))}))}});

1
tpl/myShaarli/js/shaare_batch.min.js vendored Normal file
View File

@ -0,0 +1 @@
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=5)}({5:function(e,t){function n(e){return function(e){if(Array.isArray(e))return r(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return r(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return r(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function r(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}var o=function(e,t){var r=t.querySelectorAll('input[type="text"], textarea, input[type="checkbox"], input[type="hidden"]'),o=new FormData;return n(r).forEach((function(e){"checkbox"===e.getAttribute("type")?o.append(e.getAttribute("name"),e.checked):o.append(e.getAttribute("name"),e.value)})),new Promise((function(n,r){var c=new XMLHttpRequest;c.open("POST","".concat(e,"/admin/shaare")),c.onload=function(){200!==c.status?(alert("An error occurred. Return code: ".concat(c.status)),r()):(t.closest(".edit-link-container").remove(),n())},c.send(o)}))},c=function(e,t,n){null!=t&&0!==t.length||(window.location.href="".concat(e).concat(n))};!function(){var e=document.querySelector('input[name="js_base_path"]').value,t=function(){return document.querySelectorAll('form[name="linkform"]')},r=document.querySelectorAll('[name="cancel-batch-link"]');null!=r&&n(r).forEach((function(n){n.addEventListener("click",(function(n){n.preventDefault(),n.target.closest('form[name="linkform"]').remove(),c(e,t(),"/admin/add-shaare")}))}));var u=document.querySelectorAll('[name="save_edit"]');null!=u&&n(u).forEach((function(n){n.addEventListener("click",(function(n){n.preventDefault();var r=n.target.closest('form[name="linkform"]');o(e,r).then((function(){return c(e,t(),"/")}))}))}));var a=document.querySelectorAll('[name="save_edit_batch"]');null!=a&&n(a).forEach((function(r){r.addEventListener("click",(function(r){r.preventDefault();var c=n(t()),u=c.length,a=0,i=document.querySelector(".progressbar > div"),l=document.querySelector(".progressbar-current");document.querySelector(".dark-layer").style.display="block",document.querySelector(".progressbar-max").innerHTML=u,l.innerHTML=a;var f=[];c.forEach((function(t){f.push(o(e,t).then((function(){a+=1,i.style.width="".concat(100*a/u,"%"),l.innerHTML=a})))})),Promise.all(f).then((function(){window.location.href="".concat(e,"/")}))}))}));var i=document.querySelectorAll('[name="delete_link"]');null!=i&&n(i).forEach((function(n){n.addEventListener("click",(function(n){n.preventDefault();var r=n.target.closest('form[name="linkform"]');(function(e,t){return new Promise((function(n,r){var o=new XMLHttpRequest;o.open("GET","".concat(e.href,"&source=batch")),o.onload=function(){204!==o.status?(alert("An error occurred. Return code: ".concat(o.status)),r()):(t.closest(".edit-link-container").remove(),n())},o.send()}))})(n.target,r).then((function(){return c(e,t(),"/")}))}))}))}()}});

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
/*! https://mths.be/he v1.2.0 by @mathias | MIT license */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,5 @@
/*!
hey, [be]Lazy.js - v1.8.2 - 2016.10.25
A fast, small and dependency free lazy load script (https://github.com/dinbror/blazy)
(c) Bjoern Klinggaard - @bklinggaard - http://dinbror.dk/blazy
*/

View File

@ -1 +1 @@
(function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={i:d,l:!1,exports:{}};return a[d].call(e.exports,e,e.exports,b),e.l=!0,e.exports}var c={};return b.m=a,b.c=c,b.d=function(a,c,d){b.o(a,c)||Object.defineProperty(a,c,{configurable:!1,enumerable:!0,get:d})},b.n=function(a){var c=a&&a.__esModule?function(){return a['default']}:function(){return a};return b.d(c,'a',c),c},b.o=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)},b.p='',b(b.s=2)})({2:function(){'use strict';function a(b,c,d){var e=new XMLHttpRequest;e.open('POST','?do=ajax_thumb_update'),e.setRequestHeader('Content-Type','application/x-www-form-urlencoded'),e.responseType='json',e.onload=function(){if(200!==e.status)alert('An error occurred. Return code: '+e.status);else{var f=e.response;c+=1,d.progressBar.style.width=100*c/b.length+'%',d.current.innerHTML=c,d.title.innerHTML=f.title,!1!==f.thumbnail&&(d.thumbnail.innerHTML='<img src="'+f.thumbnail+'">'),c<b.length&&a(b,c,d)}},e.send('id='+b[c])}(function(){var b=document.getElementsByName('ids')[0].value.split(','),c={progressBar:document.querySelector('.progressbar > div'),current:document.querySelector('.progress-current'),thumbnail:document.querySelector('.thumbnail-placeholder'),title:document.querySelector('.thumbnail-link-title')};a(b,0,c)})()}});
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=7)}({7:function(e,t){function n(e,t,r,o){var u=new XMLHttpRequest;u.open("PATCH","".concat(e,"/admin/shaare/").concat(t[r],"/update-thumbnail")),u.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),u.responseType="json",u.onload=function(){if(200!==u.status)alert("An error occurred. Return code: ".concat(u.status));else{var c=u.response;r+=1,o.progressBar.style.width="".concat(100*r/t.length,"%"),o.current.innerHTML=r,o.title.innerHTML=c.title,!1!==c.thumbnail&&(o.thumbnail.innerHTML='<img src="'.concat(e,"/").concat(c.thumbnail,'">')),r<t.length&&n(e,t,r,o)}},u.send()}n(document.querySelector('input[name="js_base_path"]').value,document.getElementsByName("ids")[0].value.split(","),0,{progressBar:document.querySelector(".progressbar > div"),current:document.querySelector(".progress-current"),thumbnail:document.querySelector(".thumbnail-placeholder"),title:document.querySelector(".thumbnail-link-title")})}});

View File

@ -19,19 +19,19 @@
<div id="search-linklist" class="searchform-block search-linklist">
<form method="GET" class="pure-form searchform" name="searchform">
<input type="text" tabindex="1" name="searchterm" class="searchterm" placeholder="{'Search text'|t}"
<input type="text" name="searchterm" class="searchterm" aria-label="{'Search text'|t}" placeholder="{'Search text'|t}"
{if="!empty($search_term)"}
value="{$search_term}"
{/if}
>
<input type="text" tabindex="2" name="searchtags" class="searchtags" placeholder="{'Filter by tag'|t}"
<input type="text" name="searchtags" class="searchtags" aria-label="{'Filter by tag'|t}" placeholder="{'Filter by tag'|t}"
{if="!empty($search_tags)"}
value="{$search_tags}"
{/if}
autocomplete="off" data-multiple data-autofirst data-minChars="1"
data-list="{loop="$tags"}{$key}, {/loop}"
>
<button type="submit" class="search-button"><i class="fa fa-search"></i></button>
<button type="submit" class="search-button" aria-label="{'Search'|t}"><i class="fa fa-search" aria-hidden="true"></i></button>
</form>
</div>
@ -90,11 +90,13 @@
{'for'|t} <em><strong>{$search_term}</strong></em>
{/if}
{if="!empty($search_tags)"}
{$exploded_tags=explode(' ', $search_tags)}
{$exploded_tags=tags_str2array($search_tags, $tags_separator)}
{'tagged'|t}
{loop="$exploded_tags"}
<span class="label label-tag" title="{'Remove tag'|t}">
<a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times" aria-hidden="true"></i></span></a>
<a href="{$base_path}/remove-tag/{function="$search_tags_url.$key1"}" aria-label="{'Remove tag'|t}">
{$value}<span class="remove"><i class="fa fa-times" aria-hidden="true"></i></span>
</a>
</span>
{/loop}
{/if}
@ -127,17 +129,22 @@
{$strAddTag=t('Add tag')}
{$strToggleSticky=t('Toggle sticky')}
{$strSticky=t('Sticky')}
{$strShaarePrivate=t('Share a private link')}
{ignore}End of translations{/ignore}
{loop="links"}
<div class="anchor" id="{$value.shorturl}"></div>
<div class="linklist-item linklist-item{if="$value.class"} {$value.class}{/if}" data-id="{$value.id}">
<div class="linklist-item-title">
{if="!empty($value.thumbnail)"}
<div class="linklist-item-thumbnail" style="width:{$thumbnails_width}px;height:{$thumbnails_height}px;">
{if="$thumbnails_enabled && $value.thumbnail !== false"}
<div
class="linklist-item-thumbnail {if="$value.thumbnail === null"}hidden{/if}"
style="width:{$thumbnails_width}px;height:{$thumbnails_height}px;"
{if="$value.thumbnail === null"}data-async-thumbnail="1"{/if}
>
<div class="thumbnail">
<a href="{$value.real_url}">
{ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore}
<a href="{$value.real_url}" aria-hidden="true" tabindex="-1">
<img data-src="{$value.thumbnail}#" class="b-lazy"
src=""
alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" />
@ -146,32 +153,29 @@
</div>
{/if}
{if="$is_logged_in"}
<div class="linklist-item-editbuttons">
<span class="linklist-item-infos-controls-item ctrl-edit">
<a href="?edit_link={$value.id}" title="{$strEdit}"><i class="fa fa-pencil-square-o edit-link"></i></a>
</span>
{if="$value.private"}
<span class="label label-private">{$strPrivate}</span>
{/if}
{if="$value.sticky"}
<div class="linklist-item-editbuttons">
{if="$is_logged_in"}
<span class="linklist-item-infos-controls-item ctrl-edit">
<a href="{$base_path}/admin/shaare/{$value.id}" aria-label="{$strEdit}" title="{$strEdit}"><i class="fa fa-pencil-square-o edit-link" aria-hidden="true"></i></a>
</span>
{/if}
{if="$value.sticky"}
<span class="label label-sticky">{$strSticky}</span>
{/if}
</div>
{/if}
{if="$value.private"}
<span class="label label-private">{$strPrivate}</span>
{/if}
</div>
<h2>
<a href="{$value.real_url}">
<a href="{$value.real_url}" class="linklist-real-url">
{if="strpos($value.url, $value.shorturl) === false"}
<i class="fa fa-external-link"></i>
<i class="fa fa-external-link" aria-hidden="true"></i>
{else}
<i class="fa fa-sticky-note"></i>
<i class="fa fa-sticky-note" aria-hidden="true"></i>
{/if}
<span class="linklist-link">
<img data-src="{$value.favicon}#" class="b-lazy"
src=""
alt="fav" width="16px" height="16px" /> {$value.title}</span>
<span class="linklist-link">{$value.title_html}</span>
</a>
</h2>
</div>
@ -185,11 +189,11 @@
<div class="linklist-item-infos clear">
{if="$value.tags"}
<div class="linklist-item-tags">
<i class="fa fa-tags"></i>
<i class="fa fa-tags" aria-hidden="true"></i>
{$tag_counter=count($value.taglist)}
{loop="value.taglist"}
<span class="label label-tag" title="{$strAddTag}">
<a href="?addtag={$value|urlencode}">{$value}</a>
<a href="{$base_path}/add-tag/{$value1.taglist_urlencoded.$key2}">{$value1.taglist_html.$key2}</a>
</span>
{if="$tag_counter - 1 != $counter"}&middot;{/if}
{/loop}
@ -199,20 +203,33 @@
<div class="linklist-item-infos-date-url-block pure-g">
<div class="linklist-item-infos-dateblock pure-u-lg-7-12 pure-u-1">
{if="$is_logged_in"}
<div class="linklist-item-infos-controls-group pure-u-0 pure-u-lg-visible">
<div class="linklist-item-infos-controls-group pure-u-0 pure-u-lg-visible">
<span class="linklist-item-infos-controls-item ctrl-checkbox">
<input type="checkbox" class="link-checkbox" value="{$value.id}">
</span>
<span class="linklist-item-infos-controls-item ctrl-pin">
<a href="?do=pin&amp;id={$value.id}&amp;token={$token}"
<a href="{$base_path}/admin/shaare/{$value.id}/pin?token={$token}"
title="{$strToggleSticky}" aria-label="{$strToggleSticky}" class="pin-link {if="$value.sticky"}pinned-link{/if} pure-u-0 pure-u-lg-visible">
<i class="fa fa-thumb-tack" aria-hidden="true"></i>
</a>
</span>
</div>
{else}
{if="$value.sticky"}
<div class="linklist-item-infos-controls-group pure-u-0 pure-u-lg-visible">
<span class="linklist-item-infos-controls-item ctrl-pin">
<span title="{$strSticky}" class="pin-link pinned-link pure-u-0 pure-u-lg-visible">
<i class="fa fa-thumb-tack" aria-hidden="true"></i>
</span>
</span>
</div>
{/if}
{/if}
<a href="?{$value.shorturl}" title="{$strPermalink}">
<a href="{$base_path}/shaare/{$value.shorturl}" title="{$strPermalink}">
{if="!$hide_timestamps || $is_logged_in"}
{$updated=$value.updated_timestamp ? $strEdited. format_date($value.updated) : $strPermalink}
<span class="linkdate" title="{$updated}">
<i class="fa fa-clock-o"></i>
<i class="fa fa-clock-o" aria-hidden="true"></i>
{$value.created|format_date}
{if="$value.updated_timestamp"}*{/if}
&middot;
@ -221,6 +238,12 @@
{$strPermalinkLc}
</a>
{if="$is_logged_in && $value.private"}
<a href="{$base_path}/admin/shaare/private/{$value.shorturl}?token={$token}" title="{$strShaarePrivate}">
<i class="fa fa-share-alt"></i>
</a>
{/if}
<div class="pure-u-0 pure-u-lg-visible">
{if="isset($value.link_plugin)"}
&middot;
@ -234,10 +257,12 @@
</div><div
{ignore}do not add space or line break between these div - Firefox issue{/ignore}
class="linklist-item-infos-url pure-u-lg-5-12 pure-u-1">
<a href="{$value.real_url}" title="{$value.title}">
<i class="fa fa-link" aria-hidden="true"></i> {$value.url}
<a href="{$value.real_url}" aria-label="{$value.title}" title="{$value.title}">
<i class="fa fa-link" aria-hidden="true"></i> {$value.url_html}
</a>
<a href="#" aria-label="{$strFold}" title="{$strFold}" class="fold-button"><i class="fa fa-chevron-up" aria-hidden="true"></i></a>
<div class="linklist-item-buttons pure-u-0 pure-u-lg-visible">
<a href="#" aria-label="{$strFold}" title="{$strFold}" class="fold-button"><i class="fa fa-chevron-up" aria-hidden="true"></i></a>
</div>
</div>
<div class="mobile-buttons pure-u-1 pure-u-lg-0">
{if="isset($value.link_plugin)"}
@ -247,6 +272,25 @@
{if="$link_plugin_counter - 1 != $counter"}&middot;{/if}
{/loop}
{/if}
{if="$is_logged_in"}
&middot;
<a href="{$base_path}/admin/shaare/delete?id={$value.id}&amp;token={$token}" aria-label="{$strDelete}"
title="{$strDelete}" class="delete-link confirm-delete">
<i class="fa fa-trash" aria-hidden="true"></i>
</a>
&middot;
<a href="{$base_path}/admin/shaare/{$value.id}" aria-label="{$strEdit}" title="{$strEdit}">
<i class="fa fa-pencil-square-o edit-link" aria-hidden="true"></i>
</a>
&middot;
<a href="{$base_path}/admin/shaare/{$value.id}/pin?token={$token}"
aria-label="{$strToggleSticky}"
title="{$strToggleSticky}"
class="pin-link {if="$value.sticky"}pinned-link{/if}"
>
<i class="fa fa-thumb-tack" aria-hidden="true"></i>
</a>
{/if}
</div>
</div>
</div>
@ -270,6 +314,7 @@
</div>
{include="page.footer"}
<script src="js/thumbnails.min.js?v={$version_hash}"></script>
<script src="{$asset_path}/js/thumbnails.min.js?v={$version_hash}#"></script>
{if="$is_logged_in && $async_metadata"}<script src="{$asset_path}/js/metadata.min.js?v={$version_hash}#"></script>{/if}
</body>
</html>

View File

@ -1,24 +1,29 @@
<div class="linklist-paging">
<div class="paging pure-g">
<div class="linklist-filters pure-u-1-3">
{if="$is_logged_in or !empty($action_plugin)"}
<span class="linklist-filters-text pure-u-0 pure-u-lg-visible">
{'Filters'|t}
</span>
{if="$is_logged_in"}
<a href="?visibility=private" aria-label="{'Only display private links'|t}" title="{'Only display private links'|t}"
class="{if="$visibility==='private'"}filter-on{else}filter-off{/if}"
><i class="fa fa-user-secret" aria-hidden="true"></i></a>
<a href="?visibility=public" aria-label="{'Only display public links'|t}" title="{'Only display public links'|t}"
class="{if="$visibility==='public'"}filter-on{else}filter-off{/if}"
><i class="fa fa-globe" aria-hidden="true"></i></a>
{/if}
<a href="?untaggedonly" aria-label="{'Filter untagged links'|t}" title="{'Filter untagged links'|t}"
class={if="$untaggedonly"}"filter-on"{else}"filter-off"{/if}
><i class="fa fa-tag" aria-hidden="true"></i></a>
<a href="#" class="filter-off fold-all pure-u-lg-0" aria-label="{'Fold all'|t}" title="{'Fold all'|t}">
<i class="fa fa-chevron-up" aria-hidden="true"></i>
</a>
<span class="linklist-filters-text pure-u-0 pure-u-lg-visible">
{'Filters'|t}
</span>
{if="$is_logged_in"}
<a href="{$base_path}/admin/visibility/private" aria-label="{'Only display private links'|t}" title="{'Only display private links'|t}"
class="{if="$visibility==='private'"}filter-on{else}filter-off{/if}"
><i class="fa fa-user-secret" aria-hidden="true"></i></a>
<a href="{$base_path}/admin/visibility/public" aria-label="{'Only display public links'|t}" title="{'Only display public links'|t}"
class="{if="$visibility==='public'"}filter-on{else}filter-off{/if}"
><i class="fa fa-globe" aria-hidden="true"></i></a>
{/if}
<a href="{$base_path}/untagged-only" aria-label="{'Filter untagged links'|t}" title="{'Filter untagged links'|t}"
class={if="$untaggedonly"}"filter-on"{else}"filter-off"{/if}
><i class="fa fa-tag" aria-hidden="true"></i></a>
{if="$is_logged_in"}
<a href="#" aria-label="{'Select all'|t}" title="{'Select all'|t}"
class="filter-off select-all-button pure-u-0 pure-u-lg-visible"
><i class="fa fa-check-square-o" aria-hidden="true"></i></a>
{/if}
<a href="#" class="filter-off fold-all pure-u-lg-0" aria-label="{'Fold all'|t}" title="{'Fold all'|t}">
<i class="fa fa-chevron-up" aria-hidden="true"></i>
</a>
{if="!empty($action_plugin)"}
{loop="$action_plugin"}
{$value.attr.class=isset($value.attr.class) ? $value.attr.class : ''}
{$value.attr.class=!empty($value.on) ? $value.attr.class .' filter-on' : $value.attr.class .' filter-off'}
@ -50,14 +55,19 @@
<div class="linksperpage pure-u-1-3">
<div class="pure-u-0 pure-u-lg-visible">{'Links per page'|t}</div>
<a href="?linksperpage=20">20</a>
<a href="?linksperpage=50">50</a>
<a href="?linksperpage=100">100</a>
<form method="GET" class="pure-u-0 pure-u-lg-visible">
<input type="text" name="linksperpage" placeholder="133">
<a href="{$base_path}/links-per-page?nb=20"
{if="$links_per_page == 20"}class="selected"{/if}>20</a>
<a href="{$base_path}/links-per-page?nb=50"
{if="$links_per_page == 50"}class="selected"{/if}>50</a>
<a href="{$base_path}/links-per-page?nb=100"
{if="$links_per_page == 100"}class="selected"{/if}>100</a>
<form method="GET" class="pure-u-0 pure-u-lg-visible" action="{$base_path}/links-per-page">
<input type="text" name="nb" placeholder="133"
{if="$links_per_page != 20 && $links_per_page != 50 && $links_per_page != 100"}
value="{$links_per_page}"{/if}>
</form>
<a href="#" class="filter-off fold-all pure-u-0 pure-u-lg-visible" aria-label="{'Fold all'|t}" title="{'Fold all'|t}">
<i class="fa fa-chevron-up" aria-hidden="true"></i>
<i class="fa fa-chevron-up" aria-hidden="true"></i>
</a>
</div>
</div>

View File

@ -5,46 +5,33 @@
</head>
<body>
{include="page.header"}
{if="!$user_can_login"}
<div class="pure-g pure-alert pure-alert-error pure-alert-closable center">
<div class="pure-u-2-24"></div>
<div class="pure-u-20-24">
<p>{'You have been banned after too many failed login attempts. Try again later.'|t}</p>
</div>
<div class="pure-u-2-24">
<i class="fa fa-times pure-alert-close"></i>
<div class="pure-g">
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
<div id="login-form" class="page-form page-form-light pure-u-lg-1-3 pure-u-22-24 login-form-container">
<form method="post" name="loginform">
<h2 class="window-title">{'Login'|t}</h2>
<div>
<input type="text" name="login" aria-label="{'Username'|t}" placeholder="{'Username'|t}"
{if="!empty($username)"}value="{$username}"{/if} class="autofocus" autocapitalize="off">
</div>
<div>
<input type="password" name="password" aria-label="{'Password'|t}" placeholder="{'Password'|t}" class="autofocus">
</div>
<div class="remember-me">
<input type="checkbox" name="longlastingsession" id="longlastingsessionform"
{if="$remember_user_default"}checked="checked"{/if}>
<label for="longlastingsessionform">{'Remember me'|t}</label>
</div>
<div>
<input type="submit" value="{'Login'|t}" class="bigbutton">
</div>
<input type="hidden" name="token" value="{$token}">
{if="$returnurl"}<input type="hidden" name="returnurl" value="{$returnurl}">{/if}
</form>
</div>
<div class="pure-u-lg-1-3 pure-u-1-8"></div>
</div>
{else}
<div class="pure-g">
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
<div id="login-form" class="page-form page-form-light pure-u-lg-1-3 pure-u-22-24 login-form-container">
<form method="post" name="loginform">
<h2 class="window-title">{'Login'|t}</h2>
<div>
<input type="text" name="login" aria-label="{'Username'|t}" placeholder="{'Username'|t}"
{if="!empty($username)"}value="{$username}"{/if} class="autofocus">
</div>
<div>
<input type="password" name="password" aria-label="{'Password'|t}" placeholder="{'Password'|t}" class="autofocus">
</div>
<div class="remember-me">
<input type="checkbox" name="longlastingsession" id="longlastingsessionform"
{if="$remember_user_default"}checked="checked"{/if}>
<label for="longlastingsessionform">{'Remember me'|t}</label>
</div>
<div>
<input type="submit" value="{'Login'|t}" class="bigbutton">
</div>
<input type="hidden" name="token" value="{$token}">
{if="$returnurl"}<input type="hidden" name="returnurl" value="{$returnurl}">{/if}
</form>
</div>
<div class="pure-u-lg-1-3 pure-u-1-8"></div>
</div>
{/if}
{include="page.footer"}
</body>
</html>

View File

@ -3,8 +3,8 @@
<ShortName>Shaarli search - {$pagetitle}</ShortName>
<Description>Shaarli search - {$pagetitle}</Description>
<Url type="text/html" template="{$serverurl}?searchterm={searchTerms}" />
<Url type="application/atom+xml" template="{$serverurl}?do=atom&amp;searchterm={searchTerms}"/>
<Url type="application/rss+xml" template="{$serverurl}?do=rss&amp;searchterm={searchTerms}"/>
<Url type="application/atom+xml" template="{$serverurl}feed/atom?searchterm={searchTerms}"/>
<Url type="application/rss+xml" template="{$serverurl}feed/rss?searchterm={searchTerms}"/>
<InputEncoding>UTF-8</InputEncoding>
<Developer>Shaarli Community - https://github.com/shaarli/Shaarli/</Developer>
<Image width="16" height="16">data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAHRklE

View File

@ -1,42 +1,46 @@
</div>
</main>
<div class="pure-g">
<div class="pure-u-2-24"></div>
<footer id="footer" class="pure-u-20-24 footer-container" role="contentinfo">
<i class="fa fa-shaarli" aria-hidden="true"></i>
<i class="fa fa-shaarli" aria-hidden="true"></i>
<strong><a href="https://github.com/shaarli/Shaarli">Shaarli</a></strong>
{if="$is_logged_in===true"}
{$version}
{/if}
&middot;
{'The personal, minimalist, super-fast, database free, bookmarking service'|t} {'by the Shaarli community'|t} &middot;
<a href="doc/html/index.html" rel="nofollow">{'Documentation'|t}</a>
<a href="{$root_path}/doc/html/index.html" rel="nofollow">{'Documentation'|t}</a>
<br>Theme <a href="https://forge.leslibres.org/Knah-Tsaeb/MyShaarli">MyShaarli </a>by Knah Tsaeb
{loop="$plugins_footer.text"}
{$value}
{/loop}
</footer>
</footer>
<div class="pure-u-2-24"></div>
</div>
<input type="hidden" name="token" value="{$token}" id="token" />
{loop="$plugins_footer.endofpage"}
{$value}
{/loop}
{loop="$plugins_footer.js_files"}
<script src="{$value}#"></script>
<script src="{$root_path}/{$value}#"></script>
{/loop}
<div id="js-translations" class="hidden">
<div id="js-translations" class="hidden" aria-hidden="true">
<span id="translation-fold">{'Fold'|t}</span>
<span id="translation-fold-all">{'Fold all'|t}</span>
<span id="translation-expand">{'Expand'|t}</span>
<span id="translation-expand-all">{'Expand all'|t}</span>
<span id="translation-delete-link">{'Are you sure you want to delete this link?'|t}</span>
<span id="translation-delete-tag">{'Are you sure you want to delete this tag?'|t}</span>
<span id="translation-shaarli-desc">
{'The personal, minimalist, super-fast, database free, bookmarking service'|t} {'by the Shaarli community'|t}
</span>
</div>
<script src="js/shaarli.min.js?v={$version_hash}"></script>
<input type="hidden" name="js_base_path" value="{$base_path}" />
<input type="hidden" name="token" value="{$token}" id="token" />
<input type="hidden" name="tags_separator" value="{$tags_separator}" id="tags_separator" />
<script src="{$asset_path}/js/shaarli.min.js?v={$version_hash}#"></script>

View File

@ -1,45 +1,45 @@
<div class="shaarli-menu pure-g" id="shaarli-menu">
<div class="pure-u-lg-0 pure-u-1">
<div class="pure-menu">
<header role="banner">
<a href="{$titleLink}" class="pure-menu-link shaarli-title" id="shaarli-title-mobile">
<img src="img/favicon_32.png" width="16" height="16" class="head-logo" alt="logo" />
<header role="banner">
<a href="{$titleLink}" class="pure-menu-link shaarli-title" id="shaarli-title-mobile">
<img src="{$asset_path}/img/favicon_16.png#" width="16" height="16" class="head-logo" alt="logo" />
{$shaarlititle}
</a>
</header>
<a href="#" class="menu-toggle" id="menu-toggle" aria-label="Menu"><s class="bar" aria-hidden="true"></s><s class="bar" aria-hidden="true"></s></a>
</header>
<a href="#" class="menu-toggle" id="menu-toggle" aria-label="{'Menu'|t}"><s class="bar" aria-hidden="true"></s><s class="bar" aria-hidden="true"></s></a>
</div>
</div>
<div class="pure-u-1">
<div class="pure-menu menu-transform pure-menu-horizontal pure-g">
<ul class="pure-menu-list pure-u-lg-5-6 pure-u-1">
<li class="pure-menu-item">
<img src="img/logo_myShaarli.png" class="head-logo" alt="logo" width="120px" height="45px"/>
</li>
<li><img src="{$asset_path}/img/logo_myShaarli.png#" class="head-logo" alt="logo" width="120px" height="45px"/></li>
<li class="pure-menu-item pure-u-0 pure-u-lg-visible">
<a href="{$titleLink}" class="pure-menu-link shaarli-title" id="shaarli-title-desktop">
<img src="img/favicon_32.png" width="18" height="18" class="head-logo" alt="" />
<img src="{$asset_path}/img/favicon_16.png#" width="16" height="16" class="head-logo" alt="logo" />
{$shaarlititle}
</a>
</li>
{if="$is_logged_in || $openshaarli"}
<li class="pure-menu-item">
<a href="?do=addlink" class="pure-menu-link" id="shaarli-menu-shaare">
<a href="{$base_path}/admin/add-shaare" class="pure-menu-link" id="shaarli-menu-shaare">
<i class="fa fa-plus" aria-hidden="true"></i> {'Shaare'|t}
</a>
</li>
<li class="pure-menu-item" id="shaarli-menu-tools">
<a href="?do=tools" class="pure-menu-link">{'Tools'|t}</a>
<a href="{$base_path}/admin/tools" class="pure-menu-link">{'Tools'|t}</a>
</li>
{/if}
<li class="pure-menu-item" id="shaarli-menu-tags">
<a href="?do=tagcloud" class="pure-menu-link">{'Tag cloud'|t}</a>
<a href="{$base_path}/tags/cloud" class="pure-menu-link">{'Tag cloud'|t}</a>
</li>
{if="$thumbnails_enabled"}
<li class="pure-menu-item" id="shaarli-menu-picwall">
<a href="?do=picwall{$searchcrits}" class="pure-menu-link">{'Picture wall'|t}</a>
<a href="{$base_path}/picture-wall?{function="ltrim($searchcrits, '&')"}" class="pure-menu-link">{'Picture wall'|t}</a>
</li>
{/if}
<li class="pure-menu-item" id="shaarli-menu-daily">
<a href="?do=daily" class="pure-menu-link">{'Daily'|t}</a>
<a href="{$base_path}/daily" class="pure-menu-link">{'Daily'|t}</a>
</li>
{loop="$plugins_header.buttons_toolbar"}
<li class="pure-menu-item shaarli-menu-plugin">
@ -53,15 +53,15 @@
</li>
{/loop}
<li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-rss">
<a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link">{'RSS Feed'|t}</a>
<a href="{$base_path}/feed/{$feed_type}?{$searchcrits}" class="pure-menu-link">{'RSS Feed'|t}</a>
</li>
{if="$is_logged_in"}
<li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-logout">
<a href="?do=logout" class="pure-menu-link">{'Logout'|t}</a>
<a href="{$base_path}/admin/logout" class="pure-menu-link">{'Logout'|t}</a>
</li>
{else}
<li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-login">
<a href="?do=login" class="pure-menu-link">{'Login'|t}</a>
<a href="{$base_path}/login" class="pure-menu-link">{'Login'|t}</a>
</li>
{/if}
</ul>
@ -75,13 +75,13 @@
</a>
</li>
<li class="pure-menu-item" id="shaarli-menu-desktop-rss">
<a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link" title="{'RSS Feed'|t}" aria-label="{'RSS Feed'|t}">
<i class="fa fa-rss" aria-hidden="true"></i>
<a href="{$base_path}/feed/{$feed_type}?{$searchcrits}" class="pure-menu-link" title="{'RSS Feed'|t}" aria-label="{'RSS Feed'|t}">
<i class="fa fa-rss" aria-hidden="true"></i>
</a>
</li>
{if="!$is_logged_in"}
<li class="pure-menu-item" id="shaarli-menu-desktop-login">
<a href="?do=login" class="pure-menu-link"
<a href="{$base_path}/login" class="pure-menu-link"
data-open-id="header-login-form"
id="login-button" aria-label="{'Login'|t}" title="{'Login'|t}">
<i class="fa fa-user" aria-hidden="true"></i>
@ -89,8 +89,8 @@
</li>
{else}
<li class="pure-menu-item" id="shaarli-menu-desktop-logout">
<a href="?do=logout" class="pure-menu-link" aria-label="{'Logout'|t}" title="{'Logout'|t}">
<i class="fa fa-sign-out" aria-hidden="true"></i>
<a href="{$base_path}/admin/logout" class="pure-menu-link" aria-label="{'Logout'|t}" title="{'Logout'|t}">
<i class="fa fa-sign-out" aria-hidden="true"></i>
</a>
</li>
{/if}
@ -100,43 +100,90 @@
</div>
</div>
<div id="content" class="container">
<main id="content" class="container" role="main">
<div id="search" class="subheader-form searchform-block header-search">
<form method="GET" class="pure-form searchform" name="searchform">
<input type="text" tabindex="1" id="searchform_value" name="searchterm" placeholder="{'Search text'|t}"
<form method="GET" class="pure-form searchform" name="searchform" action="{$base_path}/">
<input type="text" id="searchform_value" name="searchterm" aria-label="{'Search text'|t}" placeholder="{'Search text'|t}"
{if="!empty($search_term)"}
value="{$search_term}"
{/if}
>
<input type="text" tabindex="2" name="searchtags" id="tagfilter_value" placeholder="{'Filter by tag'|t}"
<input type="text" name="searchtags" id="tagfilter_value" aria-label="{'Filter by tag'|t}" placeholder="{'Filter by tag'|t}"
{if="!empty($search_tags)"}
value="{$search_tags}"
{/if}
autocomplete="off" data-multiple data-autofirst data-minChars="1"
data-list="{loop="$tags"}{$key}, {/loop}"
>
<button type="submit" class="search-button"><i class="fa fa-search"></i></button>
<button type="submit" class="search-button" aria-label="{'Search'|t}"><i class="fa fa-search" aria-hidden="true"></i></button>
</form>
</div>
<div id="actions" class="subheader-form">
<div class="pure-g">
<div class="pure-u-1">
<a href="" id="actions-delete" class="button">Delete</a>
<a href="" id="actions-delete" class="button">
<i class="fa fa-trash" aria-hidden="true"></i>
{'Delete'|t}
</a>&nbsp;
<a href="" class="actions-change-visibility button" data-visibility="public">
<i class="fa fa-globe" aria-hidden="true"></i>
{'Set public'|t}
</a>&nbsp;
<a href="" class="actions-change-visibility button" data-visibility="private">
<i class="fa fa-user-secret" aria-hidden="true"></i>
{'Set private'|t}
</a>&nbsp;
<a href="" class="subheader-opener button" data-open-id="bulk-tag-action-add">
<i class="fa fa-tag" aria-hidden="true"></i>
{'Add tags'|t}
</a>&nbsp;
<a href="" class="subheader-opener button" data-open-id="bulk-tag-action-delete">
<i class="fa fa-window-close" aria-hidden="true"></i>
{'Delete tags'|t}
</a>
</div>
</div>
</div>
{$addDelete=['add', 'delete']}
{loop="$addDelete"}
<div id="bulk-tag-action-{$value}" class="subheader-form">
<form class="pure-g" action="{$base_path}/admin/shaare/update-tags" method="post">
<div class="pure-u-1">
<span>
<input
type="text" name="tag" class="autofocus"
aria-label="{$value === 'add' ? t('Tag to add') : t('Tag to delete')}"
placeholder="{$value === 'add' ? t('Tag to add') : t('Tag to delete')}"
autocomplete="off" data-multiple data-autofirst data-minChars="1"
data-list="{loop="$tags"}{$key}, {/loop}"
>
<input type="hidden" name="action" value="{$value}" />
<input type="hidden" name="id" value="" />
<input type="hidden" name="token" value="{$token}" />
</span>&nbsp;
<a href="" class="button action">
<i class="fa fa-tag" aria-hidden="true"></i>
{$value === 'add' ? t('Add tag') : t('Delete tag')}
</a>&nbsp;
<a href="" class="subheader-opener button cancel" data-open-id="actions">{'Cancel'|t}</a>
</div>
</form>
</div>
{/loop}
{if="!$is_logged_in"}
<form method="post" name="loginform">
<div class="subheader-form header-login-form" id="header-login-form">
<input type="text" name="login" placeholder="{'Username'|t}" tabindex="3">
<input type="password" name="password" placeholder="{'Password'|t}" tabindex="5">
<input type="text" name="login" aria-label="{'Username'|t}" placeholder="{'Username'|t}" autocapitalize="off" >
<input type="password" name="password" aria-label="{'Password'|t}" placeholder="{'Password'|t}" >
<div class="remember-me">
<input type="checkbox" name="longlastingsession" id="longlastingsession" tabindex="6" checked>
<input type="checkbox" name="longlastingsession" id="longlastingsession" checked>
<label for="longlastingsession">{'Remember me'|t}</label>
</div>
<input type="hidden" name="token" value="{$token}">
<input type="hidden" name="returnurl">
<input type="submit" value="Login" tabindex="7">
<input type="submit" value="Login">
</div>
</form>
{/if}
@ -174,8 +221,22 @@
</div>
{/if}
{if="!empty($global_warnings) && $is_logged_in"}
<div class="pure-g pure-alert pure-alert-warning pure-alert-closable" id="shaarli-warnings-alert">
{if="!empty($global_errors)"}
<div class="pure-g header-alert-message pure-alert pure-alert-error pure-alert-closable" id="shaarli-errors-alert">
<div class="pure-u-2-24"></div>
<div class="pure-u-20-24">
{loop="$global_errors"}
<p>{$value}</p>
{/loop}
</div>
<div class="pure-u-2-24">
<i class="fa fa-times pure-alert-close"></i>
</div>
</div>
{/if}
{if="!empty($global_warnings)"}
<div class="pure-g header-alert-message pure-alert pure-alert-warning pure-alert-closable" id="shaarli-warnings-alert">
<div class="pure-u-2-24"></div>
<div class="pure-u-20-24">
{loop="global_warnings"}
@ -188,4 +249,18 @@
</div>
{/if}
{if="!empty($global_successes)"}
<div class="pure-g header-alert-message new-version-message pure-alert pure-alert-success pure-alert-closable" id="shaarli-success-alert">
<div class="pure-u-2-24"></div>
<div class="pure-u-20-24">
{loop="$global_successes"}
<p>{$value}</p>
{/loop}
</div>
<div class="pure-u-2-24">
<i class="fa fa-times pure-alert-close"></i>
</div>
</div>
{/if}
<div class="clear"></div>

View File

@ -6,47 +6,54 @@
<body>
{include="page.header"}
<div class="pure-g myShaarli_picwall">
<div class="pure-u-lg-1-6 pure-u-1-24"></div>
<div class="pure-u-lg-2-3 pure-u-22-24 page-form page-visitor">
{$countPics=count($linksToDisplay)}
<h2 class="window-title">{'Picture Wall'|t} - {$countPics} {'pics'|t}</h2>
<div id="plugin_zone_start_picwall" class="plugin_zone">
{loop="$plugin_start_zone"}
{$value}
{/loop}
</div>
<div id="picwall-container" class="picwall-container">
{loop="$linksToDisplay"}
<div class="picwall-pictureframe">
{ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore}
<img data-src="{$value.thumbnail}#" class="b-lazy"
src=""
alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" />
<a href="{$value.real_url}"><span class="info">{$value.title}</span></a>
{loop="$value.picwall_plugin"}
{$value}
{/loop}
</div>
{/loop}
<div class="clear"></div>
</div>
<div id="plugin_zone_end_picwall" class="plugin_zone">
{loop="$plugin_end_zone"}
{$value}
{/loop}
</div>
{if="count($linksToDisplay)===0 && $is_logged_in"}
<div class="pure-g pure-alert pure-alert-warning page-single-alert">
<div class="pure-u-1 center">
{'There is no cached thumbnail.'|t}
<a href="{$base_path}/admin/thumbnails">{'Try to synchronize them.'|t}</a>
</div>
<div class="pure-u-lg-1-6 pure-u-1-24"></div>
</div>
{/if}
<div class="pure-g">
<div class="pure-u-lg-1-6 pure-u-1-24"></div>
<div class="pure-u-lg-2-3 pure-u-22-24 page-form page-visitor">
{$countPics=count($linksToDisplay)}
<h2 class="window-title">{'Picture Wall'|t} - {$countPics} {'pics'|t}</h2>
<div id="plugin_zone_start_picwall" class="plugin_zone">
{loop="$plugin_start_zone"}
{$value}
{/loop}
</div>
<div id="picwall-container" class="picwall-container" role="list">
{loop="$linksToDisplay"}
<div class="picwall-pictureframe" role="listitem">
{ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore}
<img data-src="{$root_path}/{$value.thumbnail}#" class="b-lazy"
src=""
alt="" width="{$thumbnails_width}" height="{$thumbnails_height}" />
<a href="{$value.real_url}"><span class="info">{$value.title}</span></a>
{loop="$value.picwall_plugin"}
{$value}
{/loop}
</div>
{/loop}
<div class="clear"></div>
</div>
<div id="plugin_zone_end_picwall" class="plugin_zone">
{loop="$plugin_end_zone"}
{$value}
{/loop}
</div>
</div>
<div class="pure-u-lg-1-6 pure-u-1-24"></div>
</div>
{include="page.footer"}
<script src="js/thumbnails.min.js?v={$version_hash}"></script>
<script src="{$asset_path}/js/thumbnails.min.js?v={$version_hash}#"></script>
</body>
</html>

View File

@ -10,13 +10,13 @@
<div class="pure-g new-version-message pure-alert pure-alert-warning">
<div class="pure-u-2-24"></div>
<div class="pure-u-20-24">
{'You need to enable Javascript to change plugin loading order.'|t}
{'You have to enable JavaScript to change plugin loading order.'|t}
</div>
</div>
<div class="clear"></div>
</noscript>
<form method="POST" action="?do=save_pluginadmin" name="pluginform" id="pluginform" class="pluginform-container">
<form method="POST" action="{$base_path}/admin/plugins" name="pluginform" id="pluginform" class="pluginform-container">
<div class="pure-g">
<div class="pure-u-lg-1-8 pure-u-1-24"></div>
<div class="pure-u-lg-3-4 pure-u-22-24 page-form page-form-complete">
@ -32,7 +32,7 @@
<table id="plugin_table">
<thead>
<tr>
<th class="center">{'Disable'|t}</th>
<th class="center">{'Enabled'|t}</th>
<th>{'Name'|t}</th>
<th><div class="pure-u-0 pure-u-lg-visible">{'Description'|t}</div></th>
<th class="center">{'Order'|t}</th>
@ -61,7 +61,7 @@
</tbody>
<tfoot>
<tr>
<th class="center">{'Disable'|t}</th>
<th class="center">{'Enabled'|t}</th>
<th>{'Name'|t}</th>
<th><div class="pure-u-0 pure-u-lg-visible">{'Description'|t}</div></th>
<th class="center">{'Order'|t}</th>
@ -82,7 +82,7 @@
<table>
<thead>
<tr>
<th class="center">{'Enable'|t}</th>
<th class="center">{'Enabled'|t}</th>
<th>{'Name'|t}</th>
<th><div class="pure-u-0 pure-u-lg-visible">{'Description'|t}</div></th>
</tr>
@ -105,7 +105,7 @@
</tbody>
<tfoot>
<tr>
<th class="center">{'Enable'|t}</th>
<th class="center">{'Enabled'|t}</th>
<th>{'Name'|t}</th>
<th><div class="pure-u-0 pure-u-lg-visible">{'Description'|t}</div></th>
</tr>
@ -117,7 +117,7 @@
<div class="center more">
{"More plugins available"|t}
<a href="doc/html/Community-&-Related-software/#third-party-plugins">{"in the documentation"|t}</a>.
<a href="{$root_path}/doc/html/Community-&-Related-software/#third-party-plugins">{"in the documentation"|t}</a>.
</div>
<div class="center">
<input type="submit" value="{'Save'|t}" name="save">
@ -127,7 +127,7 @@
<input type="hidden" name="token" value="{$token}">
</form>
<form action="?do=save_pluginadmin" method="POST">
<form action="{$base_path}/admin/plugins" method="POST">
<div class="pure-g">
<div class="pure-u-lg-1-8 pure-u-1-24"></div>
<div class="pure-u-lg-3-4 pure-u-22-24 page-form page-form-light">
@ -173,10 +173,11 @@
</section>
</div>
</div>
<input type="hidden" name="token" value="{$token}">
</form>
{include="page.footer"}
<script src="js/pluginsadmin.min.js?v={$version_hash}"></script>
<script src="{$asset_path}/js/pluginsadmin.min.js?v={$version_hash}#"></script>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
<head>
{include="includes"}
</head>
<body>
{include="page.header"}
{$content}
{include="page.footer"}
</body>
</html>

129
tpl/myShaarli/server.html Normal file
View File

@ -0,0 +1,129 @@
<!DOCTYPE html>
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
<head>
{include="includes"}
</head>
<body>
{include="page.header"}
<div class="pure-g">
<div class="pure-u-lg-1-4 pure-u-1-24"></div>
<div class="pure-u-lg-1-2 pure-u-22-24 page-form server-tables-page">
<h2 class="window-title">{'Server administration'|t}</h2>
<h3 class="window-subtitle">{'General'|t}</h3>
<div class="pure-g server-row">
<div class="pure-u-lg-1-2 pure-u-1 server-label">
<p>{'Index URL'|t}</p>
</div>
<div class="pure-u-lg-1-2 pure-u-1">
<p><a href="{$index_url}" title="{$pagetitle}">{$index_url}</a></p>
</div>
</div>
<div class="pure-g server-row">
<div class="pure-u-lg-1-2 pure-u-1 server-label">
<p>{'Base path'|t}</p>
</div>
<div class="pure-u-lg-1-2 pure-u-1">
<p>{$base_path}</p>
</div>
</div>
<div class="pure-g server-row">
<div class="pure-u-lg-1-2 pure-u-1 server-label">
<p>{'Client IP'|t}</p>
</div>
<div class="pure-u-lg-1-2 pure-u-1">
<p>{$client_ip}</p>
</div>
</div>
<div class="pure-g server-row">
<div class="pure-u-lg-1-2 pure-u-1 server-label">
<p>{'Trusted reverse proxies'|t}</p>
</div>
<div class="pure-u-lg-1-2 pure-u-1">
{if="count($trusted_proxies) > 0"}
<p>
{loop="$trusted_proxies"}
{$value}<br>
{/loop}
</p>
{else}
<p>{'N/A'|t}</p>
{/if}
</div>
</div>
{include="server.requirements"}
<h3 class="window-subtitle">{'Version'|t}</h3>
<div class="pure-g server-row">
<div class="pure-u-lg-1-2 pure-u-1 server-label">
<p>{'Current version'|t}</p>
</div>
<div class="pure-u-lg-1-2 pure-u-1">
<p>{$current_version}</p>
</div>
</div>
<div class="pure-g server-row">
<div class="pure-u-lg-1-2 pure-u-1 server-label">
<p>{'Latest release'|t}</p>
</div>
<div class="pure-u-lg-1-2 pure-u-1">
<p>
<a href="{$release_url}" title="{'Visit releases page on Github'|t}">
{$latest_version}
</a>
</p>
</div>
</div>
<h3 class="window-subtitle">{'Thumbnails'|t}</h3>
<div class="pure-g server-row">
<div class="pure-u-lg-1-2 pure-u-1 server-label">
<p>{'Thumbnails status'|t}</p>
</div>
<div class="pure-u-lg-1-2 pure-u-1">
<p>
{if="$thumbnails_mode==='all'"}
{'All'|t}
{elseif="$thumbnails_mode==='common'"}
{'Only common media hosts'|t}
{else}
{'None'|t}
{/if}
</p>
</div>
</div>
{if="$thumbnails_mode!=='none'"}
<div class="center tools-item">
<a href="{$base_path}/admin/thumbnails" title="{'Synchronize all link thumbnails'|t}">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Synchronize thumbnails'|t}</span>
</a>
</div>
{/if}
<h3 class="window-subtitle">{'Cache'|t}</h3>
<div class="center tools-item">
<a href="{$base_path}/admin/clear-cache?type=main">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Clear main cache'|t}</span>
</a>
</div>
<div class="center tools-item">
<a href="{$base_path}/admin/clear-cache?type=thumbnails">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Clear thumbnails cache'|t}</span>
</a>
</div>
</div>
</div>
{include="page.footer"}
</body>
</html>

View File

@ -0,0 +1,68 @@
<div class="server-tables">
<h3 class="window-subtitle">{'Permissions'|t}</h3>
{if="count($permissions) > 0"}
<p class="center">
<i class="fa fa-close fa-color-red" aria-hidden="true"></i>
{'There are permissions that need to be fixed.'|t}
</p>
<p>
{loop="$permissions"}
<div class="center">{$value}</div>
{/loop}
</p>
{else}
<p class="center">
<i class="fa fa-check fa-color-green" aria-hidden="true"></i>
{'All read/write permissions are properly set.'|t}
</p>
{/if}
<h3 class="window-subtitle">PHP</h3>
<p class="center">
<strong>{'Running PHP'|t} {$php_version}</strong>
{if="$php_has_reached_eol"}
<i class="fa fa-circle fa-color-orange" aria-label="hidden"></i><br>
{'End of life: '|t} {$php_eol}
{else}
<i class="fa fa-circle fa-color-green" aria-label="hidden"></i><br>
{/if}
</p>
<table class="center">
<thead>
<tr>
<th>{'Extension'|t}</th>
<th>{'Usage'|t}</th>
<th>{'Status'|t}</th>
<th>{'Loaded'|t}</th>
</tr>
</thead>
<tbody>
{loop="$php_extensions"}
<tr>
<td>{$value.name}</td>
<td>{$value.desc}</td>
<td>{$value.required ? t('Required') : t('Optional')}</td>
<td>
{if="$value.loaded"}
{$classLoaded="fa-color-green"}
{$strLoaded=t('Loaded')}
{else}
{$strLoaded=t('Not loaded')}
{if="$value.required"}
{$classLoaded="fa-color-red"}
{else}
{$classLoaded="fa-color-orange"}
{/if}
{/if}
<i class="fa fa-circle {$classLoaded}" aria-label="{$strLoaded}" title="{$strLoaded}"></i>
</td>
</tr>
{/loop}
</tbody>
</table>
</div>

View File

@ -15,7 +15,7 @@
<h2 class="window-title">{'Tag cloud'|t} - {$countTags} {'tags'|t}</h2>
{if="!empty($search_tags)"}
<p class="center">
<a href="?searchtags={$search_tags|urlencode}" class="pure-button pure-button-shaarli">
<a href="{$base_path}/?searchtags={$search_tags_url}" class="pure-button pure-button-shaarli">
{'List all links with those tags'|t}
</a>
</p>
@ -26,14 +26,15 @@
<div class="pure-u-1 pure-u-lg-1-2">
<form method="GET">
<input type="hidden" name="do" value="tagcloud">
<input type="text" name="searchtags" placeholder="{'Filter by tag'|t}"
<input type="text" name="searchtags" aria-label="{'Filter by tag'|t}" placeholder="{'Filter by tag'|t}"
{if="!empty($search_tags)"}
value="{$search_tags}"
{/if}
autocomplete="off" data-multiple data-autofirst data-minChars="1"
data-list="{loop="$tags"}{$key}, {/loop}"
class="autofocus"
>
<button type="submit" class="search-button"><i class="fa fa-search"></i></button>
<button type="submit" class="search-button" aria-label="{'Search'|t}"><i class="fa fa-search" aria-hidden="true"></i></button>
</form>
</div>
<div class="pure-u-lg-1-4"></div>
@ -47,8 +48,8 @@
<div id="cloudtag" class="cloudtag-container">
{loop="tags"}
<a href="?searchtags={$key|urlencode} {$search_tags|urlencode}" style="font-size:{$value.size}em;">{$key}</a
><a href="?addtag={$key|urlencode}" title="{'Filter by tag'|t}" class="count">{$value.count}</a>
<a href="{$base_path}/?searchtags={$tags_url.$key1}{$tags_separator|urlencode}{$search_tags_url}" style="font-size:{$value.size}em;">{$key}</a
><a href="{$base_path}/add-tag/{$tags_url.$key1}" title="{'Filter by tag'|t}" class="count">{$value.count}</a>
{loop="$value.tag_plugin"}
{$value}
{/loop}

View File

@ -15,7 +15,7 @@
<h2 class="window-title">{'Tag list'|t} - {$countTags} {'tags'|t}</h2>
{if="!empty($search_tags)"}
<p class="center">
<a href="?searchtags={$search_tags|urlencode}" class="pure-button pure-button-shaarli">
<a href="{$base_path}/?searchtags={$search_tags_url}" class="pure-button pure-button-shaarli">
{'List all links with those tags'|t}
</a>
</p>
@ -26,14 +26,14 @@
<div class="pure-u-1 pure-u-lg-1-2">
<form method="GET">
<input type="hidden" name="do" value="taglist">
<input type="text" name="searchtags" placeholder="{'Filter by tag'|t}"
<input type="text" name="searchtags" aria-label="{'Filter by tag'|t}" placeholder="{'Filter by tag'|t}"
{if="!empty($search_tags)"}
value="{$search_tags}"
{/if}
autocomplete="off" data-multiple data-autofirst data-minChars="1"
data-list="{loop="$tags"}{$key}, {/loop}"
>
<button type="submit" class="search-button"><i class="fa fa-search"></i></button>
<button type="submit" class="search-button" aria-label="{'Search'|t}"><i class="fa fa-search" aria-hidden="true"></i></button>
</form>
</div>
<div class="pure-u-lg-1-4"></div>
@ -47,17 +47,17 @@
<div id="taglist" class="taglist-container">
{loop="tags"}
<div class="tag-list-item pure-g" data-tag="{$key}">
<div class="tag-list-item pure-g" data-tag="{$key}" data-tag-url="{$tags_url.$key1}">
<div class="pure-u-1">
{if="$is_logged_in===true"}
<a href="#" class="delete-tag"><i class="fa fa-trash"></i></a>&nbsp;&nbsp;
<a href="?do=changetag&fromtag={$key|urlencode}" class="rename-tag">
<i class="fa fa-pencil-square-o {$key}"></i>
<a href="#" class="delete-tag" aria-label="{'Delete'|t}"><i class="fa fa-trash" aria-hidden="true"></i></a>&nbsp;&nbsp;
<a href="{$base_path}/admin/tags?fromtag={$tags_url.$key1}" class="rename-tag" aria-label="{'Rename tag'|t}">
<i class="fa fa-pencil-square-o {$key}" aria-hidden="true"></i>
</a>
{/if}
<a href="?addtag={$key|urlencode}" title="{'Filter by tag'|t}" class="count">{$value}</a>
<a href="?searchtags={$key|urlencode} {$search_tags|urlencode}" class="tag-link">{$key}</a>
<a href="{$base_path}/add-tag/{$tags_url.$key1}" title="{'Filter by tag'|t}" class="count">{$value}</a>
<a href="{$base_path}/?searchtags={$tags_url.$key1} {$search_tags_url}" class="tag-link">{$key}</a>
{loop="$value.tag_plugin"}
{$value}
@ -66,7 +66,7 @@
{if="$is_logged_in===true"}
<div class="rename-tag-form pure-u-1">
<input type="text" name="{$key}" value="{$key}" class="rename-tag-input" />
<a href="#" class="validate-rename-tag"><i class="fa fa-check"></i></a>
<a href="#" class="validate-rename-tag"><i class="fa fa-check" aria-hidden="true"></i></a>
</div>
{/if}
</div>

View File

@ -1,8 +1,8 @@
<div class="pure-g">
<div class="pure-u-1 pure-alert pure-alert-success tag-sort">
{'Sort by:'|t}
<a href="?do=tagcloud">{'Cloud'|t}</a> &middot;
<a href="?do=taglist&sort=usage">{'Most used'|t}</a> &middot;
<a href="?do=taglist&sort=alpha">{'Alphabetical'|t}</a>
<a href="{$base_path}/tags/cloud">{'Cloud'|t}</a>
<a href="{$base_path}/tags/list?sort=usage">{'Most used'|t}</a>
<a href="{$base_path}/tags/list?sort=alpha">{'Alphabetical'|t}</a>
</div>
</div>
</div>

View File

@ -38,11 +38,11 @@
</div>
</div>
<input type="hidden" name="ids" value="{function="implode($ids, ',')"}" />
<input type="hidden" name="ids" value="{function="implode(',', $ids)"}" />
</div>
</div>
{include="page.footer"}
<script src="js/thumbnails_update.min.js?v={$version_hash}"></script>
<script src="{$asset_path}/js/thumbnails_update.min.js?v={$version_hash}#"></script>
</body>
</html>

View File

@ -11,48 +11,46 @@
<div class="pure-u-lg-1-3 pure-u-22-24 page-form page-form-light">
<h2 class="window-title">{'Settings'|t}</h2>
<div class="tools-item">
<a href="?do=configure" title="{'Change Shaarli settings: title, timezone, etc.'|t}">
<a href="{$base_path}/admin/configure" title="{'Change Shaarli settings: title, timezone, etc.'|t}">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Configure your Shaarli'|t}</span>
</a>
</div>
<div class="tools-item">
<a href="?do=pluginadmin" title="{'Enable, disable and configure plugins'|t}">
<a href="{$base_path}/admin/plugins" title="{'Enable, disable and configure plugins'|t}">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Plugin administration'|t}</span>
</a>
</div>
<div class="tools-item">
<a href="{$base_path}/admin/server"
title="{'Check instance\'s server configuration'|t}">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Server administration'|t}</span>
</a>
</div>
{if="!$openshaarli"}
<div class="tools-item">
<a href="?do=changepasswd" title="{'Change your password'|t}">
<a href="{$base_path}/admin/password" title="{'Change your password'|t}">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Change password'|t}</span>
</a>
</div>
{/if}
<div class="tools-item">
<a href="?do=changetag" title="{'Rename or delete a tag in all links'|t}">
<a href="{$base_path}/admin/tags" title="{'Rename or delete a tag in all links'|t}">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Manage tags'|t}</span>
</a>
</div>
<div class="tools-item">
<a href="?do=import"
<a href="{$base_path}/admin/import"
title="{'Import Netscape HTML bookmarks (as exported from Firefox, Chrome, Opera, delicious...)'|t}">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Import links'|t}</span>
</a>
</div>
<div class="tools-item">
<a href="?do=export"
<a href="{$base_path}/admin/export"
title="{'Export Netscape HTML bookmarks (which can be imported in Firefox, Chrome, Opera, delicious...)'|t}">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Export database'|t}</span>
</a>
</div>
{if="$thumbnails_enabled"}
<div class="tools-item">
<a href="?do=thumbs_update" title="{'Synchronize all link thumbnails'|t}">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Synchronize thumbnails'|t}</span>
</a>
</div>
{/if}
{loop="$tools_plugin"}
<div class="tools-item">
{$value}
@ -67,7 +65,7 @@
<div class="pure-g">
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
<div class="pure-u-lg-1-3 pure-u-22-24 page-form page-form-light">
<h2 class="window-title">Bookmarklets</h2>
<h2 class="window-title">{'Bookmarklets'|t}</h2>
<p>
{'Drag one of these button to your bookmarks toolbar or right-click it and "Bookmark This Link"'|t},
{'then click on the bookmarklet in any page you want to share.'|t}
@ -86,7 +84,7 @@
alert('{function="str_replace(' ', '%20', t('The selected text is too long, it will be truncated.'))"}');
}
window.open(
'{$pageabsaddr}?post='%20+%20encodeURIComponent(url)+
'{$pageabsaddr}admin/shaare?post='%20+%20encodeURIComponent(url)+
'&amp;title='%20+%20encodeURIComponent(title)+
'&amp;description='%20+%20encodeURIComponent(desc)+
'&amp;source=bookmarklet','_blank','menubar=no,height=800,width=600,toolbar=no,scrollbars=yes,status=no,dialog=1'
@ -108,7 +106,7 @@
alert('{function="str_replace(' ', '%20', t('The selected text is too long, it will be truncated.'))"}');
}
window.open(
'{$pageabsaddr}?private=1&amp;post='+
'{$pageabsaddr}admin/shaare?private=1&amp;post='+
'&amp;description='%20+%20encodeURIComponent(desc)+
'&amp;source=bookmarklet','_blank','menubar=no,height=800,width=600,toolbar=no,scrollbars=yes,status=no,dialog=1'
);
@ -123,31 +121,10 @@
<div class="pure-g">
<div class="pure-u-lg-1-3 pure-u-1-24"></div>
<div class="pure-u-lg-1-3 pure-u-22-24 page-form page-form-light">
<h2 class="window-title">{'3rd party'|t}</h2>
<h2 class="window-title">{'Third-party resources'|t}</h2>
<div class="tools-item">
<a href="https://addons.mozilla.org/fr/firefox/addon/shaarli/">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">Firefox {'plugin'|t}</span>
</a>
</div>
<div class="tools-item">
<a href="https://chrome.google.com/webstore/detail/shiny-shaarli/hajdfkmbdmadjmmpkkbbcnllepomekin">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">Chrome {'plugin'|t}</span>
</a>
</div>
<div class="tools-item">
<a href="https://play.google.com/store/apps/details?id=com.dimtion.shaarlier&hl=fr">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">Android Shaarlier</span>
</a>
</div>
<div class="tools-item">
<a href="https://stakali.toneiv.eu/">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">Android Stakali</span>
</a>
</div>
<div class="tools-item">
<a href="https://itunes.apple.com/app/ShaarliOS/id1027441388?mt=8"
title="iOS">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">iOS</span>
<a href="https://shaarli.readthedocs.io/en/master/Community-and-related-software/">
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Community and related software'|t}</span>
</a>
</div>
</div>