1<?php
2/**
3 * swfObject Plugin
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     i-net software <tools@inetsoftware.de>
7 * @author     Gerry Weissbach <gweissbach@inetsoftware.de>
8 */
9
10
11// must be run within Dokuwiki
12if(!defined('DOKU_INC')) die();
13
14if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
15require_once(DOKU_PLUGIN.'syntax.php');
16
17/**
18 * All DokuWiki plugins to extend the parser/rendering mechanism
19 * need to inherit from this class
20 */
21class syntax_plugin_swfobject extends DokuWiki_Syntax_Plugin {
22
23	var $saveData = array();
24	var $swfID = array();
25
26	function getInfo(){
27        return array(
28            'author' => 'i-net software',
29            'email'  => 'tools@inetsoftware.de',
30            'date'   => '2010-03-18',
31            'name'   => 'swfObject',
32            'desc'   => 'The Plugin wraps the SWFObject which can display an alternative if Flash is not present.',
33        );
34    }
35
36    function getType(){ return 'protected';}
37    function getAllowedTypes() { return array('container','substition','protected','disabled','formatting','paragraphs'); }
38    function getPType(){ return 'block';}
39
40	function getSort(){ return 194; }
41	function connectTo($mode) {
42		$this->Lexer->addEntryPattern('<swfobject\s[^\r\n\|]*?>(?=.*?</swfobject.*?>)',$mode,'plugin_swfobject');
43	}
44
45	function postConnect() {
46		$this->Lexer->addExitPattern('</swfobject.*?>', 'plugin_swfobject');
47	}
48
49	/**
50	 * Handle the match
51	 */
52	function handle($match, $state, $pos, &$handler){
53
54		switch ($state) {
55			case DOKU_LEXER_ENTER:
56				if( preg_match('%<swfobject\s([^\r\n\|]*?)>%', $match, $matches) ) {
57
58					$conf = split('\?', $matches[1], 2);
59
60					$return = array(	'swffile' => $conf[0],
61										'width' => $this->getConf('width'),
62										'height' => $this->getConf('height'),
63										'minfla' => $this->getConf('minfla'),
64										'skiplinux' => $this->getConf('skiplinux'),
65										'autowidth' => $this->getConf('autowidth'),
66										'param' => array(
67															'play' => 'true',
68															'loop' => 'false',
69															'menu' => 'false',
70															'quality' => 'autohigh',
71															'scale' => 'default',
72															'salign' => '',
73															'wmode' => 'transparent',
74															'bgcolor' => '',
75															'base' => '',
76															'swliveconnect' => 'false',
77															'flashvars' => '',
78															'devicefont' => 'true',
79															'allowscriptaccess' => 'false',
80															'seamlesstabbing' => 'false',
81															'allowfullscreen' => 'false',
82															'allownetworking' => 'true'
83										)
84									);
85
86					$conf = explode('&', $conf[1]);
87					foreach ( $conf AS $keyValue ) {
88						list ($key, $value) = explode('=', $keyValue);
89						if (empty($key)) { continue; }
90
91						if ( substr($value, 0, 1) == ':' )
92							$value = ml(cleanID($value));
93
94						if ( in_array(strtolower($key), array_keys($return['param'])) ) {
95							$return['param'][strtolower($key)] = strtolower($value);
96						} else if ( in_array(strtolower($key), array_keys($return)) ) {
97								$return[strtolower($key)] = $value;
98						} else {
99								if ( !empty($return['param']['flashvars']) )
100									$return['param']['flashvars'] .= '&';
101								$return['param']['flashvars'] .= "$key=$value";
102						}
103					}
104
105					return array('SWFOBJECT__ENTER', $return);
106			}
107
108			break;
109
110			case DOKU_LEXER_UNMATCHED:
111					return array('SWFOBJECT__UNMATCHED', $match);
112			break;
113
114			case DOKU_LEXER_EXIT:
115					return array('SWFOBJECT__EXIT', $match);
116			break;
117        }
118        return false;
119    }
120
121	/**
122	 * Create output
123	 */
124	function render($mode, &$renderer, $inputData) {
125		global $conf;
126
127		if($mode == 'xhtml'){
128
129			list( $state, $data) = $inputData;
130			switch ( $state ) {
131				case 'SWFOBJECT__ENTER' :
132					$this->saveData[] = $data;
133					//Alternative Content
134					$swfID = "SWFObject__Alternative" . rand(0, 1000000);
135					$this->swfID[] = $swfID;
136
137					$renderer->doc .= <<<OUTPUT
138				<div id="$swfID" class="swfobject alternate show">
139				<!-- DEFAULT CONTENT -->
140OUTPUT;
141					return true;
142					break;
143
144				case 'SWFOBJECT__UNMATCHED' :
145					$renderer->doc .= $renderer->_xmlEntities($data);
146
147					return true;
148					break;
149
150				case 'SWFOBJECT__EXIT' :
151
152					$data = array_pop($this->saveData);
153					$swfID = array_pop($this->swfID);
154
155					$skipLinux = $data['skiplinux'] ? " && clientPC.indexOf('linux') == -1 ": '';
156
157					$file = ml($data['swffile'], null, true, '&');
158
159					$flashvars = "";
160					$params = "";
161					if ( is_array($data['param']) ) {
162						foreach( array_keys($data['param']) AS $paramKeys ) {
163							if ( empty( $paramKeys ) || empty($data['param'][$paramKeys]) ) { continue; }
164							if ( !empty($params) ) { $params.= ','; }
165							$params .= $paramKeys .':\''. $data['param'][$paramKeys] . '\'';
166						}
167					}
168
169					$attributes = "styleclass: 'swfobject'";
170					$autoWidth = '';
171					if ( $data['autowidth'] ) {
172						$autoWidth = "$('$swfID').style.width = \"100%\";";
173					}
174
175					$DOKU_BASE = DOKU_BASE;
176					$XI = ( $this->getConf("useExpressInstall") ) ? "\"{$DOKU_BASE}lib/plugins/swfobject/expressinstall.swf\"" : "null";
177					$JS = <<<JSOUTPUT
178
179					var counter$swfID = 10;
180					var addSWF$swfID = function () {
181
182						if ( counter$swfID <= 0 ) { if ( $('$swfID') ) $('$swfID').className += ' show'; return; }
183						if ( typeof addInitEvent == "undefined" ) { counter$swfID--; window.setTimeout("addSWF$swfID", 100); return; }
184
185						addInitEvent( function() {
186							if ( typeof swfobject != "undefined" $skipLinux) {
187								swfobject.embedSWF("$file", "$swfID", "{$data['width']}", "{$data['height']}", "{$data['minfla']}", $XI, { $flashvars }, { $params }, { $attributes }, null );
188								$autoWidth
189							} else {
190								if ( $('$swfID') ) $('$swfID').className += ' show';
191							}
192						});
193					};
194
195					if ( document.getElementById('$swfID') ) document.getElementById('$swfID').className = document.getElementById('$swfID').className.substr( 0, document.getElementById('$swfID').className.lastIndexOf("show")-1 );
196					addSWF$swfID();
197
198JSOUTPUT;
199					if ( $conf['compress'] ) $JS = $this->js_compress($JS);
200					$renderer->doc .= <<<OUTPUT
201
202				</div>
203
204				<script type="text/javascript">{$JS}</script>
205OUTPUT;
206				break;
207				return true;
208			}
209		}
210		return false;
211	}
212
213	/**
214	 * Strip comments and whitespaces from given JavaScript Code
215	 *
216	 * This is a port of Nick Galbreath's python tool jsstrip.py which is
217	 * released under BSD license. See link for original code.
218	 *
219	 * This was taken from the Core.
220	 *
221	 * @author Nick Galbreath <nickg@modp.com>
222	 * @author Andreas Gohr <andi@splitbrain.org>
223	 * @link   http://code.google.com/p/jsstrip/
224	 */
225	function js_compress($s){
226
227	    $s = ltrim($s);     // strip all initial whitespace
228	    $s .= "\n";
229	    $i = 0;             // char index for input string
230	    $j = 0;             // char forward index for input string
231	    $line = 0;          // line number of file (close to it anyways)
232	    $slen = strlen($s); // size of input string
233	    $lch  = '';         // last char added
234	    $result = '';       // we store the final result here
235
236	    // items that don't need spaces next to them
237	    $chars = "^&|!+\-*\/%=\?:;,{}()<>% \t\n\r'\"[]";
238
239	    while($i < $slen){
240	        // skip all "boring" characters.  This is either
241	        // reserved word (e.g. "for", "else", "if") or a
242	        // variable/object/method (e.g. "foo.color")
243	        while ($i < $slen && (strpos($chars,$s[$i]) === false) ){
244	            $result .= $s{$i};
245	            $i = $i + 1;
246	        }
247
248	        $ch = $s{$i};
249	        // multiline comments (keeping IE conditionals)
250	        if($ch == '/' && $s{$i+1} == '*' && $s{$i+2} != '@'){
251	            $endC = strpos($s,'*/',$i+2);
252	            if($endC === false) trigger_error('Found invalid /*..*/ comment', E_USER_ERROR);
253	            $i = $endC + 2;
254	            continue;
255	        }
256
257	        // singleline
258	        if($ch == '/' && $s{$i+1} == '/'){
259	            $endC = strpos($s,"\n",$i+2);
260	            if($endC === false) trigger_error('Invalid comment', E_USER_ERROR);
261	            $i = $endC;
262	            continue;
263	        }
264
265	        // tricky.  might be an RE
266	        if($ch == '/'){
267	            // rewind, skip white space
268	            $j = 1;
269	            while($s{$i-$j} == ' '){
270	                $j = $j + 1;
271	            }
272	            if( ($s{$i-$j} == '=') || ($s{$i-$j} == '(') ){
273	                // yes, this is an re
274	                // now move forward and find the end of it
275	                $j = 1;
276	                while($s{$i+$j} != '/'){
277	                    while( ($s{$i+$j} != '\\') && ($s{$i+$j} != '/')){
278	                        $j = $j + 1;
279	                    }
280	                    if($s{$i+$j} == '\\') $j = $j + 2;
281	                }
282	                $result .= substr($s,$i,$j+1);
283	                $i = $i + $j + 1;
284	                continue;
285	            }
286	        }
287
288	        // double quote strings
289	        if($ch == '"'){
290	            $j = 1;
291	            while( $s{$i+$j} != '"' && ($i+$j < $slen)){
292	                if( $s{$i+$j} == '\\' && ($s{$i+$j+1} == '"' || $s{$i+$j+1} == '\\') ){
293	                    $j += 2;
294	                }else{
295	                    $j += 1;
296	                }
297	            }
298	            $result .= substr($s,$i,$j+1);
299	            $i = $i + $j + 1;
300	            continue;
301	        }
302
303	        // single quote strings
304	        if($ch == "'"){
305	            $j = 1;
306	            while( $s{$i+$j} != "'" && ($i+$j < $slen)){
307	                if( $s{$i+$j} == '\\' && ($s{$i+$j+1} == "'" || $s{$i+$j+1} == '\\') ){
308	                    $j += 2;
309	                }else{
310	                    $j += 1;
311	                }
312	            }
313	            $result .= substr($s,$i,$j+1);
314	            $i = $i + $j + 1;
315	            continue;
316	        }
317
318	        // whitespaces
319	        if( $ch == ' ' || $ch == "\r" || $ch == "\n" || $ch == "\t" ){
320	            // leading spaces
321	            if($i+1 < $slen && (strpos($chars,$s[$i+1]) !== false)){
322	                $i = $i + 1;
323	                continue;
324	            }
325	            // trailing spaces
326	            //  if this ch is space AND the last char processed
327	            //  is special, then skip the space
328	            $lch = substr($result,-1);
329	            if($lch && (strpos($chars,$lch) !== false)){
330	                $i = $i + 1;
331	                continue;
332	            }
333	            // else after all of this convert the "whitespace" to
334	            // a single space.  It will get appended below
335	            $ch = ' ';
336	        }
337
338	        // other chars
339	        $result .= $ch;
340	        $i = $i + 1;
341	    }
342
343	    return trim($result);
344	}
345}
346
347//Setup VIM: ex: et ts=4 enc=utf-8 :