Fixes #784
From now, searching for tags with an empty value will return only not tagged links,
with the search bar showing `x results [not tagged]`.
Note that using the api, the searchtags request parameter must be set to `false` to get the same result.
- [ ] Update API doc
12 files changed:
*/
public function buildData()
{
*/
public function buildData()
{
+ // Search for untagged links
+ if (isset($this->userInput['searchtags']) && empty($this->userInput['searchtags'])) {
+ $this->userInput['searchtags'] = false;
+ }
+
// Optionally filter the results:
$linksToDisplay = $this->linkDB->filterSearch($this->userInput);
// Optionally filter the results:
$linksToDisplay = $this->linkDB->filterSearch($this->userInput);
public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all')
{
// Filter link database according to parameters.
public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all')
{
// Filter link database according to parameters.
- $searchtags = !empty($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : '';
- $searchterm = !empty($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : '';
+ $searchtags = isset($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : '';
+ $searchterm = isset($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : '';
- // Search tags + fullsearch.
- if (! empty($searchtags) && ! empty($searchterm)) {
- $type = LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT;
- $request = array($searchtags, $searchterm);
- }
- // Search by tags.
- elseif (! empty($searchtags)) {
- $type = LinkFilter::$FILTER_TAG;
- $request = $searchtags;
- }
- // Fulltext search.
- elseif (! empty($searchterm)) {
- $type = LinkFilter::$FILTER_TEXT;
- $request = $searchterm;
- }
- // Otherwise, display without filtering.
- else {
- $type = '';
- $request = '';
- }
+ // Search tags + fullsearch - blank string parameter will return all links.
+ $type = LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT;
+ $request = [$searchtags, $searchterm];
$linkFilter = new LinkFilter($this);
return $linkFilter->filter($type, $request, $casesensitive, $visibility);
$linkFilter = new LinkFilter($this);
return $linkFilter->filter($type, $request, $casesensitive, $visibility);
{
// Implode if array for clean up.
$tags = is_array($tags) ? trim(implode(' ', $tags)) : $tags;
{
// Implode if array for clean up.
$tags = is_array($tags) ? trim(implode(' ', $tags)) : $tags;
+ if ($tags === false) {
+ return $this->filterUntagged($visibility);
+ }
if (empty($tags)) {
return $this->noFilter($visibility);
}
if (empty($tags)) {
return $this->noFilter($visibility);
}
+ /**
+ * Return only links without any tag.
+ *
+ * @param string $visibility return only all/private/public links.
+ *
+ * @return array filtered links.
+ */
+ public function filterUntagged($visibility)
+ {
+ $filtered = [];
+ foreach ($this->links as $key => $link) {
+ if ($visibility !== 'all') {
+ if (! $link['private'] && $visibility === 'private') {
+ continue;
+ } else if ($link['private'] && $visibility === 'public') {
+ continue;
+ }
+ }
+
+ if (empty(trim($link['tags']))) {
+ $filtered[$key] = $link;
+ }
+ }
+
+ return $filtered;
+ }
+
/**
* Returns the list of articles for a given day, chronologically sorted
*
/**
* Returns the list of articles for a given day, chronologically sorted
*
*/
function escape($input)
{
*/
function escape($input)
{
+ if (is_bool($input)) {
+ return $input;
+ }
+
if (is_array($input)) {
$out = array();
foreach($input as $key => $value) {
if (is_array($input)) {
$out = array();
foreach($input as $key => $value) {
function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
{
// Used in templates
function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
{
// Used in templates
- $searchtags = !empty($_GET['searchtags']) ? escape(normalize_spaces($_GET['searchtags'])) : '';
+ if (isset($_GET['searchtags'])) {
+ if (! empty($_GET['searchtags'])) {
+ $searchtags = escape(normalize_spaces($_GET['searchtags']));
+ } else {
+ $searchtags = false;
+ }
+ } else {
+ $searchtags = '';
+ }
$searchterm = !empty($_GET['searchterm']) ? escape(normalize_spaces($_GET['searchterm'])) : '';
// Smallhash filter
$searchterm = !empty($_GET['searchterm']) ? escape(normalize_spaces($_GET['searchterm'])) : '';
// Smallhash filter
} else {
// Filter links according search parameters.
$visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all';
} else {
// Filter links according search parameters.
$visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all';
- $linksToDisplay = $LINKSDB->filterSearch($_GET, false, $visibility);
+ $request = [
+ 'searchtags' => $searchtags,
+ 'searchterm' => $searchterm,
+ ];
+ $linksToDisplay = $LINKSDB->filterSearch($request, false, $visibility);
}
// Compute paging navigation
}
// Compute paging navigation
- $searchtagsUrl = empty($searchtags) ? '' : '&searchtags=' . urlencode($searchtags);
+ $searchtagsUrl = $searchtags === '' ? '' : '&searchtags=' . urlencode($searchtags);
$searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm);
$previous_page_url = '';
if ($i != count($keys)) {
$searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm);
$previous_page_url = '';
if ($i != count($keys)) {
public function testReorderLinksDesc()
{
self::$privateLinkDB->reorder('ASC');
public function testReorderLinksDesc()
{
self::$privateLinkDB->reorder('ASC');
- $linkIds = array(42, 4, 1, 0, 7, 6, 8, 41);
+ $linkIds = array(42, 4, 9, 1, 0, 7, 6, 8, 41);
$cpt = 0;
foreach (self::$privateLinkDB as $key => $value) {
$this->assertEquals($linkIds[$cpt++], $key);
$cpt = 0;
foreach (self::$privateLinkDB as $key => $value) {
$this->assertEquals($linkIds[$cpt++], $key);
count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, ''))
);
count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, ''))
);
+ // Untagged only
+ $this->assertEquals(
+ self::$refDB->countUntaggedLinks(),
+ count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, false))
+ );
+
$this->assertEquals(
ReferenceLinkDB::$NB_LINKS_TOTAL,
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, ''))
$this->assertEquals(
ReferenceLinkDB::$NB_LINKS_TOTAL,
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, ''))
public function testFilterDay()
{
$this->assertEquals(
public function testFilterDay()
{
$this->assertEquals(
count(self::$linkFilter->filter(LinkFilter::$FILTER_DAY, '20121206'))
);
}
count(self::$linkFilter->filter(LinkFilter::$FILTER_DAY, '20121206'))
);
}
+ ReferenceLinkDB::$NB_LINKS_TOTAL - 1,
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '-revolution'))
);
}
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '-revolution'))
);
}
+ ReferenceLinkDB::$NB_LINKS_TOTAL - 1,
count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free'))
);
}
count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free'))
);
}
+ $this->assertEquals(
+ 1,
+ count(self::$linkFilter->filter(
+ LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT,
+ array(false, 'PSR-2')
+ ))
+ );
$this->assertEquals(
1,
count(self::$linkFilter->filter(
$this->assertEquals(
1,
count(self::$linkFilter->filter(
$this->assertEquals($this->refDB->countLinks(), count($data));
// Check order
$this->assertEquals($this->refDB->countLinks(), count($data));
// Check order
- $order = [41, 8, 6, 7, 0, 1, 4, 42];
+ $order = [41, 8, 6, 7, 0, 1, 9, 4, 42];
$cpt = 0;
foreach ($data as $link) {
$this->assertEquals(self::NB_FIELDS_LINK, count($link));
$cpt = 0;
foreach ($data as $link) {
$this->assertEquals(self::NB_FIELDS_LINK, count($link));
$data = json_decode((string) $response->getBody(), true);
$this->assertEquals($this->refDB->countLinks(), count($data));
// Check order
$data = json_decode((string) $response->getBody(), true);
$this->assertEquals($this->refDB->countLinks(), count($data));
// Check order
- $order = [41, 8, 6, 7, 0, 1, 4, 42];
+ $order = [41, 8, 6, 7, 0, 1, 9, 4, 42];
$cpt = 0;
foreach ($data as $link) {
$this->assertEquals(self::NB_FIELDS_LINK, count($link));
$cpt = 0;
foreach ($data as $link) {
$this->assertEquals(self::NB_FIELDS_LINK, count($link));
$this->assertEquals(200, $response->getStatusCode());
$data = json_decode((string) $response->getBody(), true);
$this->assertEquals(200, $response->getStatusCode());
$data = json_decode((string) $response->getBody(), true);
- $this->assertEquals(8, $data['global_counter']);
+ $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, $data['global_counter']);
$this->assertEquals(2, $data['private_counter']);
$this->assertEquals('Shaarli', $data['settings']['title']);
$this->assertEquals('?', $data['settings']['header_link']);
$this->assertEquals(2, $data['private_counter']);
$this->assertEquals('Shaarli', $data['settings']['title']);
$this->assertEquals('?', $data['settings']['header_link']);
$this->assertEquals(200, $response->getStatusCode());
$data = json_decode((string) $response->getBody(), true);
$this->assertEquals(200, $response->getStatusCode());
$data = json_decode((string) $response->getBody(), true);
- $this->assertEquals(8, $data['global_counter']);
+ $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, $data['global_counter']);
$this->assertEquals(2, $data['private_counter']);
$this->assertEquals($title, $data['settings']['title']);
$this->assertEquals($headerLink, $data['settings']['header_link']);
$this->assertEquals(2, $data['private_counter']);
$this->assertEquals($title, $data['settings']['title']);
$this->assertEquals($headerLink, $data['settings']['header_link']);
*/
class ReferenceLinkDB
{
*/
class ReferenceLinkDB
{
- public static $NB_LINKS_TOTAL = 8;
+ public static $NB_LINKS_TOTAL = 9;
private $_links = array();
private $_publicCount = 0;
private $_links = array();
private $_publicCount = 0;
+ $this->addLink(
+ 9,
+ 'PSR-2: Coding Style Guide',
+ 'http://www.php-fig.org/psr/psr-2/',
+ 'This guide extends and expands on PSR-1, the basic coding standard.',
+ 0,
+ DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_152312'),
+ ''
+ );
+
$this->addLink(
8,
'Free as in Freedom 2.0 @website',
$this->addLink(
8,
'Free as in Freedom 2.0 @website',
return $this->_privateCount;
}
return $this->_privateCount;
}
+ /**
+ * Returns the number of links without tag
+ */
+ public function countUntaggedLinks()
+ {
+ $cpt = 0;
+ foreach ($this->_links as $link) {
+ if (empty($link['tags'])) {
+ ++$cpt;
+ }
+ }
+ return $cpt;
+ }
+
public function getLinks()
{
return $this->_links;
public function getLinks()
{
return $this->_links;
<div id="searchcriteria">{'Nothing found.'|t}</div>
</div>
</div>
<div id="searchcriteria">{'Nothing found.'|t}</div>
</div>
</div>
- {elseif="!empty($search_term) or !empty($search_tags) or !empty($visibility)"}
+ {elseif="!empty($search_term) or $search_tags !== '' or !empty($visibility)"}
<div class="pure-g pure-alert pure-alert-success search-result">
<div class="pure-u-2-24"></div>
<div class="pure-u-20-24">
<div class="pure-g pure-alert pure-alert-success search-result">
<div class="pure-u-2-24"></div>
<div class="pure-u-20-24">
<a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times"></i></span></a>
</span>
{/loop}
<a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times"></i></span></a>
</span>
{/loop}
+ {elseif="$search_tags === false"}
+ <span class="label label-tag" title="{'Remove tag'|t}">
+ <a href="?">{'untagged'|t}<span class="remove"><i class="fa fa-times"></i></span></a>
+ </span>
{/if}
{if="!empty($visibility)"}
{'with status'|t}
{/if}
{if="!empty($visibility)"}
{'with status'|t}
{if="count($links)==0"}
<div id="searchcriteria">Nothing found.</div>
{if="count($links)==0"}
<div id="searchcriteria">Nothing found.</div>
- {elseif="!empty($search_term) or !empty($search_tags)"}
+ {elseif="!empty($search_term) or $search_tags !== ''"}
<div id="searchcriteria">
{$result_count} results
{if="!empty($search_term)"}
<div id="searchcriteria">
{$result_count} results
{if="!empty($search_term)"}
<a href="?removetag={function="urlencode($value)"}">{$value} <span class="remove">x</span></a>
</span>
{/loop}
<a href="?removetag={function="urlencode($value)"}">{$value} <span class="remove">x</span></a>
</span>
{/loop}
+ {elseif="$search_tags === false"}
+ <span class="linktag" title="Remove tag">
+ <a href="?">untagged <span class="remove">x</span></a>
+ </span>