1<?php
2/**
3 * DokuWiki Plugin tumblr (Syntax Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Lee Kwangyoung <ipari@leaflette.com>
7 */
8
9// must be run within Dokuwiki
10if (!defined('DOKU_INC')) die();
11
12class syntax_plugin_tumblr extends DokuWiki_Syntax_Plugin {
13    function getInfo() {
14        return array(
15        'author'  => 'Lee, Kwangyoung',
16        'email'   => 'ipari@leaflette.com',
17        'date'    => '2011-04-04',
18        'name'    => 'Tumblr Plugin',
19        'desc'    => 'Embed tumblr into DokuWiki',
20        'url'     => 'http://www.dokuwiki.org/plugin:tumblr'
21        );
22    }
23
24    /**
25     * @return string Syntax mode type
26     */
27    function getType() {
28        return 'substition';
29    }
30    /**
31     * @return string Paragraph type
32     */
33    function getPType() {
34        return 'normal';
35    }
36    /**
37     * https://www.dokuwiki.org/devel:parser:getsort_list
38     *
39     * @return int Sort order - Low numbers go before high numbers
40     */
41    function getSort() {
42        return 315;
43    }
44
45    /**
46     * Connect lookup pattern to lexer.
47     *
48     * @param string $mode Parser mode
49     */
50    function connectTo($mode) {
51        $this->Lexer->addSpecialPattern('\{\{tumblr>[^}]*\}\}',$mode,'plugin_tumblr');
52    }
53
54//    function postConnect() {
55//        $this->Lexer->addExitPattern('</FIXME>','plugin_tumblr');
56//    }
57
58    /**
59     * Handle matches of the tumblr syntax
60     *
61     * @param string $match The match of the syntax
62     * @param int    $state The state of the handler
63     * @param int    $pos The position in the document
64     * @param Doku_Handler    $handler The handler
65     * @return array Data for the renderer
66     */
67    function handle($match, $state, $pos, Doku_Handler &$handler){
68        $match = substr($match,9,-2); //strip '{{tumblr>' and '}}'
69        $params = explode('&',$match);
70
71        $data = array();
72        foreach($params as $param) {
73            $param = explode('=',$param);
74            $data[$param[0]] = $param[1];
75        }
76        return $data;
77    }
78
79    /**
80     * Render xhtml output or metadata
81     *
82     * @param string         $mode      Renderer mode (supported modes: xhtml)
83     * @param Doku_Renderer  $renderer  The renderer
84     * @param array          $data      The data from the handler() function
85     * @return bool If rendering was successful.
86     */
87    function render($mode, Doku_Renderer &$renderer, $data) {
88        if($mode != 'xhtml') return false;
89        // prevent caching to show lastest posts
90        $renderer->info['cache'] = false;
91        $renderer->doc .= $this->tumblr($data);
92        return true;
93    }
94
95    public $tumblr_url = false;
96
97    function load_rss($url) {
98        global $conf;
99        require_once(DOKU_INC.'inc/FeedParser.php');
100
101        $feed = new FeedParser();
102        $feed->set_feed_url($url);
103        $rc = $feed->init();
104        if (!$rc) {
105            return false;
106        }
107
108        $posts = array();
109        foreach($feed->get_items() as $item) {
110            $posts[] = array(
111                'title'         => $item->get_title(),
112                'date'          => $item->get_local_date($conf['dformat']),
113                'permalink'     => $item->get_permalink(),
114                'description'   => $item->get_description(),
115                'tags'          => $this->tags($item->get_categories())
116            );
117        }
118        return $posts;
119    }
120
121    function page_exists($url) {
122        require_once(DOKU_INC.'inc/FeedParser.php');
123        $feed  = new FeedParser();
124        $feed->set_feed_url($url);
125        $feed->init();
126        return $feed->get_item_quantity();
127    }
128
129    function get_url_parameters() {
130        $parameters = array(
131            'page'      => $_REQUEST['page'] ? $_REQUEST['page'] : 0,
132            'post'      => $_REQUEST['post'],
133            'search'    => $_REQUEST['search'],
134            'tagged'    => $_REQUEST['tagged']
135        );
136        return $parameters;
137    }
138
139    function get_url($page=false) {
140        $url = $this->tumblr_url;
141        $params = $this->get_url_parameters();
142        if ($page !== false) {
143            $params['page'] = $page;
144        }
145        // return rss url by URL parameter
146        if ($params['search']) {
147            $new_url = $url.'/search/'.$params['search'].'/page/'.$params['page'].'/rss';
148        } elseif ($params['tagged']) {
149            $new_url = $url.'/tagged/'.$params['tagged'].'/page/'.$params['page'].'/rss';
150        } elseif ($params['post']) {
151            $new_url = $url.'/'.$params['post'].'/rss';
152        } else {
153            $new_url = $url.'/page/'.$params['page'].'/rss';
154        }
155        return $new_url;
156    }
157
158    function tags($tags) {
159        // SimplePie Object to Array
160        if(!$tags) {
161            return false;
162        }
163        $new_tags = array();
164        foreach($tags as $tag) {
165            $new_tags[] = $tag->term;
166        }
167        return $new_tags;
168    }
169
170    function make_link($url, $ID, $inner=false) {
171        // tumblr post url format is http://oo.tumblr.com/post/123456789012
172        $post_id = end(explode('/',$url));
173        $html .= '<a href="'.wl($ID, 'post='.$post_id).'">';
174        $html .= $inner ? $inner : $url;
175        $html .= '</a>';
176        return $html;
177    }
178
179    function print_tags($tags, $ID) {
180        if(!$tags) {
181            return false;
182        }
183        $html .= '<ul>';
184        foreach($tags as $tag) {
185            $html .= '<li>';
186            $html .= '<a href="'.wl($ID, 'tagged='.str_replace(" ", "-", $tag)).'">'.$tag.'</a>';
187            $html .= '</li>';
188        }
189        $html .= '</ul>';
190        return $html;
191    }
192
193    function get_nav_query($next) {
194        $params = $this->get_url_parameters();
195        // page 1 is not exists on tumblr
196        if ($next) {
197            $params['page'] = ($params['page'] == 0) ? 2 : $params['page'] + 1;
198        } else {
199            $params['page'] = ($params['page'] == 2) ? 0 : $params['page'] - 1;
200        }
201
202        // check url exists
203        $url = $this->get_url($params['page']);
204        if ($params['page'] >= 0 && $this->page_exists($url)) {
205            return http_build_query($params, '', '&amp;');
206        } else {
207            return false;
208        }
209    }
210
211    function tumblr($options) {
212        global $lang;
213        global $ID;
214        $this->tumblr_url = $options['url'];
215
216        $html = '';
217        $url = $this->get_url();
218        $pID = $options['target'] ? $options['target'] : $ID;
219        $posts = $this->load_rss($url);
220        if (!$posts) {
221            $html .= '<div class="tumblr-post">';
222            $html .= '<h2>'.$this->getLang('page_not_exists').'</h2>';
223            $html .= '<p>';
224            $html .= '<a href="javascript:history.go(-1)">'.$this->getLang('back_to_list').'</a><br />';
225            $html .= $this->getLang('err_shown_when');
226            $html .= '</p>';
227            $html .= '<ul>';
228            $html .= '<li>'.$this->getLang('err_no_result').'</li>';
229            $html .= '<li>'.$this->getLang('err_not_accessible').'</li>';
230            $html .= '<li>'.$this->getLang('err_wrong_url').'</li>';
231            $html .= '</ul>';
232            $html .= '</div>';
233            return $html;
234        }
235        // render page
236        $html .= '<div class="tumblr-container">';
237        if ($options['type'] != 'list') {
238            foreach($posts as $post) {
239                $html .= '<div class="tumblr-post">';
240                $html .= '<h2>'.$this->make_link($post['permalink'], $pID, $post['title']).'</h2>';
241                $html .= '<div>'.$post['description'].'</div>';
242
243                // post meta
244                $html .= '<div class="tumblr-meta">';
245                $html .= '<dl>';
246                $html .= '<dt>DATE</dt>';
247                $html .= '<dd>'.$post['date'].'</dd>';
248                $html .= '<dt>PERMALINK</dt>';
249                $html .= '<dd>'.$this->make_link($post['permalink'], $pID).'</dd>';
250                $html .= '</dl>';
251
252                // tags
253                if ($post['tags']) {
254                    $html .= '<div class="tumblr-tags">';
255                    $html .= $this->print_tags($post['tags'], $pID);
256                    $html .= '</div>';
257                }
258                $html .= '</div>';
259                $html .= '</div>'; // end of tumblr-post
260            }
261        } else {
262            $html .= '<div class="tumblr-list">';
263            $html .= '<table>';
264            foreach($posts as $post) {
265                $html .= '<tr>';
266                $html .= '<td class="post-date"><time>'.$post['date'].'</time></td>';
267                $html .= '<td class="post-title">';
268                $html .= $this->make_link($post['permalink'], $pID, $post['title']);
269                $html .= '</td>';
270                $html .= '</tr>';
271            }
272            $html .= '</table>';
273            $html .= '</div>';
274        }
275
276        // page navigation
277        $html .= '<div class="tumblr-nav">';
278        if ($_REQUEST['post']) {
279            $html .= '<div class="tumblr-btn-left" style="visibility:hidden">a</div>';
280            // go back to list
281            $html .= '<div class="tumblr-btn-right">';
282            $html .= '<a href="javascript:history.go(-1)">'.$this->getLang('back_to_list').'</a>';
283            $html .= '</div>';
284        } else {
285            $prev_query = $this->get_nav_query(false);
286            $next_query = $this->get_nav_query(true);
287            // left button
288            $html .= '<div class="tumblr-btn-left"';
289            if (!$prev_query) { $html .= ' style="visibility:hidden"'; }
290            $html .= '>';
291            $html .= '<a href="'.wl($ID, $prev_query).'">'.$this->getLang('newer_posts').'</a>';
292            $html .= '</div>';
293            // right button
294            $html .= '<div class="tumblr-btn-right"';
295            if (!$next_query) { $html .= ' style="visibility:hidden"'; }
296            $html .= '>';
297            $html .= '<a href="'.wl($ID, $next_query).'">'.$this->getLang('older_posts').'</a>';
298            $html .= '</div>';
299        }
300        // search form
301        if (!$options['search']) {
302            $html .= '<div class="tumblr-search">';
303            $html .= '<form method="get">';
304            $html .= '<input type="text" name="search">';
305            $html .= '<button type="submit">'.$lang['btn_search'].'</button>';
306            $html .= '</form>';
307            $html .= '</div>'; // end of tumblr-search
308        }
309        $html .= '<div class="tumblr-clear"></div>';
310        $html .= '</div>'; // end of tumblr-nav
311        $html .= '</div>'; // end of tumblr-container
312        return $html;
313    }
314}
315
316// vim:ts=4:sw=4:et:
317