ajout de la partie slam dans le dossier web
This commit is contained in:
		
							
								
								
									
										167
									
								
								ap23/web/doku/inc/Ui/Admin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								ap23/web/doku/inc/Ui/Admin.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | ||||
| <?php | ||||
| namespace dokuwiki\Ui; | ||||
|  | ||||
| /** | ||||
|  * Class Admin | ||||
|  * | ||||
|  * Displays the Admin screen | ||||
|  * | ||||
|  * @package dokuwiki\Ui | ||||
|  * @author Andreas Gohr <andi@splitbrain.org> | ||||
|  * @author Håkan Sandell <hakan.sandell@home.se> | ||||
|  */ | ||||
| class Admin extends Ui { | ||||
|  | ||||
|     protected $forAdmins = array('usermanager', 'acl', 'extension', 'config', 'styling'); | ||||
|     protected $forManagers = array('revert', 'popularity'); | ||||
|     /** @var array[] */ | ||||
|     protected $menu; | ||||
|  | ||||
|     /** | ||||
|      * Display the UI element | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function show() { | ||||
|         $this->menu = $this->getPluginList(); | ||||
|         echo '<div class="ui-admin">'; | ||||
|         echo p_locale_xhtml('admin'); | ||||
|         $this->showSecurityCheck(); | ||||
|         $this->showMenu('admin'); | ||||
|         $this->showMenu('manager'); | ||||
|         $this->showVersion(); | ||||
|         $this->showMenu('other'); | ||||
|         echo '</div>'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Show the given menu of available plugins | ||||
|      * | ||||
|      * @param string $type admin|manager|other | ||||
|      */ | ||||
|     protected function showMenu($type) { | ||||
|         if (!$this->menu[$type]) return; | ||||
|  | ||||
|         if ($type === 'other') { | ||||
|             echo p_locale_xhtml('adminplugins'); | ||||
|             $class = 'admin_plugins'; | ||||
|         } else { | ||||
|             $class = 'admin_tasks'; | ||||
|         } | ||||
|  | ||||
|         echo "<ul class=\"$class\">"; | ||||
|         foreach ($this->menu[$type] as $item) { | ||||
|             $this->showMenuItem($item); | ||||
|         } | ||||
|         echo '</ul>'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Display the DokuWiki version | ||||
|      */ | ||||
|     protected function showVersion() { | ||||
|         echo '<div id="admin__version">'; | ||||
|         echo getVersion(); | ||||
|         echo '</div>'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * data security check | ||||
|      * | ||||
|      * simple check if the 'savedir' is relative and accessible when appended to DOKU_URL | ||||
|      * | ||||
|      * it verifies either: | ||||
|      *   'savedir' has been moved elsewhere, or | ||||
|      *   has protection to prevent the webserver serving files from it | ||||
|      */ | ||||
|     protected function showSecurityCheck() { | ||||
|         global $conf; | ||||
|         if(substr($conf['savedir'], 0, 2) !== './') return; | ||||
|         $img = DOKU_URL . $conf['savedir'] . | ||||
|             '/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.png'; | ||||
|         echo '<a style="border:none; float:right;" | ||||
|                 href="http://www.dokuwiki.org/security#web_access_security"> | ||||
|                 <img src="' . $img . '" alt="Your data directory seems to be protected properly." | ||||
|                 onerror="this.parentNode.style.display=\'none\'" /></a>'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Display a single Admin menu item | ||||
|      * | ||||
|      * @param array $item | ||||
|      */ | ||||
|     protected function showMenuItem($item) { | ||||
|         global $ID; | ||||
|         if(blank($item['prompt'])) return; | ||||
|         echo '<li><div class="li">'; | ||||
|         echo '<a href="' . wl($ID, 'do=admin&page=' . $item['plugin']) . '">'; | ||||
|         echo '<span class="icon">'; | ||||
|         echo inlineSVG($item['icon']); | ||||
|         echo '</span>'; | ||||
|         echo '<span class="prompt">'; | ||||
|         echo $item['prompt']; | ||||
|         echo '</span>'; | ||||
|         echo '</a>'; | ||||
|         echo '</div></li>'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Build  list of admin functions from the plugins that handle them | ||||
|      * | ||||
|      * Checks the current permissions to decide on manager or admin plugins | ||||
|      * | ||||
|      * @return array list of plugins with their properties | ||||
|      */ | ||||
|     protected function getPluginList() { | ||||
|         global $conf; | ||||
|  | ||||
|         $pluginlist = plugin_list('admin'); | ||||
|         $menu = ['admin' => [], 'manager' => [], 'other' => []]; | ||||
|  | ||||
|         foreach($pluginlist as $p) { | ||||
|             /** @var \dokuwiki\Extension\AdminPlugin $obj */ | ||||
|             if(($obj = plugin_load('admin', $p)) === null) continue; | ||||
|  | ||||
|             // check permissions | ||||
|             if (!$obj->isAccessibleByCurrentUser()) continue; | ||||
|  | ||||
|             if (in_array($p, $this->forAdmins, true)) { | ||||
|                 $type = 'admin'; | ||||
|             } elseif (in_array($p, $this->forManagers, true)){ | ||||
|                 $type = 'manager'; | ||||
|             } else { | ||||
|                 $type = 'other'; | ||||
|             } | ||||
|  | ||||
|             $menu[$type][$p] = array( | ||||
|                 'plugin' => $p, | ||||
|                 'prompt' => $obj->getMenuText($conf['lang']), | ||||
|                 'icon' => $obj->getMenuIcon(), | ||||
|                 'sort' => $obj->getMenuSort(), | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         // sort by name, then sort | ||||
|         uasort($menu['admin'], [$this, 'menuSort']); | ||||
|         uasort($menu['manager'], [$this, 'menuSort']); | ||||
|         uasort($menu['other'], [$this, 'menuSort']); | ||||
|  | ||||
|         return $menu; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Custom sorting for admin menu | ||||
|      * | ||||
|      * We sort alphabetically first, then by sort value | ||||
|      * | ||||
|      * @param array $a | ||||
|      * @param array $b | ||||
|      * @return int | ||||
|      */ | ||||
|     protected function menuSort($a, $b) { | ||||
|         $strcmp = strcasecmp($a['prompt'], $b['prompt']); | ||||
|         if($strcmp != 0) return $strcmp; | ||||
|         if($a['sort'] === $b['sort']) return 0; | ||||
|         return ($a['sort'] < $b['sort']) ? -1 : 1; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										647
									
								
								ap23/web/doku/inc/Ui/Search.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										647
									
								
								ap23/web/doku/inc/Ui/Search.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,647 @@ | ||||
| <?php | ||||
|  | ||||
| namespace dokuwiki\Ui; | ||||
|  | ||||
| use dokuwiki\Extension\Event; | ||||
| use dokuwiki\Form\Form; | ||||
|  | ||||
| class Search extends Ui | ||||
| { | ||||
|     protected $query; | ||||
|     protected $parsedQuery; | ||||
|     protected $searchState; | ||||
|     protected $pageLookupResults = array(); | ||||
|     protected $fullTextResults = array(); | ||||
|     protected $highlight = array(); | ||||
|  | ||||
|     /** | ||||
|      * Search constructor. | ||||
|      * | ||||
|      * @param array $pageLookupResults pagename lookup results in the form [pagename => pagetitle] | ||||
|      * @param array $fullTextResults fulltext search results in the form [pagename => #hits] | ||||
|      * @param array $highlight  array of strings to be highlighted | ||||
|      */ | ||||
|     public function __construct(array $pageLookupResults, array $fullTextResults, $highlight) | ||||
|     { | ||||
|         global $QUERY; | ||||
|         $Indexer = idx_get_indexer(); | ||||
|  | ||||
|         $this->query = $QUERY; | ||||
|         $this->parsedQuery = ft_queryParser($Indexer, $QUERY); | ||||
|         $this->searchState = new SearchState($this->parsedQuery); | ||||
|  | ||||
|         $this->pageLookupResults = $pageLookupResults; | ||||
|         $this->fullTextResults = $fullTextResults; | ||||
|         $this->highlight = $highlight; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * display the search result | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function show() | ||||
|     { | ||||
|         $searchHTML = ''; | ||||
|  | ||||
|         $searchHTML .= $this->getSearchIntroHTML($this->query); | ||||
|  | ||||
|         $searchHTML .= $this->getSearchFormHTML($this->query); | ||||
|  | ||||
|         $searchHTML .= $this->getPageLookupHTML($this->pageLookupResults); | ||||
|  | ||||
|         $searchHTML .= $this->getFulltextResultsHTML($this->fullTextResults, $this->highlight); | ||||
|  | ||||
|         echo $searchHTML; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get a form which can be used to adjust/refine the search | ||||
|      * | ||||
|      * @param string $query | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function getSearchFormHTML($query) | ||||
|     { | ||||
|         global $lang, $ID, $INPUT; | ||||
|  | ||||
|         $searchForm = (new Form(['method' => 'get'], true))->addClass('search-results-form'); | ||||
|         $searchForm->setHiddenField('do', 'search'); | ||||
|         $searchForm->setHiddenField('id', $ID); | ||||
|         $searchForm->setHiddenField('sf', '1'); | ||||
|         if ($INPUT->has('min')) { | ||||
|             $searchForm->setHiddenField('min', $INPUT->str('min')); | ||||
|         } | ||||
|         if ($INPUT->has('max')) { | ||||
|             $searchForm->setHiddenField('max', $INPUT->str('max')); | ||||
|         } | ||||
|         if ($INPUT->has('srt')) { | ||||
|             $searchForm->setHiddenField('srt', $INPUT->str('srt')); | ||||
|         } | ||||
|         $searchForm->addFieldsetOpen()->addClass('search-form'); | ||||
|         $searchForm->addTextInput('q')->val($query)->useInput(false); | ||||
|         $searchForm->addButton('', $lang['btn_search'])->attr('type', 'submit'); | ||||
|  | ||||
|         $this->addSearchAssistanceElements($searchForm); | ||||
|  | ||||
|         $searchForm->addFieldsetClose(); | ||||
|  | ||||
|         Event::createAndTrigger('FORM_SEARCH_OUTPUT', $searchForm); | ||||
|  | ||||
|         return $searchForm->toHTML(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add elements to adjust how the results are sorted | ||||
|      * | ||||
|      * @param Form $searchForm | ||||
|      */ | ||||
|     protected function addSortTool(Form $searchForm) | ||||
|     { | ||||
|         global $INPUT, $lang; | ||||
|  | ||||
|         $options = [ | ||||
|             'hits' => [ | ||||
|                 'label' => $lang['search_sort_by_hits'], | ||||
|                 'sort' => '', | ||||
|             ], | ||||
|             'mtime' => [ | ||||
|                 'label' => $lang['search_sort_by_mtime'], | ||||
|                 'sort' => 'mtime', | ||||
|             ], | ||||
|         ]; | ||||
|         $activeOption = 'hits'; | ||||
|  | ||||
|         if ($INPUT->str('srt') === 'mtime') { | ||||
|             $activeOption = 'mtime'; | ||||
|         } | ||||
|  | ||||
|         $searchForm->addTagOpen('div')->addClass('toggle')->attr('aria-haspopup', 'true'); | ||||
|         // render current | ||||
|         $currentWrapper = $searchForm->addTagOpen('div')->addClass('current'); | ||||
|         if ($activeOption !== 'hits') { | ||||
|             $currentWrapper->addClass('changed'); | ||||
|         } | ||||
|         $searchForm->addHTML($options[$activeOption]['label']); | ||||
|         $searchForm->addTagClose('div'); | ||||
|  | ||||
|         // render options list | ||||
|         $searchForm->addTagOpen('ul')->attr('aria-expanded', 'false'); | ||||
|  | ||||
|         foreach ($options as $key => $option) { | ||||
|             $listItem = $searchForm->addTagOpen('li'); | ||||
|  | ||||
|             if ($key === $activeOption) { | ||||
|                 $listItem->addClass('active'); | ||||
|                 $searchForm->addHTML($option['label']); | ||||
|             } else { | ||||
|                 $link = $this->searchState->withSorting($option['sort'])->getSearchLink($option['label']); | ||||
|                 $searchForm->addHTML($link); | ||||
|             } | ||||
|             $searchForm->addTagClose('li'); | ||||
|         } | ||||
|         $searchForm->addTagClose('ul'); | ||||
|  | ||||
|         $searchForm->addTagClose('div'); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Check if the query is simple enough to modify its namespace limitations without breaking the rest of the query | ||||
|      * | ||||
|      * @param array $parsedQuery | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function isNamespaceAssistanceAvailable(array $parsedQuery) { | ||||
|         if (preg_match('/[\(\)\|]/', $parsedQuery['query']) === 1) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Check if the query is simple enough to modify the fragment search behavior without breaking the rest of the query | ||||
|      * | ||||
|      * @param array $parsedQuery | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     protected function isFragmentAssistanceAvailable(array $parsedQuery) { | ||||
|         if (preg_match('/[\(\)\|]/', $parsedQuery['query']) === 1) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if (!empty($parsedQuery['phrases'])) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add the elements to be used for search assistance | ||||
|      * | ||||
|      * @param Form $searchForm | ||||
|      */ | ||||
|     protected function addSearchAssistanceElements(Form $searchForm) | ||||
|     { | ||||
|         $searchForm->addTagOpen('div') | ||||
|             ->addClass('advancedOptions') | ||||
|             ->attr('style', 'display: none;') | ||||
|             ->attr('aria-hidden', 'true'); | ||||
|  | ||||
|         $this->addFragmentBehaviorLinks($searchForm); | ||||
|         $this->addNamespaceSelector($searchForm); | ||||
|         $this->addDateSelector($searchForm); | ||||
|         $this->addSortTool($searchForm); | ||||
|  | ||||
|         $searchForm->addTagClose('div'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      *  Add the elements to adjust the fragment search behavior | ||||
|      * | ||||
|      * @param Form $searchForm | ||||
|      */ | ||||
|     protected function addFragmentBehaviorLinks(Form $searchForm) | ||||
|     { | ||||
|         if (!$this->isFragmentAssistanceAvailable($this->parsedQuery)) { | ||||
|             return; | ||||
|         } | ||||
|         global $lang; | ||||
|  | ||||
|         $options = [ | ||||
|             'exact' => [ | ||||
|                 'label' => $lang['search_exact_match'], | ||||
|                 'and' => array_map(function ($term) { | ||||
|                     return trim($term, '*'); | ||||
|                 }, $this->parsedQuery['and']), | ||||
|                 'not' => array_map(function ($term) { | ||||
|                     return trim($term, '*'); | ||||
|                 }, $this->parsedQuery['not']), | ||||
|             ], | ||||
|             'starts' => [ | ||||
|                 'label' => $lang['search_starts_with'], | ||||
|                 'and' => array_map(function ($term) { | ||||
|                     return trim($term, '*') . '*'; | ||||
|                 }, $this->parsedQuery['and']), | ||||
|                 'not' => array_map(function ($term) { | ||||
|                     return trim($term, '*') . '*'; | ||||
|                 }, $this->parsedQuery['not']), | ||||
|             ], | ||||
|             'ends' => [ | ||||
|                 'label' => $lang['search_ends_with'], | ||||
|                 'and' => array_map(function ($term) { | ||||
|                     return '*' . trim($term, '*'); | ||||
|                 }, $this->parsedQuery['and']), | ||||
|                 'not' => array_map(function ($term) { | ||||
|                     return '*' . trim($term, '*'); | ||||
|                 }, $this->parsedQuery['not']), | ||||
|             ], | ||||
|             'contains' => [ | ||||
|                 'label' => $lang['search_contains'], | ||||
|                 'and' => array_map(function ($term) { | ||||
|                     return '*' . trim($term, '*') . '*'; | ||||
|                 }, $this->parsedQuery['and']), | ||||
|                 'not' => array_map(function ($term) { | ||||
|                     return '*' . trim($term, '*') . '*'; | ||||
|                 }, $this->parsedQuery['not']), | ||||
|             ] | ||||
|         ]; | ||||
|  | ||||
|         // detect current | ||||
|         $activeOption = 'custom'; | ||||
|         foreach ($options as $key => $option) { | ||||
|             if ($this->parsedQuery['and'] === $option['and']) { | ||||
|                 $activeOption = $key; | ||||
|             } | ||||
|         } | ||||
|         if ($activeOption === 'custom') { | ||||
|             $options = array_merge(['custom' => [ | ||||
|                 'label' => $lang['search_custom_match'], | ||||
|             ]], $options); | ||||
|         } | ||||
|  | ||||
|         $searchForm->addTagOpen('div')->addClass('toggle')->attr('aria-haspopup', 'true'); | ||||
|         // render current | ||||
|         $currentWrapper = $searchForm->addTagOpen('div')->addClass('current'); | ||||
|         if ($activeOption !== 'exact') { | ||||
|             $currentWrapper->addClass('changed'); | ||||
|         } | ||||
|         $searchForm->addHTML($options[$activeOption]['label']); | ||||
|         $searchForm->addTagClose('div'); | ||||
|  | ||||
|         // render options list | ||||
|         $searchForm->addTagOpen('ul')->attr('aria-expanded', 'false'); | ||||
|  | ||||
|         foreach ($options as $key => $option) { | ||||
|             $listItem = $searchForm->addTagOpen('li'); | ||||
|  | ||||
|             if ($key === $activeOption) { | ||||
|                 $listItem->addClass('active'); | ||||
|                 $searchForm->addHTML($option['label']); | ||||
|             } else { | ||||
|                 $link = $this->searchState | ||||
|                     ->withFragments($option['and'], $option['not']) | ||||
|                     ->getSearchLink($option['label']) | ||||
|                 ; | ||||
|                 $searchForm->addHTML($link); | ||||
|             } | ||||
|             $searchForm->addTagClose('li'); | ||||
|         } | ||||
|         $searchForm->addTagClose('ul'); | ||||
|  | ||||
|         $searchForm->addTagClose('div'); | ||||
|  | ||||
|         // render options list | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add the elements for the namespace selector | ||||
|      * | ||||
|      * @param Form $searchForm | ||||
|      */ | ||||
|     protected function addNamespaceSelector(Form $searchForm) | ||||
|     { | ||||
|         if (!$this->isNamespaceAssistanceAvailable($this->parsedQuery)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         global $lang; | ||||
|  | ||||
|         $baseNS = empty($this->parsedQuery['ns']) ? '' : $this->parsedQuery['ns'][0]; | ||||
|         $extraNS = $this->getAdditionalNamespacesFromResults($baseNS); | ||||
|  | ||||
|         $searchForm->addTagOpen('div')->addClass('toggle')->attr('aria-haspopup', 'true'); | ||||
|         // render current | ||||
|         $currentWrapper = $searchForm->addTagOpen('div')->addClass('current'); | ||||
|         if ($baseNS) { | ||||
|             $currentWrapper->addClass('changed'); | ||||
|             $searchForm->addHTML('@' . $baseNS); | ||||
|         } else { | ||||
|             $searchForm->addHTML($lang['search_any_ns']); | ||||
|         } | ||||
|         $searchForm->addTagClose('div'); | ||||
|  | ||||
|         // render options list | ||||
|         $searchForm->addTagOpen('ul')->attr('aria-expanded', 'false'); | ||||
|  | ||||
|         $listItem = $searchForm->addTagOpen('li'); | ||||
|         if ($baseNS) { | ||||
|             $listItem->addClass('active'); | ||||
|             $link = $this->searchState->withNamespace('')->getSearchLink($lang['search_any_ns']); | ||||
|             $searchForm->addHTML($link); | ||||
|         } else { | ||||
|             $searchForm->addHTML($lang['search_any_ns']); | ||||
|         } | ||||
|         $searchForm->addTagClose('li'); | ||||
|  | ||||
|         foreach ($extraNS as $ns => $count) { | ||||
|             $listItem = $searchForm->addTagOpen('li'); | ||||
|             $label = $ns . ($count ? " <bdi>($count)</bdi>" : ''); | ||||
|  | ||||
|             if ($ns === $baseNS) { | ||||
|                 $listItem->addClass('active'); | ||||
|                 $searchForm->addHTML($label); | ||||
|             } else { | ||||
|                 $link = $this->searchState->withNamespace($ns)->getSearchLink($label); | ||||
|                 $searchForm->addHTML($link); | ||||
|             } | ||||
|             $searchForm->addTagClose('li'); | ||||
|         } | ||||
|         $searchForm->addTagClose('ul'); | ||||
|  | ||||
|         $searchForm->addTagClose('div'); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Parse the full text results for their top namespaces below the given base namespace | ||||
|      * | ||||
|      * @param string $baseNS the namespace within which was searched, empty string for root namespace | ||||
|      * | ||||
|      * @return array an associative array with namespace => #number of found pages, sorted descending | ||||
|      */ | ||||
|     protected function getAdditionalNamespacesFromResults($baseNS) | ||||
|     { | ||||
|         $namespaces = []; | ||||
|         $baseNSLength = strlen($baseNS); | ||||
|         foreach ($this->fullTextResults as $page => $numberOfHits) { | ||||
|             $namespace = getNS($page); | ||||
|             if (!$namespace) { | ||||
|                 continue; | ||||
|             } | ||||
|             if ($namespace === $baseNS) { | ||||
|                 continue; | ||||
|             } | ||||
|             $firstColon = strpos((string)$namespace, ':', $baseNSLength + 1) ?: strlen($namespace); | ||||
|             $subtopNS = substr($namespace, 0, $firstColon); | ||||
|             if (empty($namespaces[$subtopNS])) { | ||||
|                 $namespaces[$subtopNS] = 0; | ||||
|             } | ||||
|             $namespaces[$subtopNS] += 1; | ||||
|         } | ||||
|         ksort($namespaces); | ||||
|         arsort($namespaces); | ||||
|         return $namespaces; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @ToDo: custom date input | ||||
|      * | ||||
|      * @param Form $searchForm | ||||
|      */ | ||||
|     protected function addDateSelector(Form $searchForm) | ||||
|     { | ||||
|         global $INPUT, $lang; | ||||
|  | ||||
|         $options = [ | ||||
|             'any' => [ | ||||
|                 'before' => false, | ||||
|                 'after' => false, | ||||
|                 'label' => $lang['search_any_time'], | ||||
|             ], | ||||
|             'week' => [ | ||||
|                 'before' => false, | ||||
|                 'after' => '1 week ago', | ||||
|                 'label' => $lang['search_past_7_days'], | ||||
|             ], | ||||
|             'month' => [ | ||||
|                 'before' => false, | ||||
|                 'after' => '1 month ago', | ||||
|                 'label' => $lang['search_past_month'], | ||||
|             ], | ||||
|             'year' => [ | ||||
|                 'before' => false, | ||||
|                 'after' => '1 year ago', | ||||
|                 'label' => $lang['search_past_year'], | ||||
|             ], | ||||
|         ]; | ||||
|         $activeOption = 'any'; | ||||
|         foreach ($options as $key => $option) { | ||||
|             if ($INPUT->str('min') === $option['after']) { | ||||
|                 $activeOption = $key; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         $searchForm->addTagOpen('div')->addClass('toggle')->attr('aria-haspopup', 'true'); | ||||
|         // render current | ||||
|         $currentWrapper = $searchForm->addTagOpen('div')->addClass('current'); | ||||
|         if ($INPUT->has('max') || $INPUT->has('min')) { | ||||
|             $currentWrapper->addClass('changed'); | ||||
|         } | ||||
|         $searchForm->addHTML($options[$activeOption]['label']); | ||||
|         $searchForm->addTagClose('div'); | ||||
|  | ||||
|         // render options list | ||||
|         $searchForm->addTagOpen('ul')->attr('aria-expanded', 'false'); | ||||
|  | ||||
|         foreach ($options as $key => $option) { | ||||
|             $listItem = $searchForm->addTagOpen('li'); | ||||
|  | ||||
|             if ($key === $activeOption) { | ||||
|                 $listItem->addClass('active'); | ||||
|                 $searchForm->addHTML($option['label']); | ||||
|             } else { | ||||
|                 $link = $this->searchState | ||||
|                     ->withTimeLimitations($option['after'], $option['before']) | ||||
|                     ->getSearchLink($option['label']) | ||||
|                 ; | ||||
|                 $searchForm->addHTML($link); | ||||
|             } | ||||
|             $searchForm->addTagClose('li'); | ||||
|         } | ||||
|         $searchForm->addTagClose('ul'); | ||||
|  | ||||
|         $searchForm->addTagClose('div'); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Build the intro text for the search page | ||||
|      * | ||||
|      * @param string $query the search query | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function getSearchIntroHTML($query) | ||||
|     { | ||||
|         global $lang; | ||||
|  | ||||
|         $intro = p_locale_xhtml('searchpage'); | ||||
|  | ||||
|         $queryPagename = $this->createPagenameFromQuery($this->parsedQuery); | ||||
|         $createQueryPageLink = html_wikilink($queryPagename . '?do=edit', $queryPagename); | ||||
|  | ||||
|         $pagecreateinfo = ''; | ||||
|         if (auth_quickaclcheck($queryPagename) >= AUTH_CREATE) { | ||||
|             $pagecreateinfo = sprintf($lang['searchcreatepage'], $createQueryPageLink); | ||||
|         } | ||||
|         $intro = str_replace( | ||||
|             array('@QUERY@', '@SEARCH@', '@CREATEPAGEINFO@'), | ||||
|             array(hsc(rawurlencode($query)), hsc($query), $pagecreateinfo), | ||||
|             $intro | ||||
|         ); | ||||
|  | ||||
|         return $intro; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create a pagename based the parsed search query | ||||
|      * | ||||
|      * @param array $parsedQuery | ||||
|      * | ||||
|      * @return string pagename constructed from the parsed query | ||||
|      */ | ||||
|     public function createPagenameFromQuery($parsedQuery) | ||||
|     { | ||||
|         $cleanedQuery = cleanID($parsedQuery['query']); // already strtolowered | ||||
|         if ($cleanedQuery === \dokuwiki\Utf8\PhpString::strtolower($parsedQuery['query'])) { | ||||
|             return ':' . $cleanedQuery; | ||||
|         } | ||||
|         $pagename = ''; | ||||
|         if (!empty($parsedQuery['ns'])) { | ||||
|             $pagename .= ':' . cleanID($parsedQuery['ns'][0]); | ||||
|         } | ||||
|         $pagename .= ':' . cleanID(implode(' ' , $parsedQuery['highlight'])); | ||||
|         return $pagename; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Build HTML for a list of pages with matching pagenames | ||||
|      * | ||||
|      * @param array $data search results | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function getPageLookupHTML($data) | ||||
|     { | ||||
|         if (empty($data)) { | ||||
|             return ''; | ||||
|         } | ||||
|  | ||||
|         global $lang; | ||||
|  | ||||
|         $html = '<div class="search_quickresult">'; | ||||
|         $html .= '<h2>' . $lang['quickhits'] . ':</h2>'; | ||||
|         $html .= '<ul class="search_quickhits">'; | ||||
|         foreach ($data as $id => $title) { | ||||
|             $name = null; | ||||
|             if (!useHeading('navigation') && $ns = getNS($id)) { | ||||
|                 $name = shorten(noNS($id), ' (' . $ns . ')', 30); | ||||
|             } | ||||
|             $link = html_wikilink(':' . $id, $name); | ||||
|             $eventData = [ | ||||
|                 'listItemContent' => [$link], | ||||
|                 'page' => $id, | ||||
|             ]; | ||||
|             Event::createAndTrigger('SEARCH_RESULT_PAGELOOKUP', $eventData); | ||||
|             $html .= '<li>' . implode('', $eventData['listItemContent']) . '</li>'; | ||||
|         } | ||||
|         $html .= '</ul> '; | ||||
|         //clear float (see http://www.complexspiral.com/publications/containing-floats/) | ||||
|         $html .= '<div class="clearer"></div>'; | ||||
|         $html .= '</div>'; | ||||
|  | ||||
|         return $html; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Build HTML for fulltext search results or "no results" message | ||||
|      * | ||||
|      * @param array $data      the results of the fulltext search | ||||
|      * @param array $highlight the terms to be highlighted in the results | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     protected function getFulltextResultsHTML($data, $highlight) | ||||
|     { | ||||
|         global $lang; | ||||
|  | ||||
|         if (empty($data)) { | ||||
|             return '<div class="nothing">' . $lang['nothingfound'] . '</div>'; | ||||
|         } | ||||
|  | ||||
|         $html = '<div class="search_fulltextresult">'; | ||||
|         $html .= '<h2>' . $lang['search_fullresults'] . ':</h2>'; | ||||
|  | ||||
|         $html .= '<dl class="search_results">'; | ||||
|         $num = 0; | ||||
|         $position = 0; | ||||
|  | ||||
|         foreach ($data as $id => $cnt) { | ||||
|             $position += 1; | ||||
|             $resultLink = html_wikilink(':' . $id, null, $highlight); | ||||
|  | ||||
|             $resultHeader = [$resultLink]; | ||||
|  | ||||
|  | ||||
|             $restrictQueryToNSLink = $this->restrictQueryToNSLink(getNS($id)); | ||||
|             if ($restrictQueryToNSLink) { | ||||
|                 $resultHeader[] = $restrictQueryToNSLink; | ||||
|             } | ||||
|  | ||||
|             $resultBody = []; | ||||
|             $mtime = filemtime(wikiFN($id)); | ||||
|             $lastMod = '<span class="lastmod">' . $lang['lastmod'] . '</span> '; | ||||
|             $lastMod .= '<time datetime="' . date_iso8601($mtime) . '" title="' . dformat($mtime) . '">' . | ||||
|                 dformat($mtime, '%f') . | ||||
|                 '</time>'; | ||||
|             $resultBody['meta'] = $lastMod; | ||||
|             if ($cnt !== 0) { | ||||
|                 $num++; | ||||
|                 $hits = '<span class="hits">' . $cnt . ' ' . $lang['hits'] . '</span>, '; | ||||
|                 $resultBody['meta'] = $hits . $resultBody['meta']; | ||||
|                 if ($num <= FT_SNIPPET_NUMBER) { // create snippets for the first number of matches only | ||||
|                     $resultBody['snippet'] = ft_snippet($id, $highlight); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             $eventData = [ | ||||
|                 'resultHeader' => $resultHeader, | ||||
|                 'resultBody' => $resultBody, | ||||
|                 'page' => $id, | ||||
|                 'position' => $position, | ||||
|             ]; | ||||
|             Event::createAndTrigger('SEARCH_RESULT_FULLPAGE', $eventData); | ||||
|             $html .= '<div class="search_fullpage_result">'; | ||||
|             $html .= '<dt>' . implode(' ', $eventData['resultHeader']) . '</dt>'; | ||||
|             foreach ($eventData['resultBody'] as $class => $htmlContent) { | ||||
|                 $html .= "<dd class=\"$class\">$htmlContent</dd>"; | ||||
|             } | ||||
|             $html .= '</div>'; | ||||
|         } | ||||
|         $html .= '</dl>'; | ||||
|  | ||||
|         $html .= '</div>'; | ||||
|  | ||||
|         return $html; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * create a link to restrict the current query to a namespace | ||||
|      * | ||||
|      * @param false|string $ns the namespace to which to restrict the query | ||||
|      * | ||||
|      * @return false|string | ||||
|      */ | ||||
|     protected function restrictQueryToNSLink($ns) | ||||
|     { | ||||
|         if (!$ns) { | ||||
|             return false; | ||||
|         } | ||||
|         if (!$this->isNamespaceAssistanceAvailable($this->parsedQuery)) { | ||||
|             return false; | ||||
|         } | ||||
|         if (!empty($this->parsedQuery['ns']) && $this->parsedQuery['ns'][0] === $ns) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $name = '@' . $ns; | ||||
|         return $this->searchState->withNamespace($ns)->getSearchLink($name); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										141
									
								
								ap23/web/doku/inc/Ui/SearchState.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								ap23/web/doku/inc/Ui/SearchState.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| <?php | ||||
|  | ||||
| namespace dokuwiki\Ui; | ||||
|  | ||||
| class SearchState | ||||
| { | ||||
|     /** | ||||
|      * @var array | ||||
|      */ | ||||
|     protected $parsedQuery = []; | ||||
|  | ||||
|     /** | ||||
|      * SearchState constructor. | ||||
|      * | ||||
|      * @param array $parsedQuery | ||||
|      */ | ||||
|     public function __construct(array $parsedQuery) | ||||
|     { | ||||
|         global $INPUT; | ||||
|  | ||||
|         $this->parsedQuery = $parsedQuery; | ||||
|         if (!isset($parsedQuery['after'])) { | ||||
|             $this->parsedQuery['after'] = $INPUT->str('min'); | ||||
|         } | ||||
|         if (!isset($parsedQuery['before'])) { | ||||
|             $this->parsedQuery['before'] = $INPUT->str('max'); | ||||
|         } | ||||
|         if (!isset($parsedQuery['sort'])) { | ||||
|             $this->parsedQuery['sort'] = $INPUT->str('srt'); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get a search state for the current search limited to a new namespace | ||||
|      * | ||||
|      * @param string $ns the namespace to which to limit the search, falsy to remove the limitation | ||||
|      * @param array  $notns | ||||
|      * | ||||
|      * @return SearchState | ||||
|      */ | ||||
|     public function withNamespace($ns, array $notns = []) | ||||
|     { | ||||
|         $parsedQuery = $this->parsedQuery; | ||||
|         $parsedQuery['ns'] = $ns ? [$ns] : []; | ||||
|         $parsedQuery['notns'] = $notns; | ||||
|  | ||||
|         return new SearchState($parsedQuery); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get a search state for the current search with new search fragments and optionally phrases | ||||
|      * | ||||
|      * @param array $and | ||||
|      * @param array $not | ||||
|      * @param array $phrases | ||||
|      * | ||||
|      * @return SearchState | ||||
|      */ | ||||
|     public function withFragments(array $and, array $not, array $phrases = []) | ||||
|     { | ||||
|         $parsedQuery = $this->parsedQuery; | ||||
|         $parsedQuery['and'] = $and; | ||||
|         $parsedQuery['not'] = $not; | ||||
|         $parsedQuery['phrases'] = $phrases; | ||||
|  | ||||
|         return new SearchState($parsedQuery); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get a search state for the current search with with adjusted time limitations | ||||
|      * | ||||
|      * @param $after | ||||
|      * @param $before | ||||
|      * | ||||
|      * @return SearchState | ||||
|      */ | ||||
|     public function withTimeLimitations($after, $before) | ||||
|     { | ||||
|         $parsedQuery = $this->parsedQuery; | ||||
|         $parsedQuery['after'] = $after; | ||||
|         $parsedQuery['before'] = $before; | ||||
|  | ||||
|         return new SearchState($parsedQuery); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get a search state for the current search with adjusted sort preference | ||||
|      * | ||||
|      * @param $sort | ||||
|      * | ||||
|      * @return SearchState | ||||
|      */ | ||||
|     public function withSorting($sort) | ||||
|     { | ||||
|         $parsedQuery = $this->parsedQuery; | ||||
|         $parsedQuery['sort'] = $sort; | ||||
|  | ||||
|         return new SearchState($parsedQuery); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get a link that represents the current search state | ||||
|      * | ||||
|      * Note that this represents only a simplified version of the search state. | ||||
|      * Grouping with braces and "OR" conditions are not supported. | ||||
|      * | ||||
|      * @param $label | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     public function getSearchLink($label) | ||||
|     { | ||||
|         global $ID, $conf; | ||||
|         $parsedQuery = $this->parsedQuery; | ||||
|  | ||||
|         $tagAttributes = [ | ||||
|             'target' => $conf['target']['wiki'], | ||||
|         ]; | ||||
|  | ||||
|         $newQuery = ft_queryUnparser_simple( | ||||
|             $parsedQuery['and'], | ||||
|             $parsedQuery['not'], | ||||
|             $parsedQuery['phrases'], | ||||
|             $parsedQuery['ns'], | ||||
|             $parsedQuery['notns'] | ||||
|         ); | ||||
|         $hrefAttributes = ['do' => 'search', 'sf' => '1', 'q' => $newQuery]; | ||||
|         if ($parsedQuery['after']) { | ||||
|             $hrefAttributes['min'] = $parsedQuery['after']; | ||||
|         } | ||||
|         if ($parsedQuery['before']) { | ||||
|             $hrefAttributes['max'] = $parsedQuery['before']; | ||||
|         } | ||||
|         if ($parsedQuery['sort']) { | ||||
|             $hrefAttributes['srt'] = $parsedQuery['sort']; | ||||
|         } | ||||
|  | ||||
|         $href = wl($ID, $hrefAttributes, false, '&'); | ||||
|         return "<a href='$href' " . buildAttributes($tagAttributes, true) . ">$label</a>"; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										20
									
								
								ap23/web/doku/inc/Ui/Ui.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								ap23/web/doku/inc/Ui/Ui.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| <?php | ||||
| namespace dokuwiki\Ui; | ||||
|  | ||||
| /** | ||||
|  * Class Ui | ||||
|  * | ||||
|  * Abstract base class for all DokuWiki screens | ||||
|  * | ||||
|  * @package dokuwiki\Ui | ||||
|  */ | ||||
| abstract class Ui { | ||||
|  | ||||
|     /** | ||||
|      * Display the UI element | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     abstract public function show(); | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user