]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - actions/noticesearch.php
Merge branch 'nightly' into 'nightly'
[quix0rs-gnu-social.git] / actions / noticesearch.php
1 <?php
2 /**
3  * Notice search action class.
4  *
5  * PHP version 5
6  *
7  * @category Action
8  * @package  StatusNet
9  * @author   Evan Prodromou <evan@status.net>
10  * @author   Robin Millette <millette@status.net>
11  * @author   Sarven Capadisli <csarven@status.net>
12  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
13  * @link     http://status.net/
14  *
15  * StatusNet - the distributed open-source microblogging tool
16  * Copyright (C) 2008, 2009, StatusNet, Inc.
17  *
18  * This program is free software: you can redistribute it and/or modify
19  * it under the terms of the GNU Affero General Public License as published by
20  * the Free Software Foundation, either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU Affero General Public License for more details.
27  *
28  * You should have received a copy of the GNU Affero General Public License
29  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
30  */
31
32 if (!defined('STATUSNET') && !defined('LACONICA')) {
33     exit(1);
34 }
35
36 require_once INSTALLDIR.'/lib/searchaction.php';
37
38 /**
39  * Notice search action class.
40  *
41  * @category Action
42  * @package  StatusNet
43  * @author   Evan Prodromou <evan@status.net>
44  * @author   Robin Millette <millette@status.net>
45  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
46  * @link     http://status.net/
47  * @todo     common parent for people and content search?
48  */
49 class NoticesearchAction extends SearchAction
50 {
51     protected $q = null;
52
53     function prepare(array $args = array())
54     {
55         parent::prepare($args);
56
57         $this->q = $this->trimmed('q');
58
59         // FIXME: very dependent on tag format
60         if (preg_match('/^#([\pL\pN_\-\.]{1,64})/ue', $this->q)) {
61             common_redirect(common_local_url('tag',
62                                              array('tag' => common_canonical_tag(substr($this->q, 1)))),
63                             303);
64         }
65
66         if (!empty($this->q)) {
67
68             $stream  = new SearchNoticeStream($this->q, $this->scoped);
69             $page    = $this->trimmed('page');
70
71             if (empty($page)) {
72                 $page = 1;
73             } else {
74                 $page = (int)$page;
75             }
76
77             $this->notice = $stream->getNotices((($page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1);
78         }
79
80         common_set_returnto($this->selfUrl());
81
82         return true;
83     }
84
85     /**
86      * Get instructions
87      *
88      * @return string instruction text
89      */
90     function getInstructions()
91     {
92         // TRANS: Instructions for Notice search page.
93         // TRANS: %%site.name%% is the name of the StatusNet site.
94         return _('Search for notices on %%site.name%% by their contents. Separate search terms by spaces; they must be 3 characters or more.');
95     }
96
97     /**
98      * Get title
99      *
100      * @return string title
101      */
102     function title()
103     {
104         // TRANS: Title of the page where users can search for notices.
105         return _('Text search');
106     }
107
108     function getFeeds()
109     {
110         $q = $this->trimmed('q');
111
112         if (!$q) {
113             return null;
114         }
115
116         return array(new Feed(Feed::RSS1, common_local_url('noticesearchrss',
117                                                            array('q' => $q)),
118                               // TRANS: Test in RSS notice search.
119                               // TRANS: %1$s is the query, %2$s is the StatusNet site name.
120                               sprintf(_('Search results for "%1$s" on %2$s'),
121                                       $q, common_config('site', 'name'))));
122     }
123
124     /**
125      * Show results
126      *
127      * @param string  $q    search query
128      * @param integer $page page number
129      *
130      * @return void
131      */
132     function showResults($q, $page)
133     {
134         if (Event::handle('StartNoticeSearchShowResults', array($this, $q, $this->notice))) {
135             if ($this->notice->N === 0) {
136                 $this->showEmptyResults($q, $page);
137             } else {
138                 $terms = preg_split('/[\s,]+/', $q);
139                 $nl = new SearchNoticeList($this->notice, $this, $terms);
140                 $cnt = $nl->show();
141                 $this->pagination($page > 1,
142                                   $cnt > NOTICES_PER_PAGE,
143                                   $page,
144                                   'noticesearch',
145                                   array('q' => $q));
146             }
147             Event::handle('EndNoticeSearchShowResults', array($this, $q, $this->notice));
148         }
149     }
150
151     function showEmptyResults($q, $page)
152     {
153             // TRANS: Text for notice search results is the query had no results.
154             $this->element('p', 'error', _('No results.'));
155
156             $this->searchSuggestions($q);
157             if (common_logged_in()) {
158                 // TRANS: Text for logged in users making a query for notices without results.
159                 // TRANS: This message contains a Markdown link.
160                 $message = sprintf(_('Be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q));
161             }
162             else {
163                 // TRANS: Text for not logged in users making a query for notices without results.
164                 // TRANS: This message contains Markdown links.
165                 $message = sprintf(_('Why not [register an account](%%%%action.register%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q));
166             }
167
168             $this->elementStart('div', 'guide');
169             $this->raw(common_markup_to_html($message));
170             $this->elementEnd('div');
171             return;
172     }
173
174     function showScripts()
175     {
176         parent::showScripts();
177         $this->autofocus('q');
178     }
179 }
180
181 class SearchNoticeList extends NoticeList {
182     function __construct($notice, $out=null, $terms)
183     {
184         parent::__construct($notice, $out);
185         $this->terms = $terms;
186     }
187
188     function newListItem(Notice $notice)
189     {
190         return new SearchNoticeListItem($notice, $this->out, $this->terms);
191     }
192 }
193
194 class SearchNoticeListItem extends NoticeListItem {
195     function __construct($notice, $out=null, $terms)
196     {
197         parent::__construct($notice, $out);
198         $this->terms = $terms;
199     }
200
201     function showContent()
202     {
203         // FIXME: URL, image, video, audio
204         $this->out->elementStart('p', array('class' => 'e-content'));
205         $this->out->raw($this->highlight($this->notice->getRendered(), $this->terms));
206         $this->out->elementEnd('p');
207
208     }
209
210     /**
211      * Highlist query terms
212      *
213      * @param string $text  notice text
214      * @param array  $terms terms to highlight
215      *
216      * @return void
217      */
218     function highlight($text, $terms)
219     {
220         /* Highligh search terms */
221         $options = implode('|', array_map('preg_quote', array_map('htmlspecialchars', $terms),
222                                                             array_fill(0, sizeof($terms), '/')));
223         $pattern = "/($options)/i";
224         $result = '';
225
226         /* Divide up into text (highlight me) and tags (don't touch) */
227         $chunks = preg_split('/(<[^>]+>)/', $text, 0, PREG_SPLIT_DELIM_CAPTURE);
228         foreach ($chunks as $i => $chunk) {
229             if ($i % 2 == 1) {
230                 // odd: delimiter (tag)
231                 $result .= $chunk;
232             } else {
233                 // even: freetext between tags
234                 $result .= preg_replace($pattern, '<strong>\\1</strong>', $chunk);
235             }
236         }
237
238         return $result;
239     }
240 }