3 * NP_MitasNom ver 0.5.9.2
7 class NP_MitasNom extends NucleusPlugin {
8 var $actionplugin=false;
11 $this->_checkVersion();
14 function getMinNucleusVersion() { return 220; }
15 function getAuthor() { return 'Katsumi'; }
16 function getVersion() { return '0.5.9.2'; }
17 function getURL() {return 'http://japan.nucleuscms.org/wiki/plugins:mitasnom';}
18 function getDescription() { return $this->translated('WYSIWYG HTML editor plagin using FCKeditor'); }
19 function supportsFeature($what) { return (int)($what=='SqlTablePrefix'); }
21 // Install, upgrade options, and Refresh member options.
22 // Note: createOption() is overrided (see below).
23 $this->createOption('version','version','text',$this->getVersion(),'access=hidden');
24 $this->createOption('width',$this->translated('Width'),'text','100%');
25 $this->createOption('height',$this->translated('Height'),'text','400');
26 $this->createOption('toolbar',$this->translated('Toolbar'),'select','Default','Default|Default|Full|Full|Basic|Basic|Custom|Custom');
27 $this->createOption('toolbar_custom',$this->translated('Custom Toolbar'), 'textarea',
28 "['Source','DocProps','-','Save','NewPage','Preview','-','Templates'],\n".
29 "['Cut','Copy','Paste','PasteText','PasteWord','-','Print','SpellCheck'],\n".
30 "['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],\n".
31 "['Bold','Italic','Underline','StrikeThrough','-','Subscript','Superscript'],\n".
32 "['OrderedList','UnorderedList','-','Outdent','Indent'],\n".
33 "['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],\n".
34 "['Link','Unlink','Anchor'],\n".
35 "['Image','Flash','Table','Rule','Smiley','SpecialChar','PageBreak','UniversalKey'],\n".
36 "['Form','Checkbox','Radio','TextField','Textarea','Select','Button','ImageButton','HiddenField'],'/',\n".
37 "['Style','FontFormat','FontName','FontSize'],\n".
38 "['TextColor','BGColor'],\n".
40 $this->createOption('addremovetoolbar',$this->translated('Add new toolbar to the menu / Delete toolbar from the menu'),'text','');
41 $this->createOption('returnafterbr',$this->translated('"<br />" => "<br />\n" conversion?'),'yesno','yes');
42 $this->createOption('returnafterbrbr',$this->translated('"<br /><br />" => "<br />\n<br />\n" conversion?'),'yesno','no');
43 $this->createOption('dialogwidth',$this->translated('Width of Popup dialog'),'text','500');
44 $this->createOption('dialogheight',$this->translated('Height of Popup dialog'),'text','450');
45 $this->createOption('protectedsource',$this->translated('Protected Sources'), 'textarea',
46 '/<script[\s\S]*?\/script>/gi'."\n".
48 //$this->createOption('additionalpsource',$this->translated('Additional Protected Sources'), 'textarea','');
49 $this->createOption('usemembersettings',$this->translated('Use member-specific settings?'),'yesno','no');
50 $this->createOption('useimagemanager',$this->translated('Use Image-Manager plugin instead of media.php?'),'yesno','no');
51 $this->createOption('usehttps',$this->translated('Use secure server (https) for edititing item?'),'yesno','no');
52 $this->createOption('usep',$this->translated('Use P tag instead of BR for enter key (IE only)?'),'yesno','no');
54 function getEventList() { return array('EditItemFormExtras','AddItemFormExtras','PrepareItemForEdit',
55 'PreAddItem','PreUpdateItem',
56 'PreItem','PostPluginOptionsUpdate','PrePluginOptionsEdit'); }
58 // SkinVar is currently used for showing link to create item
59 function doSkinVar($skinType,$type,$text='') {
60 global $blogid,$CONF,$member;
61 switch (strtolower($type)) {
64 if (!$member->isLoggedIn()) return;
65 if (!$text) $text=$this->translated('New Item with WYSIWYG');
66 $url=$CONF['ActionURL'].'?action=plugin&name=MitasNom&type=createitem&blogid='.$blogid;
67 $url=htmlspecialchars($url);
68 if ($this->getOption('usehttps')=='yes') $url=preg_replace('/^http:/','https:',$url);
69 echo "<a href=\"$url\">$text</a>\n";
74 // TemplateVar is currently used for showing link to edit item
75 function doTemplateVar(&$item,$type,$text='') {
77 switch (strtolower($type)) {
80 if (!$text) $text=$text=$this->translated('Edit Item with WYSIWYG');
81 $itemid=$item->itemid;
82 $url=htmlspecialchars($url);
83 if ($this->getOption('usehttps')=='yes') $url=preg_replace('/^http:/','https:',$url);
84 $url=$CONF['ActionURL'].'?action=plugin&name=MitasNom&type=itemedit&itemid='.$itemid;
85 echo "<a href=\"$url\">$text</a>\n";
90 // Action is used to show item-editing/newitem-creating window.
91 function doAction($type){
92 global $DIR_LIBS,$member,$manager,$CONF,$blogid,$itemid;
93 if (!$member->isLoggedIn()) return _NOTLOGGEDIN;
94 if (!strstr('createitem itemedit',$type)) return _BADACTION;
96 // Resolve itemid and blogid
97 if (!$blogid && $itemid) $blogid=getBlogIDFromItemID($itemid);
98 if (!$blogid) return _BADACTION;
99 if (!$member->teamRights($blogid)) return _ERROR_DISALLOWED;
100 $blog=&$manager->getBlog($blogid);
102 if ($blog) if ($blog->convertBreaks()) $convBreaks=true;
105 $this->actionplugin=true;
106 include($DIR_LIBS . 'ADMIN.php');
111 $a->action_createitem();
112 $buff=ob_get_contents();
117 $a->action_itemedit();
118 $buff=ob_get_contents();
125 // Return if not valid editing HTML
126 // These codes must be changed when non-compatible Nucleus version comes out.
127 if (!preg_match('/<head>/',$buff)) return _ERRORMSG;
128 if (!preg_match('/<div class="jsbuttonbar">/',$buff)) return _ERRORMSG;
129 if (!preg_match('/<textarea([^>]*)inputbody([^>]*)>([^>]*)<\/textarea>/',$buff)) return _ERRORMSG;
130 if (!preg_match('/<textarea([^>]*)inputmore([^>]*)>([^>]*)<\/textarea>/',$buff)) return _ERRORMSG;
132 // Create NucleusFCKeditor instances
133 if (!class_exists('NucleusFCKeditor')) include ($this->getDirectory().'fckclass.php');
136 if ($type=='itemedit') {
137 if (preg_match ('/<textarea([^>]*)inputbody([^>]*)>([^>]*)<\/textarea>/',$buff,$matches))
139 $body=$this->unhtmlentities($body);
140 if (preg_match ('/<textarea([^>]*)inputmore([^>]*)>([^>]*)<\/textarea>/',$buff,$matches))
142 $more=$this->unhtmlentities($more);
145 $body=addBreaks($body);
146 $more=addBreaks($more);
148 $FCKedit1=new NucleusFCKEditor('body',$this,$body);
149 $FCKedit2=new NucleusFCKEditor('more',$this,$more);
150 $buff1=$FCKedit1->CreateHtml();
151 $buff2=$FCKedit2->CreateHtml();
153 // Replace texts of editing page
154 // These codes must be changed when non-compatible Nucleus version comes out.
155 $buff=preg_replace ('/<head>/','<head><base href="'.$CONF['AdminURL'].'">', $buff,1);
156 $buff=preg_replace ('/<div class="jsbuttonbar">/','<div class="jsbuttonbar" style="DISPLAY: none;">', $buff,2);
157 $buff=preg_replace ('/<textarea([^>]*)inputbody([^>]*)>([^>]*)<\/textarea>/',$buff1, $buff,1);
158 $buff=preg_replace ('/<textarea([^>]*)inputmore([^>]*)>([^>]*)<\/textarea>/',$buff2, $buff,1);
162 // Solve <%image%> tag for showing items
163 function event_PreItem(&$data) {
164 $item=&$data['item'];
165 $pattern=$this->_patternBeforeEdit();
166 $replace=$this->_replaceBeforeEdit($item->authorid);
167 for ($i=0;$i<1;$i++){
168 $item->body=preg_replace($pattern[$i],$replace[$i],$item->body);
169 $item->more=preg_replace($pattern[$i],$replace[$i],$item->more);
173 // NP_MitasNom option in editing dialog.
174 // This is more compatible to newer Nucleus version,
175 // unless 'id="inputbody"' and 'id="inputmore"' changed.
176 function event_AddItemFormExtras(&$data) { return $this->event_EditItemFormExtras($data); }
177 function event_EditItemFormExtras(&$data) {
178 global $DIR_LIBS,$member,$manager,$CONF,$blogid,$itemid;
179 // Resolve itemid and blogid
180 if (!$blogid && $itemid) $blogid=getBlogIDFromItemID($itemid);
181 if (!$blogid) return _BADACTION;
182 if (!$member->teamRights($blogid)) return _ERROR_DISALLOWED;
183 $blog=&$manager->getBlog($blogid);
185 if ($blog) if ($blog->convertBreaks()) $convBreaks=true;
186 $authorid=$member->getID();
188 $item=&$manager->getItem($itemid,1,1);
189 $authorid=$item['authorid'];
192 if ($this->actionplugin) {
193 echo '<input type="hidden" name="mitasnom_wysiwyged" id="mitasnom_wysiwyged" value="full"/>';
195 } else echo '<input type="hidden" name="mitasnom_wysiwyged" id="mitasnom_wysiwyged" value=""/>';
196 $dwidth=$this->this_getOption('dialogwidth');
197 $dheight=$this->this_getOption('dialogheight');
198 $mURL=$CONF['MediaURL'].$member->getID().'/';
201 <script type="text/javascript">
203 function WYSIWYGpopup(textId){
204 window.open('plugins/mitasnom/popup.php?blogid=<?php echo (int)$blogid; ?>&id='+textId,'name',
205 <?php echo "'status=yes,toolbar=no,scrollbars=yes,resizable=yes,width=$dwidth,height=$dheight,top=0,left=0');\n"; ?>
207 function convBreaks(T) {
209 T=T.replace(/\x0D\x0A/g,"\x0A");
210 T=T.replace(/\x0D/g,"\x0A");
211 T=T.replace(/\x0A/g,"<br />\x0A");
214 function rmvBreaks(T) {
216 T=T.replace(/\x0A/g,'');
217 T=T.replace(/\x0D/g,'');
218 T=T.replace(/<br \/>/g,'\n');
220 if ($this->this_getOption('returnafterbrbr')!='yes')
221 echo 'while (T.match(/\n\n/g)) T=T.replace(/\n\n/g,"\n<br />");'."\n";
222 echo 'while (T.match(/<br \/>\n/g)) T=T.replace(/<br \/>\n/g,"<br /><br />");'."\n";
224 T=T.replace(/\n<br \/>/g,'<br />\n');
227 function WYSIWYGgettext(id){
228 var T=document.getElementById(id).value+'';
230 if ($convBreaks) echo "\tT=convBreaks(T);\n";
231 $replacearray=$this->_replaceBeforeEdit($authorid);
232 foreach($this->_patternBeforeEdit() as $key => $pattern) {
233 $replace=$replacearray[$key];
234 echo "\tT=T.replace($pattern"."g,'$replace');\n";
239 function WYSIWYGsettext(id,T){
241 if ($convBreaks) echo "\tT=rmvBreaks(T);\n";
242 $replacearray=$this->_replaceAfterEdit();
243 foreach($this->_patternAfterEdit() as $key => $pattern) {
244 $replace=$replacearray[$key];
245 echo "\tT=T.replace($pattern"."g,'$replace');\n";
248 document.getElementById(id).value=T;
249 document.getElementById('mitasnom_wysiwyged').value='image';
254 <a href="javascript:WYSIWYGpopup('inputbody');" title="Edit by HTML editor"><?php echo $this->translated('WYSIWYG:body'); ?></a>
255 <a href="javascript:WYSIWYGpopup('inputmore');" title="Edit by HTML editor"><?php echo $this->translated('WYSIWYG:more'); ?></a>
260 //<%image%>, <%popup%> conversion
261 function event_PrepareItemForEdit(&$data) {
262 global $CONF,$member;
263 if (!$this->actionplugin) return;
264 $item=&$data['item'];
265 $pattern=$this->_patternBeforeEdit();
266 $replace=$this->_replaceBeforeEdit($item['authorid']);
267 $item['body']=preg_replace($pattern,$replace,$item['body']);
268 $item['more']=preg_replace($pattern,$replace,$item['more']);
271 // Creates Nucleus-specific tags (<%image%> <%popup%>) from general HTML tags.
272 function event_PreAddItem(&$item) { return $this->event_PreUpdateItem($item); }
273 function event_PreUpdateItem(&$item) {
274 if (!requestVar('mitasnom_wysiwyged')) return;
275 $body=&$item['body'];
276 $more=&$item['more'];
277 $blog=&$item['blog'];
278 $body=$this->_restoreImgPopup($body);
279 $more=$this->_restoreImgPopup($more);
280 if (requestVar('mitasnom_wysiwyged')!='full') return;
281 if ($blog->convertBreaks()) {
282 $body=removeBreaks($body);
283 $more=removeBreaks($more);
285 if ($this->this_getOption('returnafterbr')=='yes') {
286 $body=$this->_addEnterAfterBr($body);
287 $more=$this->_addEnterAfterBr($more);
289 $pattern=$this->_patternAfterEdit();
290 $replace=$this->_replaceAfterEdit();
291 $body=preg_replace($pattern,$replace,$body);
292 $more=preg_replace($pattern,$replace,$more);
294 function _addEnterAfterBr(&$data){
295 // <br/> => <br/>\n conversion
297 $data=str_replace(array("\r","\n"),'',$data);
299 if (($i=strpos($data,'<br />'))===false) break;
300 $ret.=substr($data,0,$i+6);
301 $data=substr($data,$i+6);
302 if (substr($data,0,1)=="\x0D" || substr($data,0,1)=="\x0A") continue;
303 if (substr($data,0,6)!='<br />' || $this->this_getOption('returnafterbrbr')=='yes') $ret.="\n";
307 function _restoreImgPopup(&$data){
308 global $CONF,$member,$DIR_MEDIA;
309 //$mURL=$CONF['MediaURL'].$member->getID().'/';
310 $mURL=$CONF['MediaURL'];
311 $pattern='/<img [^>]*?src="'.str_replace('/','\/',$mURL).'[^"]*?"[^>]*? \/>/';
312 if (preg_match_all ( $pattern, $data, $matches,PREG_SET_ORDER)) {
313 foreach($matches as $match){
315 $src=$width=$height=$alt='';
317 foreach(explode('" ',substr($subject,5)) as $value) {
318 $i=strpos($value,'=');
319 $j=strpos($value,'"');
320 if ($i===false || $j===false) continue;
321 $key=substr($value,0,$i);
322 $value=substr($value,$j+1);
325 if (preg_match('/src="'.str_replace('/','\/',$mURL).'([^"]*?)"/',$subject,$match)) $src=$match[1];
338 if (!$prop['title']) $prop['title']=$prop['alt'];
339 if (!$prop['alt']) $prop['alt']=$prop['title'];
340 foreach ($prop as $key => $value) {
341 if (!$alt) $alt.=' ';
342 $alt.=$key.'="'.$value.'"';
344 $data=str_replace($subject,"<%image($src|$width|$height|$alt)%>",$data);
347 $pattern='/<a [\s\S]*?href="'.str_replace('/','\/',$mURL).'[^"]*?"[\s\S]*?<\/a>/';
348 if (preg_match_all ( $pattern, $data, $matches,PREG_SET_ORDER)) {
350 foreach($matches as $match){
352 if (preg_match('/href="'.str_replace('/','\/',$mURL).'([^"]*?)"/',$subject,$match)) $href=$match[1];
354 if (preg_match('/title="width=([^\|]*?)\|height=([^"]*?)"/',$subject,$match)) {
358 $old_level = error_reporting(0);
359 $size = @GetImageSize($DIR_MEDIA.$href);
360 error_reporting($old_level);
361 $width = ($height = 0);
367 if (preg_match('/>([^<]*?)<\/a>/',$subject,$match)) $alt=$match[1];
369 if (!$width) $width=100;
370 if (!$height) $height=100;
371 if ($alt) $data=str_replace($subject,"<%popup($href|$width|$height|$alt)%>",$data);
377 //Replacement for <%image%>, <%popup%>
378 function _patternBeforeEdit(){
379 return array( '/<%image\(([0-9]*?)\/([^\|]*?)\|([0-9]*?)\|([0-9]*?)\|([^\)]*?)alt="([^"]*?)"([^\)]*?)\)%>/',
380 '/<%image\(([^\|\/]*?)\|([0-9]*?)\|([0-9]*?)\|([^\)]*?)alt="([^"]*?)"([^\)]*?)\)%>/',
381 '/<%image\(([^\|]*?)\|([0-9]*?)\|([0-9]*?)\|([^\)]*?)alt="([^"]*?)"([^\)]*?)\)%>/',
382 '/<%image\(([0-9]*?)\/([^\|]*?)\|([0-9]*?)\|([0-9]*?)\|([^\)]*?)\)%>/',
383 '/<%image\(([^\|\/]*?)\|([0-9]*?)\|([0-9]*?)\|([^\)]*?)\)%>/',
384 '/<%image\(([^\|]*?)\|([0-9]*?)\|([0-9]*?)\|([^\)]*?)\)%>/',
385 '/<%popup\(([0-9]*?)\/([^\|]*?)\|([0-9]*?)\|([0-9]*?)\|([^\)]*?)\)%>/',
386 '/<%popup\(([^\|\/]*?)\|([0-9]*?)\|([0-9]*?)\|([^\)]*?)\)%>/',
387 '/<%popup\(([^\|]*?)\|([0-9]*?)\|([0-9]*?)\|([^\)]*?)\)%>/',
390 function _replaceBeforeEdit($authorid) {
392 $mURL=$CONF['MediaURL'].$authorid.'/';
393 return array( '<img src="'.$CONF['MediaURL'].'$1/$2" width="$3" height="$4" $5 alt="$6"$7 />',
394 '<img src="'.$mURL.'$1" width="$2" height="$3" $4 alt="$5"$6 />',
395 '<img src="'.$CONF['MediaURL'].'$1" width="$2" height="$3" $4 alt="$5"$6 />',
396 '<img src="'.$CONF['MediaURL'].'$1/$2" width="$3" height="$4" alt="$5" title="$5" />',
397 '<img src="'.$mURL.'$1" width="$2" height="$3" alt="$4" title="$4" />',
398 '<img src="'.$CONF['MediaURL'].'$1" width="$2" height="$3" alt="$4" title="$4" />',
399 '<a href="'.$CONF['MediaURL'].'$1/$2" title="width=$3|height=$4">$5</a>',
400 '<a href="'.$mURL.'$1" title="width=$2|height=$3">$4</a>',
401 '<a href="'.$CONF['MediaURL'].'$1" title="width=$2|height=$3">$4</a>',
402 '<mitasnom title="nucleustag"></mitasnom><%$1%>');
404 function _patternAfterEdit(){
405 return array( '/<mitasnom title="nucleustag"><\/mitasnom>/');
407 function _replaceAfterEdit() {
411 // Show information when editing plugin option
413 function event_PrePluginOptionsEdit($data){
414 if ($this->errormessage) echo "<h4>".$this->errormessage."</h4>";
416 function returnWithMessage($text) { $this->errormessage=$text;}
418 // Customize toolbar menu
419 function event_PostPluginOptionsUpdate($data) {
420 $plugid=$data['plugid'];
421 if ($plugid!=$this->GetID()) return;
422 $this->install();// Refresh member option settings.
423 if (!($name=$this->getOption('addremovetoolbar'))) return;
424 $name=ereg_replace("[^0-9a-zA-Z]","",$name);
425 $this->setOption('addremovetoolbar','');
426 if (!($toolbar=$this->getOption('toolbar_custom')))
427 return $this->returnWithMessage($this->translated('Toolbar definition is empty'));
428 if (strstr(' default full basic custom ',strtolower($name)))
429 return $this->returnWithMessage($this->translated('Default, Full, Basic and Custom toolbars cannot be removed.'));
430 $ret=$this->getOption('toolbar_'.strtolower($name));//$ret=$this->getOption('toolbar_'.$this);
431 if (!($oid=$this->this_getOid('toolbar'))) return;
432 if (!($extra=$this->this_getExtra($oid))) return;
433 if (strstr(strtolower($extra),strtolower($name))) {
435 $extra=eregi_replace("\|$name\|$name","",$extra);
436 sql_query('UPDATE ' . sql_table('plugin_option_desc') .
437 ' SET oextra = "'.addslashes($extra). '" WHERE oid=' . (int)$oid);
438 $this->deleteOption('toolbar_'.strtolower($name));
439 $this->returnWithMessage($name.$this->translated(' toolbar is deleted.'));
442 $extra=str_replace("|Custom|Custom","|$name|$name|Custom|Custom",$extra);
443 sql_query('UPDATE ' . sql_table('plugin_option_desc') .
444 ' SET oextra = "'.addslashes($extra). '" WHERE oid=' . (int)$oid);
445 $this->createOption('toolbar_'.strtolower($name), $name.$this->translated(' Toolbar'), 'textarea', $toolbar);
446 $this->returnWithMessage($name.$this->translated(' toolbar is added.'));
450 // Member specific stuff
451 function this_getOption($name) {
453 if ($this->getOption('usemembersettings')!='yes') return $this->getOption($name);
454 if (!$this->_useMemberSpecificOption($name)) return $this->getOption($name);
455 return $this->getMemberOption($member->getID(), $name);
457 function _useMemberSpecificOption($name) {
458 foreach ($this->_allMemberSpecificOptions() as $value) if ($name==$value) return true;
461 function _allMemberSpecificOptions() {
462 return array('width','height','toolbar','returnafterbr','returnafterbrbr',
463 'dialogwidth','dialogheight','additionalpsource');
467 function this_getOid($name,$context='global'){
468 $query = 'SELECT oid, oname FROM ' . sql_table('plugin_option_desc') .
469 ' WHERE opid=' . intval($this->plugid).
470 ' and ocontext="'.addslashes($context).'"';
471 $res = sql_query($query);
472 while ($o = mysql_fetch_object($res)) if ($o->oname==$name) return $o->oid;
475 function this_getExtra($oid){
476 $query = 'SELECT oextra FROM ' . sql_table('plugin_option_desc') . ' WHERE oid=' . intval($oid);
477 $res = sql_query($query);
478 if ($o = mysql_fetch_object($res)) return $o->oextra;
483 function _checkVersion(){
484 if (!$this->this_getOid('version')) $this->install();
485 else if ($this->getVersion()!=$this->getOption('version')) $this->install();
486 $this->setOption('version',$this->getVersion());
489 // Overrided function
490 function createOption($name, $desc, $type, $defValue = '', $typeExtras = '') {
491 if (!$this->this_getOid($name)) parent::createOption($name, $desc, $type, $defValue, $typeExtras);
492 if ($this->_useMemberSpecificOption($name)) {
493 if ($this->getOption('usemembersettings')=='yes') {
494 if (!$this->this_getOid($name,'member')) {
495 if ($name=='toolbar') {
496 $typeExtras=quickQuery(
497 'SELECT oextra as result FROM '.sql_table('plugin_option_desc').
498 ' WHERE opid='.(int)$this->getID().' AND oname="toolbar"');
500 if (($Extras=$typeExtras)=='access=hidden') $Extras='';
501 $Extras=str_replace('|Custom|Custom','',$Extras);
502 $Extras=str_replace('|Full|Full','',$Extras);
503 $this->createMemberOption($name, $desc, $type,$this->getOption($name), $Extras);
506 if ($this->this_getOid($name,'member'))
507 $this->deleteMemberOption($name);
515 function translated($english){
516 if (!is_array($this->langArray)) {
517 $this->langArray=array();
518 $language=$this->getDirectory().'language/'.ereg_replace( '[\\|/]', '', getLanguageName()).'.php';
519 if (file_exists($language)) include($language);
521 if (!($ret=$this->langArray[$english])) $ret=$english;
525 // General function (found on PHP help page) follows
526 function unhtmlentities($string) {
527 $trans_tbl = get_html_translation_table (HTML_ENTITIES);
528 $trans_tbl = array_flip ($trans_tbl);
529 return strtr ($string, $trans_tbl);