diff --git a/action.php b/action.php index 9f8a1e0..83bee92 100644 --- a/action.php +++ b/action.php @@ -7,7 +7,7 @@ class action_plugin_pagequery extends DokuWiki_Action_Plugin { /** * Register the eventhandlers */ - function register(&$controller) { + function register(Doku_Event_Handler $controller) { $controller->register_hook('TOOLBAR_DEFINE', 'AFTER', $this, 'insert_button', array ()); } diff --git a/inc/pagequery.php b/inc/pagequery.php index 8f3c253..a7c9969 100644 --- a/inc/pagequery.php +++ b/inc/pagequery.php @@ -1,13 +1,12 @@ lang = $lang; @@ -35,11 +34,19 @@ function render_as_empty($query, $error = '') { function render_as_html($layout, $sorted_results, $opt, $count) { + $this->snippet_cnt = $opt['snippet']['count']; $render_type = '_render_as_html_' . $layout; return $this->$render_type($sorted_results, $opt, $count); } - + /** + * Used by the render_as_html_table function below + * **DEPRECATED** + * + * @param $sorted_results + * @param $ratios + * @return int + */ private function _adjusted_height($sorted_results, $ratios) { // ratio of different heading heights (%), to ensure more even use of columns (h1 -> h6) $adjusted_height = 0; @@ -53,7 +60,8 @@ private function _adjusted_height($sorted_results, $ratios) { /** * Render the final pagequery results list as HTML, indented and in columns as required. * - * DEPRECATED --- I would like to scrap this ASAP (old browsers only). + * **DEPRECATED** --- I would like to scrap this ASAP (old browsers only). + * It's complicated and it's hard to maintain. * * @param array $sorted_results * @param array $opt @@ -109,7 +117,7 @@ protected function _render_as_html_table($sorted_results, $opt, $count) { // now render the pagequery list foreach ($sorted_results as $line) { - list($level, $name, $id, $_, $abstract, $display) = $line; + list($level, $name, $id, $_, $abstract, $display, $thumbnail) = $line; $heading = ''; $is_heading = ($level > 0); @@ -152,11 +160,14 @@ protected function _render_as_html_table($sorted_results, $opt, $count) { if ( ! $prev_was_heading) { $render .= '' . DOKU_LF; } + if ($opt['nstitle'] && ! empty($display)) { + $heading = $display; + } if ($opt['proper'] == 'header' || $opt['proper'] == 'both') { $heading = $this->_proper($heading); } if ( ! empty($id)) { - $heading = $this->_html_wikilink($id, $heading, '', $opt, false, true); + $heading = $this->_html_wikilink($id, $heading, '', $thumbnail, $opt, false, true); } $render .= '' . $heading . '' . DOKU_LF; $prev_was_heading = true; @@ -170,7 +181,7 @@ protected function _render_as_html_table($sorted_results, $opt, $count) { if ($opt['proper'] == 'name' || $opt['proper'] == 'both') { $display = $this->_proper($display); } - $link = $this->_html_wikilink($id, $display, $abstract, $opt); + $link = $this->_html_wikilink($id, $display, $abstract, $thumbnail, $opt); $render .= $link; $prev_was_heading = false; } @@ -201,53 +212,35 @@ protected function _render_as_html_table($sorted_results, $opt, $count) { */ protected function _render_as_html_column($sorted_results, $opt, $count) { - $render = ''; $prev_was_heading = false; $cont_level = 1; $is_first = true; - - $fontsize = ''; - $outer_border = ''; - $inner_border = ''; - $show_count = ''; - $label = ''; - $show_jump = ''; - $list_style = ''; - - // A fixed anchor to jump back to at top - $top_id = 'top-' . mt_rand(); + $top_id = 'top-' . mt_rand(); // A fixed anchor at top to jump back to // CSS for the various display options - if ( ! empty($opt['fontsize'])) { - $fontsize = 'font-size:' . $opt['fontsize']; - } - if ($opt['border'] == 'outside' || $opt['border'] == 'both') { - $outer_border = 'border'; - } - if ($opt['border'] == 'inside'|| $opt['border'] == 'both') { - $inner_border = 'inner-border" '; - } - if ($opt['showcount'] == true) { - $show_count = '
' . $count . ' ∞
' . DOKU_LF; - } - if ($opt['label'] != '') { - $label = '

' . $opt['label'] . '

' . DOKU_LF; - } - if ($opt['hidejump'] === false) { - $show_jump = '' . $this->lang['link_to_top'] . '' . DOKU_LF; - } - if ($opt['bullet'] != 'none') { - $list_style = 'list-style-position:inside;list-style-type:' . $opt['bullet']; - } - - // no grouping = no indenting + $fontsize = ( ! empty($opt['fontsize'])) ? + 'font-size:' . $opt['fontsize'] : ''; + $outer_border = ($opt['border'] == 'outside' || $opt['border'] == 'both') ? + 'border' : ''; + $inner_border = ($opt['border'] == 'inside'|| $opt['border'] == 'both') ? + 'inner-border' : ''; + $show_count = ($opt['showcount'] == true) ? + '
' . $count . ' ∞
' . DOKU_LF : ''; + $label = ($opt['label'] != '') ? + '

' . $opt['label'] . '

' . DOKU_LF : ''; + $show_jump = ($opt['hidejump'] === false) ? + '' . $this->lang['link_to_top'] . '' . DOKU_LF : ''; + $list_style = ($opt['bullet'] != 'none') ? + 'list-style-position:inside;list-style-type:' . $opt['bullet'] : ''; + + // no grouping => no indenting $can_indent = $opt['group']; // now prepare the actual pagequery list $pagequery = ''; foreach ($sorted_results as $line) { - list($level, $name, $id, $_, $abstract, $display) = $line; + list($level, $name, $id, $_, $abstract, $display, $thumbnail) = $line; $is_heading = ($level > 0); $heading = ($is_heading) ? $name : ''; @@ -259,23 +252,27 @@ protected function _render_as_html_column($sorted_results, $opt, $count) { $indent_style = ''; } - // finally display the appropriate heading or page link(s) + // finally display the appropriate heading... if ($is_heading) { - // close previous sub list if necessary + // close previous subheading list if necessary if ( ! $prev_was_heading) { $pagequery .= '' . DOKU_LF; } + if ($opt['nstitle'] && ! empty($display)) { + $heading = $display; + } if ($opt['proper'] == 'header' || $opt['proper'] == 'both') { $heading = $this->_proper($heading); } if ( ! empty($id)) { - $heading = $this->_html_wikilink($id, $heading, '', $opt, false, true); + $heading = $this->_html_wikilink($id, $heading, '', $thumbnail, $opt, false, true); } $pagequery .= '' . $heading . '' . DOKU_LF; $prev_was_heading = true; $cont_level = $level + 1; + // ...or page link(s) } else { // open a new sub list if necessary if ($prev_was_heading || $is_first) { @@ -285,13 +282,15 @@ protected function _render_as_html_column($sorted_results, $opt, $count) { if ($opt['proper'] == 'name' || $opt['proper'] == 'both') { $display = $this->_proper($display); } - $link = $this->_html_wikilink($id, $display, $abstract, $opt); + $link = $this->_html_wikilink($id, $display, $abstract, $thumbnail, $opt); $pagequery .= $link; $prev_was_heading = false; } $is_first = false; } + // and put it all together for display + $render = ''; $render .= '
' . DOKU_LF; $render .= $show_count . $show_jump . $label . DOKU_LF; $render .= '
' . DOKU_LF; @@ -312,28 +311,41 @@ protected function _render_as_html_column($sorted_results, $opt, $count) { * @param bool $raw => non-formatted (no html) * @return string */ - private function _html_wikilink($id, $display, $abstract, $opt, $track_snippets = true, $raw = false) { - static $snippet_cnt = 0; + private function _html_wikilink($id, $display, $abstract, $thumbnail, $opt, $track_snippets = true, $raw = false) { + global $INFO; - if ($track_snippets) { - $snippet_cnt++; - } $id = (strpos($id, ':') === false) ? ':' . $id : $id; // : needed for root pages (root level) $link = html_wikilink($id, $display); $type = $opt['snippet']['type']; $inline = ''; $after = ''; - - $count = $opt['snippet']['count']; - $skip_snippet = ($count > 0 && $snippet_cnt >= $count); + $thumbnail_html = ''; + + if ( !empty( $thumbnail ) && !empty( $opt[ 'thumbnail' ] ) ) { + // Build the array of necessary data + $thumbnail_data = array( + 'src' => $thumbnail, + 'title' => $id, + 'align' => $opt['thumbnail']['align'], + 'width' => $opt['thumbnail']['width'], + 'height' => $opt['thumbnail']['height'], + 'cache' => 'cache', + ); + // Check if we are dealing with an internal image + if ( !media_isexternal( $thumbnail ) ) { + $thumbnail_data['type'] = 'internalmedia'; + } + // Get the link and image + $thumbnail_html = html_wikilink( $id, $thumbnail_data ); + } if ($type == 'tooltip') { $tooltip = str_replace("\n\n", "\n", $abstract); $tooltip = htmlentities($tooltip, ENT_QUOTES, 'UTF-8'); $link = $this->_add_tooltip($link, $tooltip); - } elseif (in_array($type, array('quoted', 'plain', 'inline')) && ! $skip_snippet) { + } elseif (in_array($type, array('quoted', 'plain', 'inline')) && $this->snippet_cnt > 0) { $short = $this->_shorten($abstract, $opt['snippet']['extent']); $short = htmlentities($short, ENT_QUOTES, 'UTF-8'); if ( ! empty($short)) { @@ -350,10 +362,16 @@ private function _html_wikilink($id, $display, $abstract, $opt, $track_snippets } $border = ($opt['underline']) ? 'border' : ''; + if ( $id == $INFO['id'] ) { + $border .= ' current'; + } if ($raw) { $wikilink = $link . $inline; } else { - $wikilink = '
  • ' . $link . $inline . DOKU_LF . $after . '
  • '; + $wikilink = '
  • ' . $thumbnail_html . $link . $inline . DOKU_LF . $after . '
  • '; + } + if ($track_snippets) { + $this->snippet_cnt--; } return $wikilink; } @@ -378,12 +396,12 @@ private function _add_tooltip($link, $tooltip) { * * @param string $text * @param string $extent c? = ? chars, w? = ? words, l? = ? lines, ~? = search up to text/char/symbol - * @param string $more + * @param string $more symbol to show if more text * @return string */ private function _shorten($text, $extent, $more = '... ') { $elem = $extent[0]; - $cnt = substr($extent, 1); + $cnt = (int) substr($extent, 1); switch ($elem) { case 'c': $result = substr($text, 0, $cnt); @@ -418,12 +436,31 @@ private function _shorten($text, $extent, $more = '... ') { private function _proper($id) { $id = str_replace(':', ': ', $id); // make a little whitespace before words so ucwords can work! $id = str_replace('_', ' ', $id); - $id = ucwords($id); + $id = utf8_ucwords($id); $id = str_replace(': ', ':', $id); return $id; } + /** + * a mb version of 'ucwords' that respects capitalised words + * does not work for hyphenated words (yet) + * **UNUSED** + */ + private function _mb_ucwords($str) { + $result = array(); + $words = mb_split('\s', $str); + foreach ($words as $word) { + if (mb_strtoupper($word) == $word) { + $result[] = $word; + } else { + $result[] = mb_convert_case($word, MB_CASE_TITLE, "UTF-8"); + } + } + return implode(' ', $result); + } + + /** * Parse out the namespace, and convert to a regex for array search * @@ -544,7 +581,7 @@ function build_sorting_array($ids, $opt) { case 'a': case 'ab': case 'abc': - $value = $this->_first(strtolower($abc), strlen($key)); + $value = $this->_first($abc, strlen($key)); break; case 'name': case 'title': @@ -644,12 +681,17 @@ function build_sorting_array($ids, $opt) { } elseif (isset($row[$display])) { $display = $row[$display]; - // if all else fails then used the page name (always available) + // if all else fails then use the page name (always available) } else { $display = $row['name']; } $row['display'] = $display; + // Get the page's first image, if available + if ( isset( $meta['relation']['firstimage'] ) ) { + $row['thumbnail'] = $meta['relation']['firstimage']; + } + $cnt++; } @@ -754,9 +796,9 @@ private function _join_keys_if($delim, $arr) { } - // returns first $count letters from $text + // returns first $count letters from $text in lowercase private function _first($text, $count) { - $result = ($count > 0) ? utf8_substr($text, 0, $count) : ''; + $result = ($count > 0) ? utf8_substr(utf8_strtolower($text), 0, $count) : ''; return $result; } @@ -1158,9 +1200,10 @@ private function _add_heading(&$results, &$sort_array, &$group_opts, $level, $id if ($group_type === self::MGROUP_HEADING) { $date_format = $group_opts['dformat'][$level]; if ( ! empty($date_format)) { - // the real date is always the the '__realdate__' column (MGROUP_REALDATE) + // the real date is always the '__realdate__' column (MGROUP_REALDATE) $cur = strftime($date_format, $sort_array[$idx][self::MGROUP_REALDATE]); } + // args : $level, $name, $id, $_, $abstract, $display $results[] = array($level + 1, $cur, ''); } elseif ($group_type === self::MGROUP_NAMESPACE) { @@ -1171,12 +1214,19 @@ private function _add_heading(&$results, &$sort_array, &$group_opts, $level, $id if ($cur_ns[$i] != $prev_ns[$i]) { $hl = $level + $i + 1; $id = implode(':', array_slice($cur_ns, 0, $i + 1)) . ':' . $conf['start']; - $ns_start = (page_exists($id)) ? $id : ''; - $results[] = array($hl , $cur_ns[$i], $ns_start, '', ''); + if (page_exists($id)) { + $ns_start = $id; + // allow the first heading to be used instead of page id/name + $display = p_get_metadata($id, 'title'); + } else { + $ns_start = $display = ''; + } + // args : $level, $name, $id, $_, $abstract, $display + $results[] = array($hl , $cur_ns[$i], $ns_start, '', '', $display); } } } } } -} \ No newline at end of file +} diff --git a/lang/ja/lang.php b/lang/ja/lang.php new file mode 100644 index 0000000..a7f2fb2 --- /dev/null +++ b/lang/ja/lang.php @@ -0,0 +1,13 @@ +[query;fulltext;sort=key:direction,key2:direction;group;limit=??;cols=?;inwords;proper]}} [..] = optional url http://www.dokuwiki.org/plugin:pagequery diff --git a/syntax.php b/syntax.php index 4b12394..10aafbc 100644 --- a/syntax.php +++ b/syntax.php @@ -55,7 +55,7 @@ function connectTo($mode) { * * @link https://www.dokuwiki.org/plugin:pagequery See PageQuery page for full details */ - function handle($match, $state, $pos, &$handler) { + function handle($match, $state, $pos, Doku_Handler $handler) { $opt = array(); $match = substr($match, 12, -2); // strip markup "{{pagequery>...}}" @@ -91,9 +91,11 @@ function handle($match, $state, $pos, &$handler) { $opt['sort'] = array(); // sort by various headings $opt['spelldate'] = false; // spell out date headings in words where possible $opt['underline'] = false; // faint underline below each link for clarity + $opt['nstitle'] = false; // internal use currently... + $opt['thumbnail'] = array(); // first image in page foreach ($params as $param) { - list($option, $value) = explode('=', $param); + list($option, $value) = $this->_keyvalue($param, '='); switch ($option) { case 'casesort': case 'fullregex': @@ -116,7 +118,7 @@ function handle($match, $state, $pos, &$handler) { case 'filter': $fields = explode(',', $value); foreach ($fields as $field) { - list($key, $expr) = explode(':', $field, 2); + list($key, $expr) = $this->_keyvalue($field); // allow for a few common naming differences switch ($key) { case 'pagename': @@ -198,6 +200,7 @@ function handle($match, $state, $pos, &$handler) { case 'heading': case 'firstheading': $opt['display'] = 'title'; + $opt['nstitle'] = true; break; case 'pageid': case 'id': @@ -206,6 +209,9 @@ function handle($match, $state, $pos, &$handler) { default: $opt['display'] = $value; } + if (preg_match('/\{(title|heading|firstheading)\}/', $value)) { + $opt['nstitle'] = true; + } break; case 'layout': if ( ! in_array($value, array('table', 'column'))) { @@ -218,13 +224,47 @@ function handle($match, $state, $pos, &$handler) { $opt['fontsize'] = $value; } break; + case 'thumbnail': + // Set defaults here + $opt['thumbnail'] = array( 'width' => 100, 'heigth' => null, 'align' => '' ); + + $thumb_details = explode( ',', strtolower( $value ) ); + $thumb_details = array_slice( $thumb_details, 0, 2 ); // Allow a maximum of 2 arguments + $thumb_details = array_map( 'trim', $thumb_details ); + foreach ( $thumb_details as $thumb_detail ) { + // Allow for full size images + if ( $thumb_detail == '0' || $thumb_detail == '0x0' ) { + $opt['thumbnail']['height'] = null; + $opt['thumbnail']['width'] = null; + } + // Determine image size (both width and height are given) + elseif ( strpos( $thumb_detail, 'x' ) ) { + $thumb_size = explode( 'x', $thumb_detail ); + $thumb_size = array_map( 'intval', $thumb_size ); + if ( $thumb_size[0] > 0 ) { + $opt['thumbnail']['width'] = $thumb_size[0]; + } + if ( $thumb_size[1] > 0 ) { + $opt['thumbnail']['height'] = $thumb_size[1]; + } + } + // Determine image size (only width is given) + elseif ( is_numeric( $thumb_detail ) && intval( $thumb_detail ) > 0 ) { + $opt['thumbnail']['width'] = intval( $thumb_detail ); + } + // Determine image alignment + elseif ( in_array( $thumb_detail, array( 'center', 'left', 'right' ) ) ) { + $opt['thumbnail']['align'] = $thumb_detail; + } + } + break; } } return $opt; - } + } - function render($mode, &$renderer, $opt) { + function render($mode, Doku_Renderer $renderer, $opt) { if ( ! PHP_MAJOR_VERSION >= 5 && ! PHP_MINOR_VERSION >= 3) { $renderer->doc .= "You must have PHP 5.3 or greater to use this pagequery plugin. Please upgrade PHP or use an older version of the plugin"; @@ -243,6 +283,7 @@ function render($mode, &$renderer, $opt) { 'no_results' => $this->getLang('no_results') ); $pq = new PageQuery($lang); + $query = $opt['query']; if ($mode == 'xhtml') { @@ -306,7 +347,7 @@ function render($mode, &$renderer, $opt) { $count = count($sort_array); // and finally the grouping - $keys = array('name', 'id', 'title', 'abstract', 'display'); + $keys = array('name', 'id', 'title', 'abstract', 'display', 'thumbnail'); if ( ! $opt['group']) $group_opts = array(); $sorted_results = $pq->mgroup($sort_array, $keys, $group_opts); @@ -324,5 +365,20 @@ function render($mode, &$renderer, $opt) { return false; } } + + + /** + * Split a string into key => value parts. + * + * @param string $str + * @param string $delim + * @return array + */ + private function _keyvalue($str, $delim = ':') { + $parts = explode($delim, $str); + $key = isset($parts[0]) ? $parts[0] : ''; + $value = isset($parts[1]) ? $parts[1] : ''; + return array($key, $value); + } }