1<?php
2/**
3 * Plugin OpenStreetMap: Allow Display of a OpenStreetMap in a wiki page.
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Michael Hamann <michael@content-space.de>
7 * @author     Christopher Smith <chris@jalakai.co.uk>
8 */
9
10if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../../').'/');
11if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC.'lib/plugins/');
12require_once(DOKU_PLUGIN.'syntax.php');
13
14/**
15 * All DokuWiki plugins to extend the parser/rendering mechanism
16 * need to inherit from this class
17 */
18class syntax_plugin_osm extends DokuWiki_Syntax_Plugin {
19    var $defaults = array
20        (
21            'width' => 450,
22            'height' => 320,
23            'lat' => -4.25,
24            'lon' => 55.833,
25            'zoom' => 8,
26            'layer' => 'mapnik'
27        );
28    var $constraints = array
29        (
30            'width' => array('min' => 100, 'max' => 1000),
31            'height' => array('min' => 99, 'max' => 1500),
32            'zoom' => array('min' => 0, 'max' => 18),
33            'lat' => array('min' => -90, 'max' => 90),
34            'lon' => array('min' => -180, 'max' => 180),
35        );
36
37    var $urlMappings = array
38        (
39            'zoom' => 'z',
40            'width' => 'w',
41            'height' => 'h',
42            'lon' => 'long'
43        );
44
45
46    var $layers = array('osmarender', 'mapnik');
47
48    function getType() { return 'substition'; }
49    function getPType() { return 'block'; }
50    function getSort() { return 900; }
51
52    function connectTo($mode) {
53        $this->Lexer->addSpecialPattern('<osm ?[^>\n]*>.*?</osm>', $mode, 'plugin_osm');
54    }
55
56    function handle($match, $state, $pos, Doku_Handler $handler) {
57
58        // break matched cdata into its components
59        list($str_params, $str_markers) = explode('>', substr($match, 4, -6), 2);
60
61        $param = array();
62        preg_match_all('/(\w*)="(.*?)"/us', $str_params, $param, PREG_SET_ORDER);
63
64        $opts = array();
65
66        foreach($param as $kvpair) {
67            list($match, $key, $val) = $kvpair;
68            $key = strtolower($key);
69            switch ($key) {
70            case 'layer':
71                if (in_array($val, $this->layers))
72                    $opts['layer'] = $val;
73                break;
74            case 'lon':
75            case 'lat':
76                $val = (float) $val;
77                if ($val >= $this->constraints[$key]['min'] && $val <= $this->constraints[$key]['max'])
78                    $opts[$key] = $val;
79                break;
80            case 'width':
81            case 'height':
82            case 'zoom':
83                $val = (int) $val;
84                if ($val >= $this->constraints[$key]['min'] && $val <= $this->constraints[$key]['max'])
85                    $opts[$key] = $val;
86                break;
87            }
88        }
89
90        $markers = $this->_extract_markers($str_markers);
91
92        return array($opts, $markers);
93    }
94
95    function render($mode, Doku_Renderer $renderer, $data) {
96        if ($mode == 'xhtml') {
97            list($options, $markers) = $data;
98
99            $options = array_merge($this->defaults, $options);
100
101            $json = new JSON();
102
103            $renderer->doc .= '<div class="openstreetmap" style="width: '.$options['width'].'px; height: '.$options['height'].'px;">'.DOKU_LF;
104            $renderer->doc .= "<a href=\"".$this->getLinkURL($options)."\" title=\"See this map on OpenStreetMap.org\">".DOKU_LF;
105            $renderer->doc .= "<img alt=\"OpenStreetMap\" src=\"".$this->getImageURL($options)."\" />".DOKU_LF;
106            $renderer->doc .= "</a>".DOKU_LF;
107            $renderer->doc .= "<!-- ".$json->encode($markers)." -->";
108            $renderer->doc .= "</div>".DOKU_LF;
109            return true;
110        }
111
112        return false;
113    }
114
115    /**
116     * extract markers for the osm from the wiki syntax data
117     *
118     * @param   string    $str_markers   multi-line string of lat,lon,txt triplets
119     * @return  array                   array of markers as associative array
120     */
121    function _extract_markers($str_markers) {
122
123        $point = array();
124        preg_match_all('/^(.*?),(.*?),(.*)$/um', $str_markers, $point, PREG_SET_ORDER);
125
126        $overlay = array();
127        foreach ($point as $pt) {
128            list($match, $lat, $lon, $txt) = $pt;
129
130            $lat = is_numeric($lat) ? (float)$lat : 0;
131            $lon = is_numeric($lon) ? (float)$lon : 0;
132            $txt = addslashes(str_replace("\n", "", p_render("xhtml", p_get_instructions($txt), $info)));
133
134            $overlay[] = compact('lat', 'lon', 'txt');
135        }
136
137        return $overlay;
138    }
139
140    /**
141     * Generates the image URL for the map using the given mapserver.
142     *
143     * @param array $options The options to send
144     * @return string The URL to the static image of this map.
145     */
146    function getImageURL($options) {
147        // create the query string
148        $query_params = array('format=jpeg');
149        foreach ($options as $option => $value) {
150            $query_params[] = (array_key_exists($option, $this->urlMappings) ? $this->urlMappings[$option] : $option).'='.$value;
151        }
152
153        return ml(hsc($this->getConf('map_service_url'))."?".implode('&', $query_params), array('cache' => 'recache'));
154    }
155
156    /**
157     * Generates the link url for this map.
158     *
159     * @param array $options The options that shall be included in the url
160     * @return string The link url.
161     */
162    function getLinkURL($options) {
163        $link_query = array();
164
165        foreach ($options as $option => $value) {
166            $link_query[] = "$option=$value";
167        }
168        return 'http://www.openstreetmap.org/?'.implode('&amp;', $link_query);
169    }
170}
171
172
173// vim:ts=4:sw=4:et:
174