Merge pull request #841 from ArthurHoaro/feature/search-no-tag
Empty tag search will look for not tagged links
This commit is contained in:
commit
3e395a6bc6
12 changed files with 115 additions and 36 deletions
|
@ -97,6 +97,11 @@ public function __construct($linkDB, $feedType, $serverInfo, $userInput, $isLogg
|
||||||
*/
|
*/
|
||||||
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:
|
// Optionally filter the results:
|
||||||
$linksToDisplay = $this->linkDB->filterSearch($this->userInput);
|
$linksToDisplay = $this->linkDB->filterSearch($this->userInput);
|
||||||
|
|
||||||
|
|
|
@ -423,29 +423,12 @@ public function filterDay($request) {
|
||||||
public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all')
|
public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all')
|
||||||
{
|
{
|
||||||
// Filter link database according to parameters.
|
// Filter link database according to parameters.
|
||||||
$searchtags = !empty($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : '';
|
$searchtags = isset($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : '';
|
||||||
$searchterm = !empty($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : '';
|
$searchterm = isset($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : '';
|
||||||
|
|
||||||
// Search tags + fullsearch.
|
// Search tags + fullsearch - blank string parameter will return all links.
|
||||||
if (! empty($searchtags) && ! empty($searchterm)) {
|
$type = LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT;
|
||||||
$type = LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT;
|
$request = [$searchtags, $searchterm];
|
||||||
$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 = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$linkFilter = new LinkFilter($this);
|
$linkFilter = new LinkFilter($this);
|
||||||
return $linkFilter->filter($type, $request, $casesensitive, $visibility);
|
return $linkFilter->filter($type, $request, $casesensitive, $visibility);
|
||||||
|
|
|
@ -253,6 +253,9 @@ public function filterTags($tags, $casesensitive = false, $visibility = 'all')
|
||||||
{
|
{
|
||||||
// Implode if array for clean up.
|
// Implode if array for clean up.
|
||||||
$tags = is_array($tags) ? trim(implode(' ', $tags)) : $tags;
|
$tags = is_array($tags) ? trim(implode(' ', $tags)) : $tags;
|
||||||
|
if ($tags === false) {
|
||||||
|
return $this->filterUntagged($visibility);
|
||||||
|
}
|
||||||
if (empty($tags)) {
|
if (empty($tags)) {
|
||||||
return $this->noFilter($visibility);
|
return $this->noFilter($visibility);
|
||||||
}
|
}
|
||||||
|
@ -295,6 +298,33 @@ public function filterTags($tags, $casesensitive = false, $visibility = 'all')
|
||||||
return $filtered;
|
return $filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
*
|
*
|
||||||
|
|
|
@ -91,6 +91,10 @@ function endsWith($haystack, $needle, $case = true)
|
||||||
*/
|
*/
|
||||||
function escape($input)
|
function escape($input)
|
||||||
{
|
{
|
||||||
|
if (is_bool($input)) {
|
||||||
|
return $input;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_array($input)) {
|
if (is_array($input)) {
|
||||||
$out = array();
|
$out = array();
|
||||||
foreach($input as $key => $value) {
|
foreach($input as $key => $value) {
|
||||||
|
|
18
index.php
18
index.php
|
@ -1622,7 +1622,15 @@ function($a, $b) { return $a['order'] - $b['order']; }
|
||||||
function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
|
function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
|
||||||
{
|
{
|
||||||
// Used in templates
|
// 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'])) : '';
|
$searchterm = !empty($_GET['searchterm']) ? escape(normalize_spaces($_GET['searchterm'])) : '';
|
||||||
|
|
||||||
// Smallhash filter
|
// Smallhash filter
|
||||||
|
@ -1637,7 +1645,11 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
|
||||||
} else {
|
} else {
|
||||||
// Filter links according search parameters.
|
// Filter links according search parameters.
|
||||||
$visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all';
|
$visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all';
|
||||||
$linksToDisplay = $LINKSDB->filterSearch($_GET, false, $visibility);
|
$request = [
|
||||||
|
'searchtags' => $searchtags,
|
||||||
|
'searchterm' => $searchterm,
|
||||||
|
];
|
||||||
|
$linksToDisplay = $LINKSDB->filterSearch($request, false, $visibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Handle paging.
|
// ---- Handle paging.
|
||||||
|
@ -1684,7 +1696,7 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute paging navigation
|
// Compute paging navigation
|
||||||
$searchtagsUrl = empty($searchtags) ? '' : '&searchtags=' . urlencode($searchtags);
|
$searchtagsUrl = $searchtags === '' ? '' : '&searchtags=' . urlencode($searchtags);
|
||||||
$searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm);
|
$searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm);
|
||||||
$previous_page_url = '';
|
$previous_page_url = '';
|
||||||
if ($i != count($keys)) {
|
if ($i != count($keys)) {
|
||||||
|
|
|
@ -475,7 +475,7 @@ public function testFilterHashInValid()
|
||||||
public function testReorderLinksDesc()
|
public function testReorderLinksDesc()
|
||||||
{
|
{
|
||||||
self::$privateLinkDB->reorder('ASC');
|
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;
|
$cpt = 0;
|
||||||
foreach (self::$privateLinkDB as $key => $value) {
|
foreach (self::$privateLinkDB as $key => $value) {
|
||||||
$this->assertEquals($linkIds[$cpt++], $key);
|
$this->assertEquals($linkIds[$cpt++], $key);
|
||||||
|
|
|
@ -63,6 +63,12 @@ public function testFilter()
|
||||||
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(
|
$this->assertEquals(
|
||||||
ReferenceLinkDB::$NB_LINKS_TOTAL,
|
ReferenceLinkDB::$NB_LINKS_TOTAL,
|
||||||
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, ''))
|
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, ''))
|
||||||
|
@ -146,7 +152,7 @@ public function testFilterUnknownTag()
|
||||||
public function testFilterDay()
|
public function testFilterDay()
|
||||||
{
|
{
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
3,
|
4,
|
||||||
count(self::$linkFilter->filter(LinkFilter::$FILTER_DAY, '20121206'))
|
count(self::$linkFilter->filter(LinkFilter::$FILTER_DAY, '20121206'))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -339,7 +345,7 @@ public function testExcludeSearch()
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
7,
|
ReferenceLinkDB::$NB_LINKS_TOTAL - 1,
|
||||||
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '-revolution'))
|
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '-revolution'))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -399,7 +405,7 @@ public function testTagFilterWithExclusion()
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
7,
|
ReferenceLinkDB::$NB_LINKS_TOTAL - 1,
|
||||||
count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free'))
|
count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free'))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -425,6 +431,13 @@ public function testFilterCrossedSearch()
|
||||||
array('', $terms)
|
array('', $terms)
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
1,
|
||||||
|
count(self::$linkFilter->filter(
|
||||||
|
LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT,
|
||||||
|
array(false, 'PSR-2')
|
||||||
|
))
|
||||||
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
1,
|
1,
|
||||||
count(self::$linkFilter->filter(
|
count(self::$linkFilter->filter(
|
||||||
|
|
|
@ -95,7 +95,7 @@ public function testGetLinks()
|
||||||
$this->assertEquals($this->refDB->countLinks(), count($data));
|
$this->assertEquals($this->refDB->countLinks(), count($data));
|
||||||
|
|
||||||
// Check order
|
// Check order
|
||||||
$order = [41, 8, 6, 7, 0, 1, 4, 42];
|
$order = [41, 8, 6, 7, 0, 1, 9, 4, 42];
|
||||||
$cpt = 0;
|
$cpt = 0;
|
||||||
foreach ($data as $link) {
|
foreach ($data as $link) {
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($link));
|
$this->assertEquals(self::NB_FIELDS_LINK, count($link));
|
||||||
|
@ -164,7 +164,7 @@ public function testGetLinksLimitAll()
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
$data = json_decode((string) $response->getBody(), true);
|
||||||
$this->assertEquals($this->refDB->countLinks(), count($data));
|
$this->assertEquals($this->refDB->countLinks(), count($data));
|
||||||
// Check order
|
// Check order
|
||||||
$order = [41, 8, 6, 7, 0, 1, 4, 42];
|
$order = [41, 8, 6, 7, 0, 1, 9, 4, 42];
|
||||||
$cpt = 0;
|
$cpt = 0;
|
||||||
foreach ($data as $link) {
|
foreach ($data as $link) {
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($link));
|
$this->assertEquals(self::NB_FIELDS_LINK, count($link));
|
||||||
|
|
|
@ -81,7 +81,7 @@ public function testGetInfo()
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
$this->assertEquals(200, $response->getStatusCode());
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
$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(2, $data['private_counter']);
|
||||||
$this->assertEquals('Shaarli', $data['settings']['title']);
|
$this->assertEquals('Shaarli', $data['settings']['title']);
|
||||||
$this->assertEquals('?', $data['settings']['header_link']);
|
$this->assertEquals('?', $data['settings']['header_link']);
|
||||||
|
@ -104,7 +104,7 @@ public function testGetInfo()
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
$this->assertEquals(200, $response->getStatusCode());
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
$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(2, $data['private_counter']);
|
||||||
$this->assertEquals($title, $data['settings']['title']);
|
$this->assertEquals($title, $data['settings']['title']);
|
||||||
$this->assertEquals($headerLink, $data['settings']['header_link']);
|
$this->assertEquals($headerLink, $data['settings']['header_link']);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
class ReferenceLinkDB
|
class ReferenceLinkDB
|
||||||
{
|
{
|
||||||
public static $NB_LINKS_TOTAL = 8;
|
public static $NB_LINKS_TOTAL = 9;
|
||||||
|
|
||||||
private $_links = array();
|
private $_links = array();
|
||||||
private $_publicCount = 0;
|
private $_publicCount = 0;
|
||||||
|
@ -37,6 +37,16 @@ public function __construct()
|
||||||
'ut'
|
'ut'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$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(
|
$this->addLink(
|
||||||
8,
|
8,
|
||||||
'Free as in Freedom 2.0 @website',
|
'Free as in Freedom 2.0 @website',
|
||||||
|
@ -161,6 +171,20 @@ public function countPrivateLinks()
|
||||||
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()
|
public function getLinks()
|
||||||
{
|
{
|
||||||
return $this->_links;
|
return $this->_links;
|
||||||
|
|
|
@ -91,7 +91,7 @@
|
||||||
<div id="searchcriteria">{'Nothing found.'|t}</div>
|
<div id="searchcriteria">{'Nothing found.'|t}</div>
|
||||||
</div>
|
</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-g pure-alert pure-alert-success search-result">
|
||||||
<div class="pure-u-2-24"></div>
|
<div class="pure-u-2-24"></div>
|
||||||
<div class="pure-u-20-24">
|
<div class="pure-u-20-24">
|
||||||
|
@ -107,6 +107,10 @@
|
||||||
<a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times"></i></span></a>
|
<a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times"></i></span></a>
|
||||||
</span>
|
</span>
|
||||||
{/loop}
|
{/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}
|
||||||
{if="!empty($visibility)"}
|
{if="!empty($visibility)"}
|
||||||
{'with status'|t}
|
{'with status'|t}
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
|
|
||||||
{if="count($links)==0"}
|
{if="count($links)==0"}
|
||||||
<div id="searchcriteria">Nothing found.</div>
|
<div id="searchcriteria">Nothing found.</div>
|
||||||
{elseif="!empty($search_term) or !empty($search_tags)"}
|
{elseif="!empty($search_term) or $search_tags !== ''"}
|
||||||
<div id="searchcriteria">
|
<div id="searchcriteria">
|
||||||
{$result_count} results
|
{$result_count} results
|
||||||
{if="!empty($search_term)"}
|
{if="!empty($search_term)"}
|
||||||
|
@ -69,6 +69,10 @@
|
||||||
<a href="?removetag={function="urlencode($value)"}">{$value} <span class="remove">x</span></a>
|
<a href="?removetag={function="urlencode($value)"}">{$value} <span class="remove">x</span></a>
|
||||||
</span>
|
</span>
|
||||||
{/loop}
|
{/loop}
|
||||||
|
{elseif="$search_tags === false"}
|
||||||
|
<span class="linktag" title="Remove tag">
|
||||||
|
<a href="?">untagged <span class="remove">x</span></a>
|
||||||
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
Loading…
Reference in a new issue