1<?php
2/**
3 * DokuWiki Plugin Gview (Syntax Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Sahara Satoshi <sahara.satoshi@gmail.com>
7 *
8 * @see also:https://docs.google.com/viewer#
9 * Google Docs Viewer Terms of Service
10 * By using this service you acknowledge that you have read and
11 * agreed to the Google Docs Viewer Terms of Service.
12 *
13 * Google Docs Viewer plugin
14 * Shows a online document using Google Docs Viewer Service.
15 * SYNTAX: {{gview [size] [noembed] [noreference] > mediaID|title }}
16 *         {{obj:[class] [size] [noembed] [noreference] > mediaID|title }}
17 */
18
19// must be run within Dokuwiki
20if (!defined('DOKU_INC')) die();
21if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
22require_once DOKU_PLUGIN.'syntax.php';
23
24class syntax_plugin_gview extends DokuWiki_Syntax_Plugin {
25
26    // URL of Google Docs Viwer Service
27    const URLgoogleViwer = 'https://docs.google.com/viewer';
28
29    public function getType()  { return 'substition'; }
30    public function getPType() { return 'normal'; }
31    public function getSort()  { return 305; }
32    public function connectTo($mode) {
33        $this->Lexer->addSpecialPattern('{{gview.*?>.*?}}',$mode,'plugin_gview');
34
35        // trick pattern :-)
36        $this->Lexer->addSpecialPattern('{{obj:.*?>.*?}}',$mode,'plugin_gview');
37    }
38
39
40    /**
41     * Resolve media URLs
42     * Create Media Link from DokuWiki media id considering $conf['userewrite'] value.
43     * @see function ml() in inc/common.php
44     *
45     * @param (string) $linkId   mediaId
46     * @return (string)          URL that does NOT contain DOKU_URL
47     */
48    private function _resolveMediaUrl($linkId = '') {
49        global $ACT, $ID, $conf;
50
51        // external URLs are always direct without rewriting
52        if(preg_match('#^https?://#i', $linkId)) {  return $linkId; }
53
54        resolve_mediaid(getNS($ID), $linkId, $exists);
55        $linkId = idfilter($linkId);
56        if (!$exists && ($ACT=='preview')) {
57            msg($this->getPluginName().': media file not exists: '.$linkId, -1);
58            return false;
59        }
60        // check access control
61        if (!media_ispublic($linkId) && ($ACT=='preview')) {
62            msg($this->getPluginName().': '.$linkId.' is NOT public!', 2);
63        }
64        // check MIME setting of DokuWiki - mime.conf/mime.local.conf
65        // Embedding will fail if the media file is to be force_download.
66        list($ext, $mtype, $force_download) = mimetype($linkId);
67        if (!$force_download) {
68            switch ($conf['userewrite']){
69                case 0: // No URL rewriting
70                    $mediapath = 'lib/exe/fetch.php?media='.$linkId;
71                    break;
72                case 1: // serverside rewiteing eg. .htaccess file
73                    $mediapath = '_media/'.$linkId;
74                    break;
75                case 2: // DokuWiki rewiteing
76                    $mediapath = 'lib/exe/fetch.php/'.$linkId;
77                    break;
78            }
79        } else {
80            // try alternative url to avoid download dialog.
81            //
82            // !!! EXPERIMENTAL : WEB SITE SPECIFIC FEATURE !!!
83            // we assume "DOKU_URL/_media" directory
84            // which physically mapped or linked to
85            // your DW_DATA_PATH/media directory.
86            // WebServer solution includes htpd.conf, IIS virtual directory.
87            // Symbolic link or Junction are Filesystem solution.
88            // Example:
89            // if linux: ln -s DW_DATA_PATH/media _media
90            // if iis6(Win2003S): linkd.exe _media DW_DATA_PATH/media
91            // if iis7(Win2008S): mklink.exe /d _media DW_DATA_PATH/media
92            //
93
94            $altMediaBaseDir = $this->getConf('alternative_mediadir');
95            if (empty($altMediaBaseDir)) $altMediaBaseDir ='/';
96            if ($linkId[0] == ':') $linkId = substr($linkId, 1);
97            $mediapath = $altMediaBaseDir . str_replace(':','/',$linkId);
98            if ($ACT=='preview') {
99                msg($this->getPluginName().': alternative url ('.$mediapath.') will be used for '.$linkId, 2);
100            }
101        }
102        // $mediapath does not contain "http://" and hostname
103        return $mediapath;
104    }
105
106
107
108    /**
109     * handle syntax
110     */
111    public function handle($match, $state, $pos, Doku_Handler $handler){
112
113        $opts = array( // set default
114                     'id'      => '',
115                     'title'   => $this->getLang('gview_linktext'),
116                     'class'   => '',
117                     'width'   => '100%',
118                     'height'  => '300px',
119                     'embedded' => true,
120                     'reference'  => true,
121                     //'border'  => false,
122                     );
123
124        list($params, $media) = explode('>', trim($match,'{}'), 2);
125
126        // handle media parameters (linkId and title)
127        list($linkId, $title) = explode('|', $media, 2);
128
129        // handle viewer parameters
130        // split phrase of parameters by white space
131        $tokens = preg_split('/\s+/', $params);
132
133        // check frist markup
134        $markup = array_shift($tokens); // first param
135        if (strpos($markup,'gview') !== false) {
136            $opts['class'] = 'gview';
137        } elseif (strlen($markup) > 6) {
138            $opts['class'] = substr($markup,6); // strip "{{obj:"
139        }
140
141        foreach ($tokens as $token) {
142
143            // get width and height of iframe
144            $matches=array();
145            if (preg_match('/(\d+(%|em|pt|px)?)([,xX](\d+(%|em|pt|px)?))?/',$token,$matches)){
146                if ($matches[4]) {
147                    // width and height was given
148                    $opts['width'] = $matches[1];
149                    if (!$matches[2]) $opts['width'].= 'px'; //default to pixel when no unit was set
150                    $opts['height'] = $matches[4];
151                    if (!$matches[5]) $opts['height'].= 'px'; //default to pixel when no unit was set
152                    continue;
153                } elseif ($matches[2]) {
154                    // only height was given
155                    $opts['height'] = $matches[1];
156                    if (!$matches[2]) $opts['height'].= 'px'; //default to pixel when no unit was set
157                    continue;
158                }
159            }
160            // get reference option, ie. whether show original document url?
161            if (preg_match('/no(reference|link)/',$token)) {
162                $opts['reference'] = false;
163                continue;
164            }
165            // get embed option
166            if (preg_match('/noembed(ded)?/',$token)) {
167                $opts['embedded'] = false;
168                continue;
169            }
170            // get border option
171            if (preg_match('/no(frame)?border/',$token)) {
172              $opts['border'] = false;
173              continue;
174            }
175        }
176
177        $opts['id'] = trim($linkId);
178        if (!empty($title)) $opts['title'] = trim($title);
179
180        return array($state, $opts);
181    }
182
183    /**
184     * Render iframe or link for Google Docs Viewer Service
185     */
186    public function render($format, Doku_Renderer $renderer, $data) {
187
188        if ($format != 'xhtml') return false;
189
190        list($state, $opts) = $data;
191        if ( $opts['id'] =='') return false;
192
193        switch ($opts['class']) {
194            case 'gview':
195                $html = $this->_html_embed_gview($opts);
196                break;
197            default:
198                $html = $this->_html_embed($opts);
199                break;
200        }
201        $renderer->doc.=$html;
202        return true;
203    }
204
205    /**
206     * Generate html for sytax {{obj:>}}
207     */
208    private function _html_embed($opts) {
209
210        // make reference link
211        $url = $this->_resolveMediaUrl($opts['id']);
212        $referencelink = '<a href="'.$url.'">'.urldecode($url).'</a>';
213
214        if (empty($opts['class'])) {
215            $html = '<div class="obj_container">'.NL;
216        } else {
217            $html = '<div class="obj_container_'.$opts['class'].'">'.NL;
218        }
219        if (!$opts['embedded']) {
220            $html.= '<a href="'.$url.'">'.$opts['title'].'</a>';
221        } else {
222            if ($opts['reference']) {
223                $html.= '<div class="obj_note">';
224                $html.= sprintf($this->getLang('reference_msg'), $referencelink);
225                $html.= '</div>'.NL;
226            }
227            $html.= '<object data="'.urldecode($url).'"';
228            $html.= ' style="';
229            if ($opts['width'])  { $html.= ' width: '.$opts['width'].';'; }
230            if ($opts['height']) { $html.= ' height: '.$opts['height'].';'; }
231            $html.= '">'.NL;
232            $html.= '</object>'.NL;
233        }
234        $html.= '</div>'.NL;
235
236        return $html;
237    }
238
239    /**
240     * Generate html for sytax {{obj:gview>}} or {{gview>}}
241     *
242     * @see also: https://docs.google.com/viewer#
243     */
244    private function _html_embed_gview($opts) {
245
246        // make reference link
247        $url = DOKU_URL.$this->_resolveMediaUrl($opts['id']);
248        $referencelink = '<a href="'.$url.'">'.urldecode($url).'</a>';
249
250        $html = '<div class="obj_container_gview">'.NL;
251        if (!$opts['embedded']) {
252            $html.= '<a href="'.$url.'">'.$opts['title'].'</a>';
253        } else {
254            if ($opts['reference']) {
255                $html.= '<div class="obj_note">';
256                $html.= sprintf($this->getLang('reference_msg'), $referencelink);
257                $html.= '</div>'.NL;
258            }
259            $html.= '<iframe src="'.self::URLgoogleViwer;
260            $html.= '?url='.urlencode($url);
261            $html.= '&embedded=true"';
262            $html.= ' style="';
263            if ($opts['width'])  { $html.= ' width: '.$opts['width'].';'; }
264            if ($opts['height']) { $html.= ' height: '.$opts['height'].';'; }
265            //if ($opts['border'] == false) { $html.= ' border: none;'; }
266            $html.= ' border: none;';
267            $html.= '"></iframe>'.NL;
268        }
269        $html.= '</div>'.NL;
270
271        return $html;
272    }
273
274}
275