Release v0.10.3
-----BEGIN PGP SIGNATURE----- iQFLBAABCAA1FiEEEv0k8DWUT53dSMUkR6bSrUEA328FAlxxaB0XHHZpcnR1YWx0 YW1AZmxpYmlkaS5uZXQACgkQR6bSrUEA328mfAf9GA0/rrA/5HMksQ2m9YKN7wJj ytCpeGdVksdvm+XRQj8dMp0oZjL+AIuEdd60W9fhMg+lVDlt9kO9GJKDc2kwkinx oNxXCl54BYfmlvaW98KF5GWLAkDAUFpaUDg91ZneD1kRXoU9y/NSNiKXZP+GV/L8 8Niu2z8smypLv0UaRGblpDY+HkVfZkoV2yZJBGEcS9b7wHPy8nVv6rqUb93b+EJM IfooUj3DaCoa61dmTFa/a5oWnuu2Iu7F0SfMvL2rFFiMC22nXfSEGpfsKDeYihmG fhlSo0Fa665o94BfoetuXNiE2IU5Kez/aDk7sNNKoOoMsbxJPtzg9A0hyKS6eA== =xHH4 -----END PGP SIGNATURE----- Merge tag 'v0.10.3' into myShaarli_commu Release v0.10.3
This commit is contained in:
commit
272b07627b
102 changed files with 1240 additions and 1219 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -50,3 +50,5 @@ tpl/default/img
|
|||
tpl/vintage/js
|
||||
tpl/vintage/css
|
||||
tpl/vintage/img
|
||||
|
||||
.composer.lock
|
12
AUTHORS
12
AUTHORS
|
@ -1,6 +1,6 @@
|
|||
687 ArthurHoaro <arthur@hoa.ro>
|
||||
355 VirtualTam <virtualtam@flibidi.net>
|
||||
195 nodiscc <nodiscc@gmail.com>
|
||||
715 ArthurHoaro <arthur@hoa.ro>
|
||||
370 VirtualTam <virtualtam@flibidi.net>
|
||||
208 nodiscc <nodiscc@gmail.com>
|
||||
56 Sébastien Sauvage <sebsauvage@sebsauvage.net>
|
||||
15 Florian Eula <eula.florian@gmail.com>
|
||||
13 Emilien Klein <emilien@klein.st>
|
||||
|
@ -8,6 +8,7 @@
|
|||
9 Willi Eggeling <thewilli@gmail.com>
|
||||
8 Christophe HENRY <christophe.henry@sbgodin.fr>
|
||||
6 B. van Berkum <dev@dotmpe.com>
|
||||
6 llune <llune@users.noreply.github.com>
|
||||
5 Lucas Cimon <lucas.cimon@gmail.com>
|
||||
5 Mark Schmitz <kramred@gmail.com>
|
||||
5 kalvn <kalvnthereal@gmail.com>
|
||||
|
@ -15,10 +16,11 @@
|
|||
4 David Sferruzza <david.sferruzza@gmail.com>
|
||||
4 Immánuel Fodor <immanuelfactor+github@gmail.com>
|
||||
3 Teromene <teromene@teromene.fr>
|
||||
3 llune <llune@users.noreply.github.com>
|
||||
2 Alexandre G.-Raymond <alex@ndre.gr>
|
||||
2 Chris Kuethe <chris.kuethe@gmail.com>
|
||||
2 Felix Bartels <felix@host-consultants.de>
|
||||
2 Knah Tsaeb <Knah-Tsaeb@knah-tsaeb.org>
|
||||
2 Luce Carević <lcarevic@access42.net>
|
||||
2 Mathieu Chabanon <git@matchab.fr>
|
||||
2 Miloš Jovanović <mjovanovic@gmail.com>
|
||||
2 Qwerty <champlywood@free.fr>
|
||||
|
@ -29,9 +31,9 @@
|
|||
2 pips <pips@e5150.fr>
|
||||
1 Adrien Oliva <adrien.oliva@yapbreak.fr>
|
||||
1 Adrien le Maire <adrien@alemaire.be>
|
||||
1 Alexandre G.-Raymond <alex@ndre.gr>
|
||||
1 Alexis J <alexis@effingo.be>
|
||||
1 Angristan <angristan@users.noreply.github.com>
|
||||
1 Bish Erbas <42714627+bisherbas@users.noreply.github.com>
|
||||
1 BoboTiG <bobotig@gmail.com>
|
||||
1 Bronco <bronco@warriordudimanche.net>
|
||||
1 Buster One <37770318+buster-one@users.noreply.github.com>
|
||||
|
|
34
CHANGELOG.md
34
CHANGELOG.md
|
@ -4,6 +4,36 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [v0.10.3](https://github.com/shaarli/Shaarli/releases/tag/v0.10.3) - 2019-02-23
|
||||
### Added
|
||||
- Add OpenGraph metadata tags on permalink page
|
||||
- Add CORS headers to REST API reponses
|
||||
- Add a button to toggle checkboxes of displayed links
|
||||
- Add an icon to the link list when the Isso plugin is enabled
|
||||
- Add noindex, nofollow to documentation pages
|
||||
- Document usage of robots.txt
|
||||
- Add a button to set links as sticky
|
||||
|
||||
### Changed
|
||||
- Update French translation
|
||||
- Refactor the documentation homepage
|
||||
- Bump netscape-bookmark-parser
|
||||
- Update session_start condition
|
||||
- Improve accessibility
|
||||
- Cleanup and refactor lint tooling
|
||||
|
||||
### Fixed
|
||||
- Fix input size for dropdown search form
|
||||
- Fix history for bulk link deletion
|
||||
- Fix thumbnail requests
|
||||
- Fix hashtag rendering when markdown escaping is enabled
|
||||
- Fix AJAX tag deletion
|
||||
- Fix lint errors and improve PSR-1 and PSR-2 compliance
|
||||
|
||||
### Removed
|
||||
- Remove Firefox Share documentation
|
||||
|
||||
## [v0.10.2](https://github.com/shaarli/Shaarli/releases/tag/v0.10.2) - 2018-08-11
|
||||
|
||||
### Fixed
|
||||
|
@ -12,7 +42,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||
|
||||
## [v0.10.1](https://github.com/shaarli/Shaarli/releases/tag/v0.10.1) - 2018-08-11
|
||||
|
||||
### Changed
|
||||
### Changed
|
||||
|
||||
- Accessibility:
|
||||
- Remove alt text on the logo
|
||||
|
@ -46,7 +76,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||
- Use Travis matrix and stages to run Javascript tests in a dedicated environment
|
||||
- Add tag endpoint in the REST API
|
||||
- Build the documentation in Travis builds
|
||||
- Provide a Docker Compose example
|
||||
- Provide a Docker Compose example
|
||||
|
||||
### Changed
|
||||
- Use web-thumbnailer to retrieve thumbnails (see #687)
|
||||
|
|
68
Makefile
68
Makefile
|
@ -2,8 +2,6 @@
|
|||
# Makefile for PHP code analysis & testing, documentation and release generation
|
||||
|
||||
BIN = vendor/bin
|
||||
PHP_SOURCE = index.php application tests plugins
|
||||
PHP_COMMA_SOURCE = index.php,application,tests,plugins
|
||||
|
||||
all: static_analysis_summary check_permissions test
|
||||
|
||||
|
@ -17,14 +15,6 @@ docker_%:
|
|||
rsync -az /shaarli/ ~/shaarli/
|
||||
cd ~/shaarli && make $*
|
||||
|
||||
##
|
||||
# Concise status of the project
|
||||
# These targets are non-blocking: || exit 0
|
||||
##
|
||||
|
||||
static_analysis_summary: code_sniffer_source copy_paste mess_detector_summary
|
||||
@echo
|
||||
|
||||
##
|
||||
# PHP_CodeSniffer
|
||||
# Detects PHP syntax errors
|
||||
|
@ -32,70 +22,26 @@ static_analysis_summary: code_sniffer_source copy_paste mess_detector_summary
|
|||
# - http://pear.php.net/manual/en/package.php.php-codesniffer.usage.php
|
||||
# - http://pear.php.net/manual/en/package.php.php-codesniffer.reporting.php
|
||||
##
|
||||
PHPCS := $(BIN)/phpcs
|
||||
|
||||
code_sniffer: code_sniffer_full
|
||||
code_sniffer:
|
||||
@$(PHPCS)
|
||||
|
||||
### - errors filtered by coding standard: PEAR, PSR1, PSR2, Zend...
|
||||
PHPCS_%:
|
||||
@$(BIN)/phpcs $(PHP_SOURCE) --report-full --report-width=200 --standard=$*
|
||||
@$(PHPCS) --report-full --report-width=200 --standard=$*
|
||||
|
||||
### - errors by Git author
|
||||
code_sniffer_blame:
|
||||
@$(BIN)/phpcs $(PHP_SOURCE) --report-gitblame
|
||||
@$(PHPCS) --report-gitblame
|
||||
|
||||
### - all errors/warnings
|
||||
code_sniffer_full:
|
||||
@$(BIN)/phpcs $(PHP_SOURCE) --report-full --report-width=200
|
||||
@$(PHPCS) --report-full --report-width=200
|
||||
|
||||
### - errors grouped by kind
|
||||
code_sniffer_source:
|
||||
@$(BIN)/phpcs $(PHP_SOURCE) --report-source || exit 0
|
||||
|
||||
##
|
||||
# PHP Copy/Paste Detector
|
||||
# Detects code redundancy
|
||||
# Documentation: https://github.com/sebastianbergmann/phpcpd
|
||||
##
|
||||
|
||||
copy_paste:
|
||||
@echo "-----------------------"
|
||||
@echo "PHP COPY/PASTE DETECTOR"
|
||||
@echo "-----------------------"
|
||||
@$(BIN)/phpcpd $(PHP_SOURCE) || exit 0
|
||||
@echo
|
||||
|
||||
##
|
||||
# PHP Mess Detector
|
||||
# Detects PHP syntax errors, sorted by category
|
||||
# Rules documentation: http://phpmd.org/rules/index.html
|
||||
##
|
||||
MESS_DETECTOR_RULES = cleancode,codesize,controversial,design,naming,unusedcode
|
||||
|
||||
mess_title:
|
||||
@echo "-----------------"
|
||||
@echo "PHP MESS DETECTOR"
|
||||
@echo "-----------------"
|
||||
|
||||
### - all warnings
|
||||
mess_detector: mess_title
|
||||
@$(BIN)/phpmd $(PHP_COMMA_SOURCE) text $(MESS_DETECTOR_RULES) | sed 's_.*\/__'
|
||||
|
||||
### - all warnings + HTML output contains links to PHPMD's documentation
|
||||
mess_detector_html:
|
||||
@$(BIN)/phpmd $(PHP_COMMA_SOURCE) html $(MESS_DETECTOR_RULES) \
|
||||
--reportfile phpmd.html || exit 0
|
||||
|
||||
### - warnings grouped by message, sorted by descending frequency order
|
||||
mess_detector_grouped: mess_title
|
||||
@$(BIN)/phpmd $(PHP_SOURCE) text $(MESS_DETECTOR_RULES) \
|
||||
| cut -f 2 | sort | uniq -c | sort -nr
|
||||
|
||||
### - summary: number of warnings by rule set
|
||||
mess_detector_summary: mess_title
|
||||
@for rule in $$(echo $(MESS_DETECTOR_RULES) | tr ',' ' '); do \
|
||||
warnings=$$($(BIN)/phpmd $(PHP_COMMA_SOURCE) text $$rule | wc -l); \
|
||||
printf "$$warnings\t$$rule\n"; \
|
||||
done;
|
||||
@$(PHPCS) --report-source || exit 0
|
||||
|
||||
##
|
||||
# Checks source file & script permissions
|
||||
|
|
|
@ -9,7 +9,7 @@ _It is designed to be personal (single-user), fast and handy._
|
|||
[![](https://img.shields.io/badge/stable-v0.9.7-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.7)
|
||||
[![](https://img.shields.io/travis/shaarli/Shaarli/stable.svg?label=stable)](https://travis-ci.org/shaarli/Shaarli)
|
||||
•
|
||||
[![](https://img.shields.io/badge/latest-v0.10.1-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.10.1)
|
||||
[![](https://img.shields.io/badge/latest-v0.10.2-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.10.2)
|
||||
[![](https://img.shields.io/travis/shaarli/Shaarli/latest.svg?label=latest)](https://travis-ci.org/shaarli/Shaarli)
|
||||
•
|
||||
[![](https://img.shields.io/badge/master-v0.10.x-blue.svg)](https://github.com/shaarli/Shaarli)
|
||||
|
|
|
@ -24,7 +24,7 @@ class ApplicationUtils
|
|||
*
|
||||
* @return mixed the version code from the repository if available, else 'false'
|
||||
*/
|
||||
public static function getLatestGitVersionCode($url, $timeout=2)
|
||||
public static function getLatestGitVersionCode($url, $timeout = 2)
|
||||
{
|
||||
list($headers, $data) = get_http_response($url, $timeout);
|
||||
|
||||
|
@ -86,13 +86,14 @@ public static function getVersion($remote, $timeout = 2)
|
|||
*
|
||||
* @return mixed the new version code if available and greater, else 'false'
|
||||
*/
|
||||
public static function checkUpdate($currentVersion,
|
||||
$updateFile,
|
||||
$checkInterval,
|
||||
$enableCheck,
|
||||
$isLoggedIn,
|
||||
$branch='stable')
|
||||
{
|
||||
public static function checkUpdate(
|
||||
$currentVersion,
|
||||
$updateFile,
|
||||
$checkInterval,
|
||||
$enableCheck,
|
||||
$isLoggedIn,
|
||||
$branch = 'stable'
|
||||
) {
|
||||
// Do not check versions for visitors
|
||||
// Do not check if the user doesn't want to
|
||||
// Do not check with dev version
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Shaarli;
|
||||
|
||||
|
||||
/**
|
||||
* URL-safe Base64 operations
|
||||
*
|
||||
|
@ -17,7 +16,8 @@ class Base64Url
|
|||
*
|
||||
* @return string Base64Url-encoded data
|
||||
*/
|
||||
public static function encode($data) {
|
||||
public static function encode($data)
|
||||
{
|
||||
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,8 @@ public static function encode($data) {
|
|||
*
|
||||
* @return string Decoded data
|
||||
*/
|
||||
public static function decode($data) {
|
||||
public static function decode($data)
|
||||
{
|
||||
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -162,7 +162,8 @@ protected function buildItem($link, $pageaddr)
|
|||
$upDate = $link['updated'];
|
||||
$link['up_iso_date'] = $this->getIsoDate($upDate, DateTime::ATOM);
|
||||
} else {
|
||||
$link['up_iso_date'] = $this->getIsoDate($pubDate, DateTime::ATOM);;
|
||||
$link['up_iso_date'] = $this->getIsoDate($pubDate, DateTime::ATOM);
|
||||
;
|
||||
}
|
||||
|
||||
// Save the more recent item.
|
||||
|
@ -260,7 +261,6 @@ protected function getIsoDate(DateTime $date, $format = false)
|
|||
}
|
||||
if ($this->feedType == self::$FEED_RSS) {
|
||||
return $date->format(DateTime::RSS);
|
||||
|
||||
}
|
||||
return $date->format(DateTime::ATOM);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
* @param int $timeout network timeout (in seconds)
|
||||
* @param int $maxBytes maximum downloaded bytes (default: 4 MiB)
|
||||
* @param callable|string $curlWriteFunction Optional callback called during the download (cURL CURLOPT_WRITEFUNCTION).
|
||||
* Can be used to add download conditions on the headers (response code, content type, etc.).
|
||||
* Can be used to add download conditions on the
|
||||
* headers (response code, content type, etc.).
|
||||
*
|
||||
* @return array HTTP response headers, downloaded content
|
||||
*
|
||||
|
@ -64,29 +65,30 @@ function get_http_response($url, $timeout = 30, $maxBytes = 4194304, $curlWriteF
|
|||
}
|
||||
|
||||
// General cURL settings
|
||||
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt(
|
||||
$ch,
|
||||
CURLOPT_HTTPHEADER,
|
||||
array('Accept-Language: ' . $acceptLanguage)
|
||||
);
|
||||
curl_setopt($ch, CURLOPT_MAXREDIRS, $maxRedirs);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
|
||||
curl_setopt($ch, CURLOPT_MAXREDIRS, $maxRedirs);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
|
||||
|
||||
if (is_callable($curlWriteFunction)) {
|
||||
curl_setopt($ch, CURLOPT_WRITEFUNCTION, $curlWriteFunction);
|
||||
}
|
||||
|
||||
// Max download size management
|
||||
curl_setopt($ch, CURLOPT_BUFFERSIZE, 1024*16);
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
|
||||
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION,
|
||||
function($arg0, $arg1, $arg2, $arg3, $arg4 = 0) use ($maxBytes)
|
||||
{
|
||||
curl_setopt($ch, CURLOPT_BUFFERSIZE, 1024*16);
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
|
||||
curl_setopt(
|
||||
$ch,
|
||||
CURLOPT_PROGRESSFUNCTION,
|
||||
function ($arg0, $arg1, $arg2, $arg3, $arg4 = 0) use ($maxBytes) {
|
||||
if (version_compare(phpversion(), '5.5', '<')) {
|
||||
// PHP version lower than 5.5
|
||||
// Callback has 4 arguments
|
||||
|
@ -232,7 +234,6 @@ function get_redirected_headers($url, $redirectionLimit = 3)
|
|||
&& !empty($headers)
|
||||
&& (strpos($headers[0], '301') !== false || strpos($headers[0], '302') !== false)
|
||||
&& !empty($headers['Location'])) {
|
||||
|
||||
$redirection = is_array($headers['Location']) ? end($headers['Location']) : $headers['Location'];
|
||||
if ($redirection != $url) {
|
||||
$redirection = getAbsoluteUrl($url, $redirection);
|
||||
|
|
|
@ -92,7 +92,7 @@ public function __construct($language, $conf)
|
|||
/**
|
||||
* Initialize the translator using php gettext extension (gettext dependency act as a wrapper).
|
||||
*/
|
||||
protected function initGettextTranslator ()
|
||||
protected function initGettextTranslator()
|
||||
{
|
||||
$this->translator = new GettextTranslator();
|
||||
$this->translator->setLanguage($this->language);
|
||||
|
@ -125,7 +125,8 @@ protected function initPhpTranslator()
|
|||
$translations = $translations->addFromPoFile('inc/languages/'. $this->language .'/LC_MESSAGES/shaarli.po');
|
||||
$translations->setDomain('shaarli');
|
||||
$this->translator->loadTranslations($translations);
|
||||
} catch (\InvalidArgumentException $e) {}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
}
|
||||
|
||||
// Default extension translation from the current theme
|
||||
$theme = $this->conf->get('theme');
|
||||
|
@ -137,7 +138,8 @@ protected function initPhpTranslator()
|
|||
);
|
||||
$translations->setDomain($theme);
|
||||
$this->translator->loadTranslations($translations);
|
||||
} catch (\InvalidArgumentException $e) {}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
// Extension translations (plugins, themes, etc.).
|
||||
|
@ -147,10 +149,13 @@ protected function initPhpTranslator()
|
|||
}
|
||||
|
||||
try {
|
||||
$extension = Translations::fromPoFile($translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po');
|
||||
$extension = Translations::fromPoFile(
|
||||
$translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po'
|
||||
);
|
||||
$extension->setDomain($domain);
|
||||
$this->translator->loadTranslations($extension);
|
||||
} catch (\InvalidArgumentException $e) {}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -107,8 +107,7 @@ public function __construct(
|
|||
$hidePublicLinks,
|
||||
$redirector = '',
|
||||
$redirectorEncode = true
|
||||
)
|
||||
{
|
||||
) {
|
||||
$this->datastore = $datastore;
|
||||
$this->loggedIn = $isLoggedIn;
|
||||
$this->hidePublicLinks = $hidePublicLinks;
|
||||
|
@ -250,11 +249,14 @@ private function check()
|
|||
'id' => 1,
|
||||
'title'=> t('The personal, minimalist, super-fast, database free, bookmarking service'),
|
||||
'url'=>'https://shaarli.readthedocs.io',
|
||||
'description'=>t('Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login.
|
||||
'description'=>t(
|
||||
'Welcome to Shaarli! This is your first public bookmark. '
|
||||
.'To edit or delete me, you must first login.
|
||||
|
||||
To learn how to use Shaarli, consult the link "Documentation" at the bottom of this page.
|
||||
|
||||
You use the community supported version of the original Shaarli project, by Sebastien Sauvage.'),
|
||||
You use the community supported version of the original Shaarli project, by Sebastien Sauvage.'
|
||||
),
|
||||
'private'=>0,
|
||||
'created'=> new DateTime(),
|
||||
'tags'=>'opensource software'
|
||||
|
@ -317,8 +319,7 @@ private function read()
|
|||
} else {
|
||||
$link['real_url'] .= $link['url'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$link['real_url'] = $link['url'];
|
||||
}
|
||||
|
||||
|
@ -403,7 +404,8 @@ public function filterHash($request)
|
|||
*
|
||||
* @return array list of shaare found.
|
||||
*/
|
||||
public function filterDay($request) {
|
||||
public function filterDay($request)
|
||||
{
|
||||
$linkFilter = new LinkFilter($this->links);
|
||||
return $linkFilter->filter(LinkFilter::$FILTER_DAY, $request);
|
||||
}
|
||||
|
@ -420,8 +422,12 @@ public function filterDay($request) {
|
|||
*
|
||||
* @return array filtered links, all links if no suitable filter was provided.
|
||||
*/
|
||||
public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all', $untaggedonly = false)
|
||||
{
|
||||
public function filterSearch(
|
||||
$filterRequest = array(),
|
||||
$casesensitive = false,
|
||||
$visibility = 'all',
|
||||
$untaggedonly = false
|
||||
) {
|
||||
// Filter link database according to parameters.
|
||||
$searchtags = isset($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : '';
|
||||
$searchterm = isset($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : '';
|
||||
|
@ -492,8 +498,7 @@ public function renameTag($from, $to)
|
|||
$delete = empty($to);
|
||||
// True for case-sensitive tag search.
|
||||
$linksToAlter = $this->filterSearch(['searchtags' => $from], true);
|
||||
foreach($linksToAlter as $key => &$value)
|
||||
{
|
||||
foreach ($linksToAlter as $key => &$value) {
|
||||
$tags = preg_split('/\s+/', trim($value['tags']));
|
||||
if (($pos = array_search($from, $tags)) !== false) {
|
||||
if ($delete) {
|
||||
|
@ -536,7 +541,10 @@ public function reorder($order = 'DESC')
|
|||
{
|
||||
$order = $order === 'ASC' ? -1 : 1;
|
||||
// Reorder array by dates.
|
||||
usort($this->links, function($a, $b) use ($order) {
|
||||
usort($this->links, function ($a, $b) use ($order) {
|
||||
if (isset($a['sticky']) && isset($b['sticky']) && $a['sticky'] !== $b['sticky']) {
|
||||
return $a['sticky'] ? -1 : 1;
|
||||
}
|
||||
return $a['created'] < $b['created'] ? 1 * $order : -1 * $order;
|
||||
});
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public function filter($type, $request, $casesensitive = false, $visibility = 'a
|
|||
$visibility = 'all';
|
||||
}
|
||||
|
||||
switch($type) {
|
||||
switch ($type) {
|
||||
case self::$FILTER_HASH:
|
||||
return $this->filterSmallHash($request);
|
||||
case self::$FILTER_TAG | self::$FILTER_TEXT: // == "vuotext"
|
||||
|
@ -205,7 +205,6 @@ private function filterFulltext($searchterms, $visibility = 'all')
|
|||
|
||||
// Iterate over every stored link.
|
||||
foreach ($this->links as $id => $link) {
|
||||
|
||||
// ignore non private links when 'privatonly' is on.
|
||||
if ($visibility !== 'all') {
|
||||
if (! $link['private'] && $visibility === 'private') {
|
||||
|
@ -257,11 +256,11 @@ private function filterFulltext($searchterms, $visibility = 'all')
|
|||
private static function tag2regex($tag)
|
||||
{
|
||||
$len = strlen($tag);
|
||||
if(!$len || $tag === "-" || $tag === "*"){
|
||||
if (!$len || $tag === "-" || $tag === "*") {
|
||||
// nothing to search, return empty regex
|
||||
return '';
|
||||
}
|
||||
if($tag[0] === "-") {
|
||||
if ($tag[0] === "-") {
|
||||
// query is negated
|
||||
$i = 1; // use offset to start after '-' character
|
||||
$regex = '(?!'; // create negative lookahead
|
||||
|
@ -271,14 +270,14 @@ private static function tag2regex($tag)
|
|||
}
|
||||
$regex .= '.*(?:^| )'; // before tag may only be a space or the beginning
|
||||
// iterate over string, separating it into placeholder and content
|
||||
for(; $i < $len; $i++){
|
||||
if($tag[$i] === '*'){
|
||||
for (; $i < $len; $i++) {
|
||||
if ($tag[$i] === '*') {
|
||||
// placeholder found
|
||||
$regex .= '[^ ]*?';
|
||||
} else {
|
||||
// regular characters
|
||||
$offset = strpos($tag, '*', $i);
|
||||
if($offset === false){
|
||||
if ($offset === false) {
|
||||
// no placeholder found, set offset to end of string
|
||||
$offset = $len;
|
||||
}
|
||||
|
@ -310,19 +309,19 @@ public function filterTags($tags, $casesensitive = false, $visibility = 'all')
|
|||
{
|
||||
// get single tags (we may get passed an array, even though the docs say different)
|
||||
$inputTags = $tags;
|
||||
if(!is_array($tags)) {
|
||||
if (!is_array($tags)) {
|
||||
// we got an input string, split tags
|
||||
$inputTags = preg_split('/(?:\s+)|,/', $inputTags, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
|
||||
if(!count($inputTags)){
|
||||
if (!count($inputTags)) {
|
||||
// no input tags
|
||||
return $this->noFilter($visibility);
|
||||
}
|
||||
|
||||
// build regex from all tags
|
||||
$re = '/^' . implode(array_map("self::tag2regex", $inputTags)) . '.*$/';
|
||||
if(!$casesensitive) {
|
||||
if (!$casesensitive) {
|
||||
// make regex case insensitive
|
||||
$re .= 'i';
|
||||
}
|
||||
|
@ -342,7 +341,7 @@ public function filterTags($tags, $casesensitive = false, $visibility = 'all')
|
|||
}
|
||||
}
|
||||
$search = $link['tags']; // build search string, start with tags of current link
|
||||
if(strlen(trim($link['description'])) && strpos($link['description'], '#') !== false){
|
||||
if (strlen(trim($link['description'])) && strpos($link['description'], '#') !== false) {
|
||||
// description given and at least one possible tag found
|
||||
$descTags = array();
|
||||
// find all tags in the form of #tag in the description
|
||||
|
@ -351,13 +350,13 @@ public function filterTags($tags, $casesensitive = false, $visibility = 'all')
|
|||
$link['description'],
|
||||
$descTags
|
||||
);
|
||||
if(count($descTags[1])){
|
||||
if (count($descTags[1])) {
|
||||
// there were some tags in the description, add them to the search string
|
||||
$search .= ' ' . implode(' ', $descTags[1]);
|
||||
}
|
||||
};
|
||||
// match regular expression with search string
|
||||
if(!preg_match($re, $search)){
|
||||
if (!preg_match($re, $search)) {
|
||||
// this entry does _not_ match our regex
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ function get_curl_download_callback(&$charset, &$title, $curlGetInfo = 'curl_get
|
|||
*
|
||||
* @return int|bool length of $data or false if we need to stop the download
|
||||
*/
|
||||
return function(&$ch, $data) use ($curlGetInfo, &$charset, &$title, &$isRedirected) {
|
||||
return function (&$ch, $data) use ($curlGetInfo, &$charset, &$title, &$isRedirected) {
|
||||
$responseCode = $curlGetInfo($ch, CURLINFO_RESPONSE_CODE);
|
||||
if (!empty($responseCode) && in_array($responseCode, [301, 302])) {
|
||||
$isRedirected = true;
|
||||
|
@ -201,7 +201,8 @@ function space2nbsp($text)
|
|||
|
||||
* @return string formatted description.
|
||||
*/
|
||||
function format_description($description, $redirector = '', $urlEncode = true, $indexUrl = '') {
|
||||
function format_description($description, $redirector = '', $urlEncode = true, $indexUrl = '')
|
||||
{
|
||||
return nl2br(space2nbsp(hashtag_autolink(text2clickable($description, $redirector, $urlEncode), $indexUrl)));
|
||||
}
|
||||
|
||||
|
|
|
@ -72,18 +72,20 @@ public static function filterAndFormat($linkDb, $selection, $prependNoteUrl, $in
|
|||
private static function importStatus(
|
||||
$filename,
|
||||
$filesize,
|
||||
$importCount=0,
|
||||
$overwriteCount=0,
|
||||
$skipCount=0,
|
||||
$duration=0
|
||||
)
|
||||
{
|
||||
$importCount = 0,
|
||||
$overwriteCount = 0,
|
||||
$skipCount = 0,
|
||||
$duration = 0
|
||||
) {
|
||||
$status = sprintf(t('File %s (%d bytes) '), $filename, $filesize);
|
||||
if ($importCount == 0 && $overwriteCount == 0 && $skipCount == 0) {
|
||||
$status .= t('has an unknown file format. Nothing was imported.');
|
||||
} else {
|
||||
$status .= vsprintf(
|
||||
t('was successfully processed in %d seconds: %d links imported, %d links overwritten, %d links skipped.'),
|
||||
t(
|
||||
'was successfully processed in %d seconds: '
|
||||
.'%d links imported, %d links overwritten, %d links skipped.'
|
||||
),
|
||||
[$duration, $importCount, $overwriteCount, $skipCount]
|
||||
);
|
||||
}
|
||||
|
|
|
@ -78,7 +78,6 @@ private function initialize()
|
|||
);
|
||||
$this->tpl->assign('newVersion', escape($version));
|
||||
$this->tpl->assign('versionError', '');
|
||||
|
||||
} catch (Exception $exc) {
|
||||
logm($this->conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], $exc->getMessage());
|
||||
$this->tpl->assign('newVersion', '');
|
||||
|
@ -101,7 +100,7 @@ private function initialize()
|
|||
'version_hash',
|
||||
ApplicationUtils::getVersionHash(SHAARLI_VERSION, $this->conf->get('credentials.salt'))
|
||||
);
|
||||
$this->tpl->assign('scripturl', index_url($_SERVER));
|
||||
$this->tpl->assign('index_url', index_url($_SERVER));
|
||||
$visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : '';
|
||||
$this->tpl->assign('visibility', $visibility);
|
||||
$this->tpl->assign('untaggedonly', !empty($_SESSION['untaggedonly']));
|
||||
|
@ -163,7 +162,7 @@ public function assignAll($data)
|
|||
$this->initialize();
|
||||
}
|
||||
|
||||
if (empty($data) || !is_array($data)){
|
||||
if (empty($data) || !is_array($data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,8 +75,7 @@ public function load($authorizedPlugins)
|
|||
|
||||
try {
|
||||
$this->loadPlugin($dirs[$index], $plugin);
|
||||
}
|
||||
catch (PluginFileNotFoundException $e) {
|
||||
} catch (PluginFileNotFoundException $e) {
|
||||
error_log($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ class Router
|
|||
|
||||
public static $PAGE_DELETELINK = 'delete_link';
|
||||
|
||||
public static $PAGE_PINLINK = 'pin';
|
||||
|
||||
public static $PAGE_EXPORT = 'export';
|
||||
|
||||
public static $PAGE_IMPORT = 'import';
|
||||
|
@ -146,6 +148,10 @@ public static function findPage($query, $get, $loggedIn)
|
|||
return self::$PAGE_DELETELINK;
|
||||
}
|
||||
|
||||
if (startsWith($query, 'do='. self::$PAGE_PINLINK)) {
|
||||
return self::$PAGE_PINLINK;
|
||||
}
|
||||
|
||||
if (startsWith($query, 'do='. self::$PAGE_EXPORT)) {
|
||||
return self::$PAGE_EXPORT;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,10 @@ public function __construct($conf)
|
|||
$this->conf->set('thumbnails.enabled', false);
|
||||
$this->conf->write(true);
|
||||
// TODO: create a proper error handling system able to catch exceptions...
|
||||
die(t('php-gd extension must be loaded to use thumbnails. Thumbnails are now disabled. Please reload the page.'));
|
||||
die(t(
|
||||
'php-gd extension must be loaded to use thumbnails. '
|
||||
.'Thumbnails are now disabled. Please reload the page.'
|
||||
));
|
||||
}
|
||||
|
||||
$this->wt = new WebThumbnailer();
|
||||
|
|
|
@ -183,7 +183,7 @@ public function updateMethodConfigToJson()
|
|||
}
|
||||
}
|
||||
|
||||
try{
|
||||
try {
|
||||
$this->conf->write($this->isLoggedIn);
|
||||
return true;
|
||||
} catch (IOException $e) {
|
||||
|
@ -517,6 +517,26 @@ public function updateMethodWebThumbnailer()
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sticky = false on all links
|
||||
*
|
||||
* @return bool true if the update is successful, false otherwise.
|
||||
*/
|
||||
public function updateMethodSetSticky()
|
||||
{
|
||||
foreach ($this->linkDB as $key => $link) {
|
||||
if (isset($link['sticky'])) {
|
||||
return true;
|
||||
}
|
||||
$link['sticky'] = false;
|
||||
$this->linkDB[$key] = $link;
|
||||
}
|
||||
|
||||
$this->linkDB->save($this->conf->get('resource.page_cache'));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,8 +34,8 @@ function unparse_url($parsedUrl)
|
|||
*/
|
||||
function cleanup_url($url)
|
||||
{
|
||||
$obj_url = new Url($url);
|
||||
return $obj_url->cleanup();
|
||||
$obj_url = new Url($url);
|
||||
return $obj_url->cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,8 +47,8 @@ function cleanup_url($url)
|
|||
*/
|
||||
function get_url_scheme($url)
|
||||
{
|
||||
$obj_url = new Url($url);
|
||||
return $obj_url->getScheme();
|
||||
$obj_url = new Url($url);
|
||||
return $obj_url->getScheme();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -217,7 +217,7 @@ protected function cleanupQuery()
|
|||
}
|
||||
|
||||
$this->parts['query'] = implode('&', $queryParams);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes undesired fragments
|
||||
|
@ -269,7 +269,8 @@ public function idnToAscii()
|
|||
*
|
||||
* @return string the URL scheme or false if none is provided.
|
||||
*/
|
||||
public function getScheme() {
|
||||
public function getScheme()
|
||||
{
|
||||
if (!isset($this->parts['scheme'])) {
|
||||
return false;
|
||||
}
|
||||
|
@ -281,7 +282,8 @@ public function getScheme() {
|
|||
*
|
||||
* @return string the URL host or false if none is provided.
|
||||
*/
|
||||
public function getHost() {
|
||||
public function getHost()
|
||||
{
|
||||
if (empty($this->parts['host'])) {
|
||||
return false;
|
||||
}
|
||||
|
@ -293,7 +295,8 @@ public function getHost() {
|
|||
*
|
||||
* @return true is HTTP, false otherwise.
|
||||
*/
|
||||
public function isHttp() {
|
||||
public function isHttp()
|
||||
{
|
||||
return strpos(strtolower($this->parts['scheme']), 'http') !== false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ function escape($input)
|
|||
|
||||
if (is_array($input)) {
|
||||
$out = array();
|
||||
foreach($input as $key => $value) {
|
||||
foreach ($input as $key => $value) {
|
||||
$out[$key] = escape($value);
|
||||
}
|
||||
return $out;
|
||||
|
@ -355,10 +355,13 @@ function return_bytes($val)
|
|||
$val = trim($val);
|
||||
$last = strtolower($val[strlen($val)-1]);
|
||||
$val = intval(substr($val, 0, -1));
|
||||
switch($last) {
|
||||
case 'g': $val *= 1024;
|
||||
case 'm': $val *= 1024;
|
||||
case 'k': $val *= 1024;
|
||||
switch ($last) {
|
||||
case 'g':
|
||||
$val *= 1024;
|
||||
case 'm':
|
||||
$val *= 1024;
|
||||
case 'k':
|
||||
$val *= 1024;
|
||||
}
|
||||
return $val;
|
||||
}
|
||||
|
@ -452,6 +455,7 @@ function alphabetical_sort(&$data, $reverse = false, $byKeys = false)
|
|||
*
|
||||
* @return string Text translated.
|
||||
*/
|
||||
function t($text, $nText = '', $nb = 1, $domain = 'shaarli') {
|
||||
function t($text, $nText = '', $nb = 1, $domain = 'shaarli')
|
||||
{
|
||||
return dn__($domain, $text, $nText, $nb);
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ public function __invoke($request, $response, $next)
|
|||
try {
|
||||
$this->checkRequest($request);
|
||||
$response = $next($request, $response);
|
||||
} catch(ApiException $e) {
|
||||
} catch (ApiException $e) {
|
||||
$e->setResponse($response);
|
||||
$e->setDebug($this->conf->get('dev.debug', false));
|
||||
$response = $e->getApiResponse();
|
||||
|
@ -98,7 +98,8 @@ protected function checkRequest($request)
|
|||
*
|
||||
* @throws ApiAuthorizationException The token couldn't be validated.
|
||||
*/
|
||||
protected function checkToken($request) {
|
||||
protected function checkToken($request)
|
||||
{
|
||||
if (! $request->hasHeader('Authorization')) {
|
||||
throw new ApiAuthorizationException('JWT token not provided');
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ abstract class ApiController
|
|||
|
||||
/**
|
||||
* ApiController constructor.
|
||||
*
|
||||
*
|
||||
* Note: enabling debug mode displays JSON with readable formatting.
|
||||
*
|
||||
* @param Container $ci Slim container.
|
||||
|
|
|
@ -35,8 +35,7 @@ public function getHistory($request, $response)
|
|||
$offset = $request->getParam('offset');
|
||||
if (empty($offset)) {
|
||||
$offset = 0;
|
||||
}
|
||||
elseif (ctype_digit($offset)) {
|
||||
} elseif (ctype_digit($offset)) {
|
||||
$offset = (int) $offset;
|
||||
} else {
|
||||
throw new ApiBadParametersException('Invalid offset');
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
/**
|
||||
* Class Info
|
||||
*
|
||||
*
|
||||
* REST API Controller: /info
|
||||
*
|
||||
* @package Api\Controllers
|
||||
|
@ -17,7 +17,7 @@ class Info extends ApiController
|
|||
{
|
||||
/**
|
||||
* Service providing various information about Shaarli instance.
|
||||
*
|
||||
*
|
||||
* @param Request $request Slim request.
|
||||
* @param Response $response Slim response.
|
||||
*
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
* Parent Exception related to the API, able to generate a valid Response (ResponseInterface).
|
||||
* Also can include various information in debug mode.
|
||||
*/
|
||||
abstract class ApiException extends \Exception {
|
||||
abstract class ApiException extends \Exception
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Response instance from Slim.
|
||||
|
@ -27,7 +28,7 @@ abstract class ApiException extends \Exception {
|
|||
*
|
||||
* @return Response Final response to give.
|
||||
*/
|
||||
public abstract function getApiResponse();
|
||||
abstract public function getApiResponse();
|
||||
|
||||
/**
|
||||
* Creates ApiResponse body.
|
||||
|
@ -36,7 +37,8 @@ public abstract function getApiResponse();
|
|||
*
|
||||
* @return array|string response body
|
||||
*/
|
||||
protected function getApiResponseBody() {
|
||||
protected function getApiResponseBody()
|
||||
{
|
||||
if ($this->debug !== true) {
|
||||
return $this->getMessage();
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Shaarli\Api\Exceptions;
|
||||
|
||||
|
||||
use Slim\Http\Response;
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Shaarli\Api\Exceptions;
|
||||
|
||||
|
||||
use Slim\Http\Response;
|
||||
|
||||
/**
|
||||
|
|
|
@ -104,12 +104,20 @@ public function write($filepath, $conf)
|
|||
|
||||
// Store all $conf['config']
|
||||
foreach ($conf['config'] as $key => $value) {
|
||||
$configStr .= '$GLOBALS[\'config\'][\''. $key .'\'] = '.var_export($conf['config'][$key], true).';'. PHP_EOL;
|
||||
$configStr .= '$GLOBALS[\'config\'][\''
|
||||
. $key
|
||||
.'\'] = '
|
||||
.var_export($conf['config'][$key], true).';'
|
||||
. PHP_EOL;
|
||||
}
|
||||
|
||||
if (isset($conf['plugins'])) {
|
||||
foreach ($conf['plugins'] as $key => $value) {
|
||||
$configStr .= '$GLOBALS[\'plugins\'][\''. $key .'\'] = '.var_export($conf['plugins'][$key], true).';'. PHP_EOL;
|
||||
$configStr .= '$GLOBALS[\'plugins\'][\''
|
||||
. $key
|
||||
.'\'] = '
|
||||
.var_export($conf['plugins'][$key], true).';'
|
||||
. PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,7 @@ function save_plugin_config($formData)
|
|||
// If there is no order, it means a disabled plugin has been enabled.
|
||||
if (isset($formData['order_' . $key])) {
|
||||
$plugins[(int) $formData['order_' . $key]] = $key;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$newEnabledPlugins[] = $key;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,6 @@ public function checkLoginState($cookie, $clientIpId)
|
|||
// The user client has a valid stay-signed-in cookie
|
||||
// Session information is updated with the current client information
|
||||
$this->sessionManager->storeLoginInfo($clientIpId);
|
||||
|
||||
} elseif ($this->sessionManager->hasSessionExpired()
|
||||
|| $this->sessionManager->hasClientIpChanged($clientIpId)
|
||||
) {
|
||||
|
|
|
@ -422,12 +422,12 @@ function init(description) {
|
|||
/**
|
||||
* Bulk actions
|
||||
*/
|
||||
const linkCheckboxes = document.querySelectorAll('.delete-checkbox');
|
||||
const linkCheckboxes = document.querySelectorAll('.link-checkbox');
|
||||
const bar = document.getElementById('actions');
|
||||
[...linkCheckboxes].forEach((checkbox) => {
|
||||
checkbox.style.display = 'inline-block';
|
||||
checkbox.addEventListener('click', () => {
|
||||
const linkCheckedCheckboxes = document.querySelectorAll('.delete-checkbox:checked');
|
||||
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');
|
||||
|
@ -444,7 +444,7 @@ function init(description) {
|
|||
event.preventDefault();
|
||||
|
||||
const links = [];
|
||||
const linkCheckedCheckboxes = document.querySelectorAll('.delete-checkbox:checked');
|
||||
const linkCheckedCheckboxes = document.querySelectorAll('.link-checkbox:checked');
|
||||
[...linkCheckedCheckboxes].forEach((checkbox) => {
|
||||
links.push({
|
||||
id: checkbox.value,
|
||||
|
@ -466,6 +466,25 @@ function init(description) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -548,7 +567,7 @@ function init(description) {
|
|||
event.preventDefault();
|
||||
const block = findParent(event.target, 'div', { class: 'tag-list-item' });
|
||||
const tag = block.getAttribute('data-tag');
|
||||
const refreshedToken = document.getElementById('token');
|
||||
const refreshedToken = document.getElementById('token').value;
|
||||
|
||||
if (confirm(`Are you sure you want to delete the tag "${tag}"?`)) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
|
|
@ -381,8 +381,6 @@ body,
|
|||
box-shadow: 0 1px 0 $light-shadow, 0 1px 4px $dark-shadow inset;
|
||||
background: $almost-white;
|
||||
padding: 5px 5px 3px 15px;
|
||||
width: 20%;
|
||||
height: 20px;
|
||||
color: $dark-grey;
|
||||
}
|
||||
|
||||
|
@ -742,7 +740,7 @@ body,
|
|||
font-size: 1em;
|
||||
}
|
||||
|
||||
.delete-checkbox {
|
||||
.link-checkbox {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -757,6 +755,14 @@ body,
|
|||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.pin-link {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.pinned-link {
|
||||
color: $blue !important;
|
||||
}
|
||||
|
||||
.linklist-item-description {
|
||||
position: relative;
|
||||
padding: 0 10px;
|
||||
|
@ -850,6 +856,10 @@ body,
|
|||
margin: 0 7px;
|
||||
}
|
||||
|
||||
.ctrl-delete {
|
||||
margin: 0 7px 0 0;
|
||||
}
|
||||
|
||||
// 64em -> lg
|
||||
@media screen and (max-width: 64em) {
|
||||
.linklist-item-infos-url {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
"require": {
|
||||
"php": ">=5.6",
|
||||
"shaarli/netscape-bookmark-parser": "^2.0",
|
||||
"shaarli/netscape-bookmark-parser": "^2.1",
|
||||
"erusev/parsedown": "^1.6",
|
||||
"slim/slim": "^3.0",
|
||||
"arthurhoaro/web-thumbnailer": "^1.1",
|
||||
|
@ -24,11 +24,9 @@
|
|||
"gettext/gettext": "^4.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpmd/phpmd" : "@stable",
|
||||
"phpunit/phpcov": "*",
|
||||
"phpunit/phpunit": "^5.0",
|
||||
"sebastian/phpcpd": "*",
|
||||
"squizlabs/php_codesniffer": "2.*",
|
||||
"phpunit/phpcov": "*"
|
||||
"squizlabs/php_codesniffer": "2.*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
495
composer.lock
generated
495
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "da7a0c081b61d949154c5d2e5370cbab",
|
||||
"content-hash": "3876b34296fedb365517b785af8384de",
|
||||
"packages": [
|
||||
{
|
||||
"name": "arthurhoaro/web-thumbnailer",
|
||||
|
@ -133,16 +133,16 @@
|
|||
},
|
||||
{
|
||||
"name": "gettext/gettext",
|
||||
"version": "v4.6.1",
|
||||
"version": "v4.6.2",
|
||||
"source": {
|
||||