1<?php 2/** 3 * Helper Component of Medialist plugin 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Satoshi Sahara <sahara.satoshi@gmail.com> 7 */ 8 9// must be run within Dokuwiki 10if (!defined('DOKU_INC')) die(); 11 12class helper_plugin_medialist extends DokuWiki_Plugin { 13 14 /** 15 * syntax parser 16 * 17 * @param $data string matched the regex {{medialist>[^\r\n]+?}} 18 * @return array parameter for render process 19 * 20 * ----------------------------------------------------------------------- 21 * [ns:] namespace, must end ":" or ":*" 22 * [page] page id 23 * 24 * {{pagelist>ns:}} 25 * - show media files in the given namespace 26 * - show button to open the given ns by fullscreen media manager 27 * {{pagelist>ns: page}} 28 * - distinguish linked files in the page if they found in the list 29 * {{pagelist>ns: +page}} 30 * - add linked media files to the list (@BOTH@) 31 * 32 * {{pagelist>page}} 33 * - show media files linked in the given page 34 * {{pagelist>page ns:}} 35 * - show button to open the given ns by fullscreen media manager 36 * ----------------------------------------------------------------------- 37 */ 38 public function parse($data) { 39 global $INFO; 40 41 $params = array(); // parameter array for render process 42 43 $match = substr($data, 12, -2); 44 $match = str_replace(' ',' ', trim($match)); // remove excessive white spaces 45 46 // v1 syntax (backword compatibility for 2009-05-21 release) 47 // @PAGE@, @NAMESPACE@, @ALL@ are complete keyword arguments, 48 // not replacement patterns. 49 switch ($match) { 50 case '@PAGE@': 51 $match = '@ID@'; break; 52 case '@NAMESPACE@': 53 $match = '@NS@:*'; break; 54 case '@ALL@': 55 case '@BOTH@': 56 $match = '@NS@:* +@ID@'; break; 57 } 58 59 // v2 syntax (available since 2016-06-XX release) 60 // - enable replacement patterns @ID@, @NS@, @PAGE@ 61 // for media file search scope 62 // - Namespace search if scope parameter ends colon ":", and 63 // require "*" after the colon for recursive search 64 65 // replacement patterns identical with Namespace Template 66 // @see https://www.dokuwiki.org/namespace_templates#syntax 67 $args = $match; 68 $args = str_replace('@ID@', $INFO['id'], $args); 69 $args = str_replace('@NS@', getNS($INFO['id']), $args); 70 $args = str_replace('@PAGE@', noNS($INFO['id']), $args); 71 72 $args = explode(' ', $args, 2); 73 74 // check first parameter 75 if (substr($args[0], -1) == ':') { 76 $params['ns'] = substr($args[0], 0, -1); 77 $params['depth'] = 1; // set depth option for search() 78 } elseif (substr($args[0], -2) == ':*') { 79 $params['ns'] = substr($args[0], 0, -2); 80 } else { 81 $params['page'] = $args[0]; 82 } 83 84 // check second parameter 85 if (!empty($args[1])) { 86 if (isset($params['ns'])) { 87 $params['page'] = ltrim($args[1], '+'); 88 $params['append'] = (bool) ($args[1][0] == '+'); 89 } else { 90 $params['uploadns'] = rtrim($args[1],':'); 91 } 92 } 93 return $params; 94 } 95 96 97 /** 98 * Renders xhtml 99 */ 100 public function render_xhtml($params) { 101 102 $linked_media = array(); 103 $stored_media = array(); 104 105 // search internal files in the given namespace 106 if (isset($params['ns'])) { 107 // search option for lookup_stored_media() 108 $opt = array(); 109 if (array_key_exists('depth', $params)) { 110 $opt = $opt + array('depth' => $params['depth']); 111 } 112 $stored_media = $this->_lookup_stored_media($params['ns'], $opt); 113 } 114 115 // search linked/used media in the given page 116 if (isset($params['page'])) { 117 $linked_media = $this->_lookup_linked_media($params['page']); 118 } 119 120 if (isset($params['append']) && $params['append']) { 121 $media = array_unique(array_merge($stored_media, $linked_media), SORT_REGULAR); 122 } else { 123 $media = isset($params['ns']) ? $stored_media : $linked_media; 124 if (!$params['ns'] && $params['page']) { 125 $linked_media = array(); 126 } 127 } 128 129 // prepare list items 130 $items = array(); 131 foreach ($media as $item) { 132 $base = !isset($params['ns']) ? getNS($item['id']) : $params['ns']; 133 134 if (in_array($item, $linked_media)) { 135 $item = $item + array('level' => 1, 'base' => $base, 'linked'=> 1); 136 } else { 137 $item = $item + array('level' => 1, 'base' => $base); 138 } 139 $items[] = $item; 140 } 141 142 // create output 143 $out = ''; 144 $out .= '<div class="medialist">'. DOKU_LF; 145 146 // mediamanager button 147 $uploadns = isset($params['uploadns']) ? $params['uploadns'] : $params['ns']; 148 $tab = empty($items) ? 'upload' : 'files'; 149 if (isset($uploadns) && (auth_quickaclcheck("$uploadns:*") >= AUTH_UPLOAD)) { 150 $out .= '<div class="mediamanager">'; 151 $out .= $this->_mediamanager_button($uploadns, $tab); 152 $out .= '</div>'. DOKU_LF; 153 } 154 155 // list of media files 156 if (!empty($items)) { 157 $out .= html_buildlist($items, 'medialist', array($this, '_media_item')); 158 $out .= DOKU_LF; 159 } elseif ($this->getConf('emptyInfo')) { 160 $out .= '<div class="info">'; 161 $out .= '<strong>'.$this->getPluginName().'</strong>'.': nothing to show here.'; 162 $out .= '</div>'. DOKU_LF;; 163 } 164 $out .= '</div>'. DOKU_LF; 165 return $out; 166 } 167 168 /** 169 * Callback function for html_buildlist() 170 * 171 * @author Michael Klier <chi@chimeric.de> 172 */ 173 public function _media_item($item) { 174 global $conf, $lang; 175 176 $out = ''; 177 178 $link = array(); 179 $link['url'] = ml($item['id']); 180 $link['class'] = isset($item['linked']) ? 'media linked' : 'media'; 181 $link['target'] = $conf['target']['media']; 182 $link['title'] = noNS($item['id']); 183 184 // link text and mediainfo 185 if ($item['type'] == 'internalmedia') { 186 // Internal file 187 if (!empty($item['base'])) { 188 // remove base namespace to get shorten link text 189 $link['name'] = preg_replace('/^'.$item['base'].':/','', $item['id']); 190 } else { 191 $link['name'] = $item['id']; 192 } 193 $mediainfo = strftime($conf['dformat'], $item['mtime']).' '; 194 $mediainfo .= filesize_h($item['size']); 195 } else { 196 // External link 197 $link['name'] = $item['id']; 198 $mediainfo = $lang['qb_extlink']; // External Link 199 } 200 201 // add file icons 202 list($ext,$mime) = mimetype($item['id']); 203 $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext); 204 $link['class'] .= ' mediafile mf_'.$class; 205 206 // build the list item 207 if ($this->getConf('checkboxes')) { 208 $out .= '<input type="checkbox" id="delete['.$item['id'].']" />'; 209 $out .= '<label for="delete['.$item['id'].']">'.'</label>'; 210 } 211 $out .= '<a href="' . $link['url'] . '" '; 212 $out .= 'class="' . $link['class'] . '" '; 213 $out .= 'target="' . $link['target'] . '" '; 214 $out .= 'title="' . $link['title'] . '">'; 215 $out .= $link['name']; 216 $out .= '</a>'; 217 $out .= ' <span class="mediainfo">('.$mediainfo.')</span>' . DOKU_LF; 218 219 return $out; 220 } 221 222 /** 223 * button to open a given namespace with the Fullscreen Media Manager 224 * @param $ns string namespace 225 * @param $tab string tab name of MediaManager (files|upload|search) 226 * @return string html 227 */ 228 protected function _mediamanager_button($ns, $tab=null) { 229 global $INFO, $lang; 230 231 $method = 'get'; 232 $params = array('do' => 'media', 'ns' => $ns); 233 if (in_array($tab, array('files','upload','search'))) { 234 $params += array('tab_files' => $tab); 235 } 236 $label = hsc("$ns:*"); 237 $tooltip = ($tab == 'upload') ? $lang['btn_upload'] :$lang['btn_media']; 238 $accesskey = ''; 239 return html_btn('media', $INFO['id'], $accesskey, $params, $method, $tooltip, $label); 240 } 241 242 243 /** 244 * searches media files linked in the given page 245 * returns an array of items 246 */ 247 protected function _lookup_linked_media($id) { 248 $linked_media = array(); 249 250 if (!page_exists($id)) { 251 //msg('MediaList: page "'. hsc($id) . '" not exists!', -1); 252 } 253 254 if (auth_quickaclcheck($id) >= AUTH_READ) { 255 // get the instructions 256 $ins = p_cached_instructions(wikiFN($id), true, $id); 257 258 // get linked media files 259 foreach ($ins as $node) { 260 if ($node[0] == 'internalmedia') { 261 $id = cleanID($node[1][0]); 262 $fn = mediaFN($id); 263 if (!file_exists($fn)) continue; 264 $linked_media[] = array( 265 'id' => $id, 266 'size' => filesize($fn), 267 'mtime' => filemtime($fn), 268 'type' => $node[0], 269 ); 270 } elseif ($node[0] == 'externalmedia') { 271 $linked_media[] = array( 272 'id' => $node[1][0], 273 'size' => null, 274 'mtime' => null, 275 'type' => $node[0], 276 ); 277 } 278 } 279 280 } 281 return array_unique($linked_media, SORT_REGULAR); 282 } 283 284 /** 285 * searches media files stored in the given namespace and sub-tiers 286 * returns an array of items 287 */ 288 protected function _lookup_stored_media($ns, $opt=array('depth'=>1)) { 289 global $conf; 290 291 $stored_media = array(); 292 293 $dir = utf8_encodeFN(str_replace(':','/', $ns)); 294 295 if (!is_dir($conf['mediadir'] . '/' . $dir)) { 296 //msg('MediaList: namespace "'. hsc($ns). '" not exists!', -1); 297 } 298 299 if (auth_quickaclcheck("$ns:*") >= AUTH_READ) { 300 // search media files in the namespace 301 $res = array(); // search result 302 search($res, $conf['mediadir'], 'search_media', $opt, $dir); 303 304 // prepare return array 305 foreach ($res as $item) { 306 $stored_media[] = array( 307 'id' => $item['id'], 308 'size' => $item['size'], 309 'mtime' => $item['mtime'], 310 'type' => 'internalmedia', 311 ); 312 } 313 } 314 return $stored_media; 315 } 316 317} 318 319