PageRenderTime 57ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/extensions/FCKeditor/FCKeditor.body.php

https://github.com/ChuguluGames/mediawiki-svn
PHP | 713 lines | 524 code | 97 blank | 92 comment | 148 complexity | d9815c338d75c443f04d22f8ca4b7b93 MD5 | raw file
  1. <?php
  2. /**
  3. * Options for FCKeditor
  4. * [start with FCKeditor]
  5. */
  6. define('RTE_VISIBLE', 1);
  7. /**
  8. * Options for FCKeditor
  9. * [show toggle link]
  10. */
  11. define('RTE_TOGGLE_LINK', 2);
  12. /**
  13. * Options for FCKeditor
  14. * [show popup link]
  15. */
  16. define('RTE_POPUP', 4);
  17. class FCKeditor_MediaWiki {
  18. public $showFCKEditor;
  19. private $count = array();
  20. private $excludedNamespaces;
  21. private $oldTextBox1;
  22. static $nsToggles = array(
  23. 'riched_disable_ns_main',
  24. 'riched_disable_ns_talk',
  25. 'riched_disable_ns_user',
  26. 'riched_disable_ns_user_talk',
  27. 'riched_disable_ns_project',
  28. 'riched_disable_ns_project_talk',
  29. 'riched_disable_ns_image',
  30. 'riched_disable_ns_image_talk',
  31. 'riched_disable_ns_mediawiki',
  32. 'riched_disable_ns_mediawiki_talk',
  33. 'riched_disable_ns_template',
  34. 'riched_disable_ns_template_talk',
  35. 'riched_disable_ns_help',
  36. 'riched_disable_ns_help_talk',
  37. 'riched_disable_ns_category',
  38. 'riched_disable_ns_category_talk',
  39. );
  40. function __call( $m, $a ) {
  41. print "\n#### " . $m . "\n";
  42. if( !isset( $this->count[$m] ) ) {
  43. $this->count[$m] = 0;
  44. }
  45. $this->count[$m]++;
  46. return true;
  47. }
  48. /**
  49. * Gets the namespaces where FCKeditor should be disabled
  50. * First check is done against user preferences, second is done against the global variable $wgFCKEditorExcludedNamespaces
  51. */
  52. private function getExcludedNamespaces() {
  53. global $wgUser, $wgDefaultUserOptions, $wgFCKEditorExcludedNamespaces;
  54. if( is_null( $this->excludedNamespaces ) ) {
  55. $this->excludedNamespaces = array();
  56. foreach( self::$nsToggles as $toggle ) {
  57. $default = isset( $wgDefaultUserOptions[$toggle] ) ? $wgDefaultUserOptions[$toggle] : '';
  58. if( $wgUser->getOption( $toggle, $default ) ) {
  59. $this->excludedNamespaces[] = constant( strtoupper( str_replace( 'riched_disable_', '', $toggle ) ) );
  60. }
  61. }
  62. /*
  63. If this site's LocalSettings.php defines Namespaces that shouldn't use the FCKEditor (in the #wgFCKexcludedNamespaces array), those excluded
  64. namespaces should be combined with those excluded in the user's preferences.
  65. */
  66. if( !empty( $wgFCKEditorExcludedNamespaces ) && is_array( $wgFCKEditorExcludedNamespaces ) ) {
  67. $this->excludedNamespaces = array_merge( $wgFCKEditorExcludedNamespaces, $this->excludedNamespaces );
  68. }
  69. }
  70. return $this->excludedNamespaces;
  71. }
  72. public static function onLanguageGetMagic( &$magicWords, $langCode ) {
  73. $magicWords['NORICHEDITOR'] = array( 0, '__NORICHEDITOR__' );
  74. return true;
  75. }
  76. public static function onParserBeforeInternalParse( &$parser, &$text, &$strip_state ) {
  77. MagicWord::get( 'NORICHEDITOR' )->matchAndRemove( $text );
  78. return true;
  79. }
  80. public function onEditPageShowEditFormFields( $pageEditor, $wgOut ) {
  81. global $wgUser, $wgFCKEditorIsCompatible, $wgTitle;
  82. /*
  83. If FCKeditor extension is enabled, BUT it shouldn't appear (because it's disabled by user, we have incompatible browser etc.)
  84. We must do this trick to show the original text as WikiText instead of HTML when conflict occurs
  85. */
  86. if ( ( !$wgUser->getOption( 'showtoolbar' ) || $wgUser->getOption( 'riched_disable' ) || !$wgFCKEditorIsCompatible ) ||
  87. in_array( $wgTitle->getNamespace(), $this->getExcludedNamespaces() ) || !( $this->showFCKEditor & RTE_VISIBLE ) ||
  88. false !== strpos( $pageEditor->textbox1, '__NORICHEDITOR__' )
  89. ) {
  90. if( $pageEditor->isConflict ) {
  91. $pageEditor->textbox1 = $pageEditor->getWikiContent();
  92. }
  93. }
  94. return true;
  95. }
  96. /**
  97. * @param $pageEditor EditPage instance
  98. * @param $out OutputPage instance
  99. * @return true
  100. */
  101. public static function onEditPageBeforeConflictDiff( $pageEditor, $out ) {
  102. global $wgRequest;
  103. /*
  104. Show WikiText instead of HTML when there is a conflict
  105. http://dev.fckeditor.net/ticket/1385
  106. */
  107. $pageEditor->textbox2 = $wgRequest->getVal( 'wpTextbox1' );
  108. $pageEditor->textbox1 = $pageEditor->getWikiContent();
  109. return true;
  110. }
  111. public static function onParserBeforeStrip( &$parser, &$text, &$stripState ) {
  112. $text = $parser->replaceVariables( $text );
  113. return true;
  114. }
  115. public static function onSanitizerAfterFixTagAttributes( $text, $element, &$attribs ) {
  116. $text = preg_match_all( "/Fckmw\d+fckmw/", $text, $matches );
  117. if( !empty( $matches[0][0] ) ) {
  118. global $leaveRawTemplates;
  119. if( !isset( $leaveRawTemplates ) ) {
  120. $leaveRawTemplates = array();
  121. }
  122. $leaveRawTemplates = array_merge( $leaveRawTemplates, $matches[0] );
  123. $attribs = array_merge( $attribs, $matches[0] );
  124. }
  125. return true;
  126. }
  127. public function onCustomEditor( $article, $user ) {
  128. global $wgRequest, $wgUseExternalEditor;
  129. $action = $wgRequest->getVal( 'action', 'view' );
  130. $internal = $wgRequest->getVal( 'internaledit' );
  131. $external = $wgRequest->getVal( 'externaledit' );
  132. $section = $wgRequest->getVal( 'section' );
  133. $oldid = $wgRequest->getVal( 'oldid' );
  134. if( !$wgUseExternalEditor || $action == 'submit' || $internal ||
  135. $section || $oldid || ( !$user->getOption( 'externaleditor' ) && !$external ) ) {
  136. $editor = new FCKeditorEditPage( $article );
  137. $editor->submit();
  138. } elseif( $wgUseExternalEditor && ( $external || $user->getOption( 'externaleditor' ) ) ) {
  139. $mode = $wgRequest->getVal( 'mode' );
  140. $extedit = new ExternalEdit( $article, $mode );
  141. $extedit->edit();
  142. }
  143. return false;
  144. }
  145. public function onEditPageBeforePreviewText( &$editPage, $previewOnOpen ) {
  146. global $wgUser, $wgRequest;
  147. if( $wgUser->getOption( 'showtoolbar' ) && !$wgUser->getOption( 'riched_disable' ) && !$previewOnOpen ) {
  148. $this->oldTextBox1 = $editPage->textbox1;
  149. $editPage->importFormData( $wgRequest );
  150. }
  151. return true;
  152. }
  153. public function onEditPagePreviewTextEnd( &$editPage, $previewOnOpen ) {
  154. global $wgUser;
  155. if( $wgUser->getOption( 'showtoolbar' ) && !$wgUser->getOption( 'riched_disable' ) && !$previewOnOpen ) {
  156. $editPage->textbox1 = $this->oldTextBox1;
  157. }
  158. return true;
  159. }
  160. public function onParserAfterTidy( &$parser, &$text ) {
  161. global $wgUseTeX, $wgUser, $wgTitle, $wgFCKEditorIsCompatible;
  162. # Don't initialize for users that have chosen to disable the toolbar, rich editor or that do not have a FCKeditor-compatible browser
  163. if( !$wgUser->getOption( 'showtoolbar' ) || $wgUser->getOption( 'riched_disable' ) || !$wgFCKEditorIsCompatible ) {
  164. return true;
  165. }
  166. # Are we editing a page that's in an excluded namespace? If so, bail out.
  167. if( is_object( $wgTitle ) && in_array( $wgTitle->getNamespace(), $this->getExcludedNamespaces() ) ) {
  168. return true;
  169. }
  170. if( $wgUseTeX ) {
  171. // it may add much overload on page with huge amount of math content...
  172. $text = preg_replace( '/<img class="tex" alt="([^"]*)"/m', '<img _fckfakelement="true" _fck_mw_math="$1"', $text );
  173. $text = preg_replace( "/<img class='tex' src=\"([^\"]*)\" alt=\"([^\"]*)\"/m", '<img src="$1" _fckfakelement="true" _fck_mw_math="$2"', $text );
  174. }
  175. return true;
  176. }
  177. /**
  178. * Adds some new JS global variables
  179. * @param $vars Array: array of JS global variables
  180. * @return true
  181. */
  182. public static function onMakeGlobalVariablesScript( $vars ){
  183. global $wgFCKEditorDir, $wgFCKEditorExtDir, $wgFCKEditorToolbarSet, $wgFCKEditorHeight;
  184. $vars['wgFCKEditorDir'] = $wgFCKEditorDir;
  185. $vars['wgFCKEditorExtDir'] = $wgFCKEditorExtDir;
  186. $vars['wgFCKEditorToolbarSet'] = $wgFCKEditorToolbarSet;
  187. $vars['wgFCKEditorHeight'] = $wgFCKEditorHeight;
  188. return true;
  189. }
  190. /**
  191. * Adds new toggles into Special:Preferences
  192. * @param $user User object
  193. * @param $preferences Preferences object
  194. * @return true
  195. */
  196. public static function onGetPreferences( $user, &$preferences ){
  197. global $wgDefaultUserOptions;
  198. $preferences['riched_disable'] = array(
  199. 'type' => 'toggle',
  200. 'section' => 'editing/fckeditor',
  201. 'label-message' => 'tog-riched_disable',
  202. );
  203. $preferences['riched_start_disabled'] = array(
  204. 'type' => 'toggle',
  205. 'section' => 'editing/fckeditor',
  206. 'label-message' => 'tog-riched_start_disabled',
  207. );
  208. $preferences['riched_use_popup'] = array(
  209. 'type' => 'toggle',
  210. 'section' => 'editing/fckeditor',
  211. 'label-message' => 'tog-riched_use_popup',
  212. );
  213. $preferences['riched_use_toggle'] = array(
  214. 'type' => 'toggle',
  215. 'section' => 'editing/fckeditor',
  216. 'label-message' => 'tog-riched_use_toggle',
  217. );
  218. $preferences['riched_toggle_remember_state'] = array(
  219. 'type' => 'toggle',
  220. 'section' => 'editing/fckeditor',
  221. 'label-message' => 'tog-riched_toggle_remember_state',
  222. );
  223. // Show default options in Special:Preferences
  224. if( !array_key_exists( 'riched_disable', $user->mOptions ) && !empty( $wgDefaultUserOptions['riched_disable'] ) )
  225. $user->setOption( 'riched_disable', $wgDefaultUserOptions['riched_disable'] );
  226. if( !array_key_exists( 'riched_start_disabled', $user->mOptions ) && !empty( $wgDefaultUserOptions['riched_start_disabled'] ) )
  227. $user->setOption( 'riched_start_disabled', $wgDefaultUserOptions['riched_start_disabled'] );
  228. if( !array_key_exists( 'riched_use_popup', $user->mOptions ) && !empty( $wgDefaultUserOptions['riched_use_popup'] ) )
  229. $user->setOption( 'riched_use_popup', $wgDefaultUserOptions['riched_use_popup'] );
  230. if( !array_key_exists( 'riched_use_toggle', $user->mOptions ) && !empty( $wgDefaultUserOptions['riched_use_toggle'] ) )
  231. $user->setOption( 'riched_use_toggle', $wgDefaultUserOptions['riched_use_toggle'] );
  232. if( !array_key_exists( 'riched_toggle_remember_state', $user->mOptions ) && !empty( $wgDefaultUserOptions['riched_toggle_remember_state'] ) )
  233. $user->setOption( 'riched_toggle_remember_state', $wgDefaultUserOptions['riched_toggle_remember_state'] );
  234. // Add the "disable rich editor on namespace X" toggles too
  235. foreach( self::$nsToggles as $newToggle ){
  236. $preferences[$newToggle] = array(
  237. 'type' => 'toggle',
  238. 'section' => 'editing/fckeditor',
  239. 'label-message' => 'tog-' . $newToggle
  240. );
  241. }
  242. return true;
  243. }
  244. /**
  245. * Add FCK script
  246. *
  247. * @param $form EditPage object
  248. * @return true
  249. */
  250. public function onEditPageShowEditFormInitial( $form ) {
  251. global $wgOut, $wgTitle, $wgScriptPath, $wgContLang, $wgUser;
  252. global $wgStylePath, $wgStyleVersion, $wgExtensionFunctions, $wgHooks, $wgDefaultUserOptions;
  253. global $wgFCKWikiTextBeforeParse, $wgFCKEditorIsCompatible;
  254. global $wgFCKEditorDir;
  255. if( !isset( $this->showFCKEditor ) ){
  256. $this->showFCKEditor = 0;
  257. if ( !$wgUser->getOption( 'riched_start_disabled', $wgDefaultUserOptions['riched_start_disabled'] ) ) {
  258. $this->showFCKEditor += RTE_VISIBLE;
  259. }
  260. if ( $wgUser->getOption( 'riched_use_popup', $wgDefaultUserOptions['riched_use_popup'] ) ) {
  261. $this->showFCKEditor += RTE_POPUP;
  262. }
  263. if ( $wgUser->getOption( 'riched_use_toggle', $wgDefaultUserOptions['riched_use_toggle'] ) ) {
  264. $this->showFCKEditor += RTE_TOGGLE_LINK;
  265. }
  266. }
  267. if( ( !empty( $_SESSION['showMyFCKeditor'] ) ) && ( $wgUser->getOption( 'riched_toggle_remember_state', $wgDefaultUserOptions['riched_toggle_remember_state'] ) ) ){
  268. // Clear RTE_VISIBLE flag
  269. $this->showFCKEditor &= ~RTE_VISIBLE;
  270. // Get flag from session
  271. $this->showFCKEditor |= $_SESSION['showMyFCKeditor'];
  272. }
  273. # Don't initialize if we have disabled the toolbar or FCkeditor or have a non-compatible browser
  274. if( !$wgUser->getOption( 'showtoolbar' ) ||
  275. $wgUser->getOption( 'riched_disable', !empty( $wgDefaultUserOptions['riched_disable'] ) ? $wgDefaultUserOptions['riched_disable'] : false )
  276. || !$wgFCKEditorIsCompatible ) {
  277. return true;
  278. }
  279. # Don't do anything if we're in an excluded namespace
  280. if( in_array( $wgTitle->getNamespace(), $this->getExcludedNamespaces() ) ) {
  281. return true;
  282. }
  283. # Make sure that there's no __NORICHEDITOR__ in the text either
  284. if( false !== strpos( $form->textbox1, '__NORICHEDITOR__' ) ) {
  285. return true;
  286. }
  287. $wgFCKWikiTextBeforeParse = $form->textbox1;
  288. if( $this->showFCKEditor & RTE_VISIBLE ){
  289. $options = new FCKeditorParserOptions();
  290. $options->setTidy( true );
  291. $parser = new FCKeditorParser();
  292. $parser->setOutputType( OT_HTML );
  293. $form->textbox1 = str_replace( '<!-- Tidy found serious XHTML errors -->', '', $parser->parse( $form->textbox1, $wgTitle, $options )->getText() );
  294. }
  295. $printsheet = htmlspecialchars( "$wgStylePath/common/wikiprintable.css?$wgStyleVersion" );
  296. $script = <<<HEREDOC
  297. <script type="text/javascript" src="$wgScriptPath/$wgFCKEditorDir/fckeditor.js"></script>
  298. <script type="text/javascript">
  299. var sEditorAreaCSS = '$printsheet,/mediawiki/skins/monobook/main.css?{$wgStyleVersion}';
  300. </script>
  301. <!--[if lt IE 5.5000]><script type="text/javascript">sEditorAreaCSS += ',/mediawiki/skins/monobook/IE50Fixes.css?{$wgStyleVersion}'; </script><![endif]-->
  302. <!--[if IE 5.5000]><script type="text/javascript">sEditorAreaCSS += ',/mediawiki/skins/monobook/IE55Fixes.css?{$wgStyleVersion}'; </script><![endif]-->
  303. <!--[if IE 6]><script type="text/javascript">sEditorAreaCSS += ',/mediawiki/skins/monobook/IE60Fixes.css?{$wgStyleVersion}'; </script><![endif]-->
  304. <!--[if IE 7]><script type="text/javascript">sEditorAreaCSS += ',/mediawiki/skins/monobook/IE70Fixes.css?{$wgStyleVersion}'; </script><![endif]-->
  305. <!--[if lt IE 7]><script type="text/javascript">sEditorAreaCSS += ',/mediawiki/skins/monobook/IEFixes.css?{$wgStyleVersion}'; </script><![endif]-->
  306. HEREDOC;
  307. # Show references only if Cite extension has been installed
  308. $showRef = false;
  309. if( ( isset( $wgHooks['ParserFirstCallInit'] ) && in_array( 'wfCite', $wgHooks['ParserFirstCallInit'] ) ) ||
  310. ( isset( $wgExtensionFunctions ) && in_array( 'wfCite', $wgExtensionFunctions ) ) ) {
  311. $showRef = true;
  312. }
  313. $showSource = false;
  314. if ( ( isset( $wgHooks['ParserFirstCallInit']) && in_array( 'efSyntaxHighlight_GeSHiSetup', $wgHooks['ParserFirstCallInit'] ) )
  315. || ( isset( $wgExtensionFunctions ) && in_array( 'efSyntaxHighlight_GeSHiSetup', $wgExtensionFunctions ) ) ) {
  316. $showSource = true;
  317. }
  318. $script .= '
  319. <script type="text/javascript">
  320. var showFCKEditor = ' . $this->showFCKEditor . ';
  321. var popup = false; // pointer to popup document
  322. var firstLoad = true;
  323. var editorMsgOn = "' . Xml::escapeJsString( wfMsgHtml( 'textrichditor' ) ) . '";
  324. var editorMsgOff = "' . Xml::escapeJsString( wfMsgHtml( 'tog-riched_disable' ) ) . '";
  325. var editorLink = "' . ( ( $this->showFCKEditor & RTE_VISIBLE ) ? Xml::escapeJsString( wfMsgHtml( 'tog-riched_disable' ) ) : Xml::escapeJsString( wfMsgHtml( 'textrichditor' ) ) ) . '";
  326. var saveSetting = ' . ( $wgUser->getOption( 'riched_toggle_remember_state', $wgDefaultUserOptions['riched_toggle_remember_state'] ) ? 1 : 0 ) . ';
  327. var RTE_VISIBLE = ' . RTE_VISIBLE . ';
  328. var RTE_TOGGLE_LINK = ' . RTE_TOGGLE_LINK . ';
  329. var RTE_POPUP = ' . RTE_POPUP . ';
  330. var oFCKeditor = new FCKeditor( "wpTextbox1" );
  331. // Set config
  332. oFCKeditor.BasePath = wgScriptPath + "/" + wgFCKEditorDir;
  333. oFCKeditor.Config["CustomConfigurationsPath"] = wgScriptPath + "/" + wgFCKEditorExtDir + "/fckeditor_config.js";';
  334. // Load fckeditor-rtl.css for right-to-left languages, but only fckeditor.css for other languages
  335. if( $wgContLang->isRTL() ) {
  336. $script .= 'oFCKeditor.Config["EditorAreaCSS"] = wgScriptPath + "/" + wgFCKEditorExtDir + "/css/fckeditor.css," + wgScriptPath + "/" + wgFCKEditorExtDir + "/css/fckeditor-rtl.css";';
  337. } else {
  338. $script .= 'oFCKeditor.Config["EditorAreaCSS"] = wgScriptPath + "/" + wgFCKEditorExtDir + "/css/fckeditor.css";';
  339. }
  340. $script .= '
  341. oFCKeditor.ToolbarSet = wgFCKEditorToolbarSet;
  342. oFCKeditor.ready = true;
  343. oFCKeditor.Config["showreferences"] = ' . ( ( $showRef ) ? 'true' : 'false' ) . ';
  344. oFCKeditor.Config["showsource"] = ' . ( ( $showSource ) ? 'true' : 'false' ) . ';
  345. ';
  346. $script .= '</script>';
  347. $newWinMsg = Xml::escapeJsString( wfMsgHtml( 'rich_editor_new_window' ) );
  348. $script .= <<<HEREDOC
  349. <script type="text/javascript">
  350. //IE hack to call func from popup
  351. function FCK_sajax(func_name, args, target) {
  352. sajax_request_type = 'POST';
  353. sajax_do_call(func_name, args, function (x) {
  354. // I know this is function, not object
  355. target(x);
  356. }
  357. );
  358. }
  359. function onLoadFCKeditor(){
  360. if( !( showFCKEditor & RTE_VISIBLE ) )
  361. showFCKEditor += RTE_VISIBLE;
  362. firstLoad = false;
  363. realTextarea = document.getElementById( 'wpTextbox1' );
  364. if ( realTextarea ){
  365. var height = wgFCKEditorHeight;
  366. realTextarea.style.display = 'none';
  367. if ( height == 0 ){
  368. // Get the window (inner) size.
  369. var height = window.innerHeight || ( document.documentElement && document.documentElement.clientHeight ) || 550;
  370. // Reduce the height to the offset of the toolbar.
  371. var offset = document.getElementById( 'wikiPreview' ) || document.getElementById( 'toolbar' );
  372. while ( offset ){
  373. height -= offset.offsetTop;
  374. offset = offset.offsetParent;
  375. }
  376. // Add a small space to be left in the bottom.
  377. height -= 20;
  378. }
  379. // Enforce a minimum height.
  380. height = ( !height || height < 300 ) ? 300 : height;
  381. // Create the editor instance and replace the textarea.
  382. oFCKeditor.Height = height;
  383. oFCKeditor.ReplaceTextarea();
  384. // Hide the default toolbar.
  385. document.getElementById( 'toolbar' ).style.display = 'none';
  386. // do things with CharInsert for example
  387. var edittools_markup = document.getElementById( 'editpage-specialchars' );
  388. if( edittools_markup ) {
  389. edittools_markup.style.display = 'none';
  390. }
  391. FCKeditorInsertTags = function( tagOpen, tagClose, sampleText, oDoc ){
  392. var txtarea;
  393. if ( !( typeof(oDoc.FCK) == "undefined" ) && !( typeof(oDoc.FCK.EditingArea) == "undefined" ) ){
  394. txtarea = oDoc.FCK.EditingArea.Textarea;
  395. } else if( oDoc.editform ){
  396. // if we have FCK enabled, behave differently...
  397. if ( showFCKEditor & RTE_VISIBLE ){
  398. SRCiframe = oDoc.getElementById( 'wpTextbox1___Frame' );
  399. if ( SRCiframe ){
  400. if( window.frames[SRCiframe] )
  401. SRCdoc = window.frames[SRCiframe].oDoc;
  402. else
  403. SRCdoc = SRCiframe.contentDocument;
  404. var SRCarea = SRCdoc.getElementById( 'xEditingArea' ).firstChild;
  405. if( SRCarea )
  406. txtarea = SRCarea;
  407. else
  408. return false;
  409. } else {
  410. return false;
  411. }
  412. } else {
  413. txtarea = oDoc.editform.wpTextbox1;
  414. }
  415. } else {
  416. // some alternate form? take the first one we can find
  417. var areas = oDoc.getElementsByTagName( 'textarea' );
  418. txtarea = areas[0];
  419. }
  420. var selText, isSample = false;
  421. if ( oDoc.selection && oDoc.selection.createRange ){ // IE/Opera
  422. // save window scroll position
  423. if ( oDoc.documentElement && oDoc.documentElement.scrollTop )
  424. var winScroll = oDoc.documentElement.scrollTop;
  425. else if ( oDoc.body )
  426. var winScroll = oDoc.body.scrollTop;
  427. // get current selection
  428. txtarea.focus();
  429. var range = oDoc.selection.createRange();
  430. selText = range.text;
  431. // insert tags
  432. checkSelected();
  433. range.text = tagOpen + selText + tagClose;
  434. // mark sample text as selected
  435. if ( isSample && range.moveStart ){
  436. if( window.opera )
  437. tagClose = tagClose.replace(/\\n/g,''); // check it out one more time
  438. range.moveStart( 'character', - tagClose.length - selText.length );
  439. range.moveEnd( 'character', - tagClose.length );
  440. }
  441. range.select();
  442. // restore window scroll position
  443. if ( oDoc.documentElement && oDoc.documentElement.scrollTop )
  444. oDoc.documentElement.scrollTop = winScroll;
  445. else if ( oDoc.body )
  446. oDoc.body.scrollTop = winScroll;
  447. } else if ( txtarea.selectionStart || txtarea.selectionStart == '0' ){ // Mozilla
  448. // save textarea scroll position
  449. var textScroll = txtarea.scrollTop;
  450. // get current selection
  451. txtarea.focus();
  452. var startPos = txtarea.selectionStart;
  453. var endPos = txtarea.selectionEnd;
  454. selText = txtarea.value.substring( startPos, endPos );
  455. // insert tags
  456. if( !selText ){
  457. selText = sampleText;
  458. isSample = true;
  459. } else if( selText.charAt(selText.length - 1) == ' ' ){ //exclude ending space char
  460. selText = selText.substring(0, selText.length - 1);
  461. tagClose += ' ';
  462. }
  463. txtarea.value = txtarea.value.substring(0, startPos) + tagOpen + selText + tagClose +
  464. txtarea.value.substring(endPos, txtarea.value.length);
  465. // set new selection
  466. if( isSample ){
  467. txtarea.selectionStart = startPos + tagOpen.length;
  468. txtarea.selectionEnd = startPos + tagOpen.length + selText.length;
  469. } else {
  470. txtarea.selectionStart = startPos + tagOpen.length + selText.length + tagClose.length;
  471. txtarea.selectionEnd = txtarea.selectionStart;
  472. }
  473. // restore textarea scroll position
  474. txtarea.scrollTop = textScroll;
  475. }
  476. }
  477. }
  478. }
  479. function checkSelected(){
  480. if( !selText ) {
  481. selText = sampleText;
  482. isSample = true;
  483. } else if( selText.charAt(selText.length - 1) == ' ' ) { //exclude ending space char
  484. selText = selText.substring(0, selText.length - 1);
  485. tagClose += ' '
  486. }
  487. }
  488. function initEditor(){
  489. var toolbar = document.getElementById( 'toolbar' );
  490. // show popup or toogle link
  491. if( showFCKEditor & ( RTE_POPUP|RTE_TOGGLE_LINK ) ){
  492. // add new toolbar before wiki toolbar
  493. var fckTools = document.createElement( 'div' );
  494. fckTools.setAttribute('id', 'fckTools');
  495. toolbar.parentNode.insertBefore( fckTools, toolbar );
  496. var SRCtextarea = document.getElementById( 'wpTextbox1' );
  497. if( showFCKEditor & RTE_VISIBLE ) SRCtextarea.style.display = 'none';
  498. }
  499. if( showFCKEditor & RTE_TOGGLE_LINK ){
  500. fckTools.innerHTML='[<a class="fckToogle" id="toggle_wpTextbox1" href="javascript:void(0)" onclick="ToggleFCKEditor(\'toggle\',\'wpTextbox1\')">'+ editorLink +'</a>] ';
  501. }
  502. if( showFCKEditor & RTE_POPUP ){
  503. var style = (showFCKEditor & RTE_VISIBLE) ? 'style="display:none"' : "";
  504. fckTools.innerHTML+='<span ' + style + ' id="popup_wpTextbox1">[<a class="fckPopup" href="javascript:void(0)" onclick="ToggleFCKEditor(\'popup\',\'wpTextbox1\')">{$newWinMsg}</a>]</span>';
  505. }
  506. if( showFCKEditor & RTE_VISIBLE ){
  507. if ( toolbar ){ // insert wiki buttons
  508. // Remove the mwSetupToolbar onload hook to avoid a JavaScript error with FF.
  509. if ( window.removeEventListener )
  510. window.removeEventListener( 'load', mwSetupToolbar, false );
  511. else if ( window.detachEvent )
  512. window.detachEvent( 'onload', mwSetupToolbar );
  513. mwSetupToolbar = function(){ return false ; };
  514. for( var i = 0; i < mwEditButtons.length; i++ ) {
  515. mwInsertEditButton(toolbar, mwEditButtons[i]);
  516. }
  517. for( var i = 0; i < mwCustomEditButtons.length; i++ ) {
  518. mwInsertEditButton(toolbar, mwCustomEditButtons[i]);
  519. }
  520. }
  521. onLoadFCKeditor();
  522. }
  523. return true;
  524. }
  525. addOnloadHook( initEditor );
  526. HEREDOC;
  527. if( $this->showFCKEditor & ( RTE_TOGGLE_LINK | RTE_POPUP ) ){
  528. // add toggle link and handler
  529. $script .= <<<HEREDOC
  530. function ToggleFCKEditor( mode, objId ){
  531. var SRCtextarea = document.getElementById( objId );
  532. if( mode == 'popup' ){
  533. if ( ( showFCKEditor & RTE_VISIBLE ) && ( FCKeditorAPI ) ) { // if FCKeditor is up-to-date
  534. var oEditorIns = FCKeditorAPI.GetInstance( objId );
  535. var text = oEditorIns.GetData( oEditorIns.Config.FormatSource );
  536. SRCtextarea.value = text; // copy text to textarea
  537. }
  538. FCKeditor_OpenPopup('oFCKeditor', objId);
  539. return true;
  540. }
  541. var oToggleLink = document.getElementById( 'toggle_' + objId );
  542. var oPopupLink = document.getElementById( 'popup_' + objId );
  543. if ( firstLoad ){
  544. // firstLoad = true => FCKeditor start invisible
  545. if( oToggleLink ) oToggleLink.innerHTML = 'Loading...';
  546. sajax_request_type = 'POST';
  547. oFCKeditor.ready = false;
  548. sajax_do_call('wfSajaxWikiToHTML', [SRCtextarea.value], function( result ){
  549. if ( firstLoad ){ //still
  550. SRCtextarea.value = result.responseText; // insert parsed text
  551. onLoadFCKeditor();
  552. if( oToggleLink ) oToggleLink.innerHTML = editorMsgOff;
  553. oFCKeditor.ready = true;
  554. }
  555. });
  556. return true;
  557. }
  558. if( !oFCKeditor.ready ) return false; // sajax_do_call in action
  559. if( !FCKeditorAPI ) return false; // not loaded yet
  560. var oEditorIns = FCKeditorAPI.GetInstance( objId );
  561. var oEditorIframe = document.getElementById( objId + '___Frame' );
  562. var FCKtoolbar = document.getElementById( 'toolbar' );
  563. var bIsWysiwyg = ( oEditorIns.EditMode == FCK_EDITMODE_WYSIWYG );
  564. //FCKeditor visible -> hidden
  565. if ( showFCKEditor & RTE_VISIBLE ){
  566. var text = oEditorIns.GetData( oEditorIns.Config.FormatSource );
  567. SRCtextarea.value = text;
  568. if ( bIsWysiwyg ) oEditorIns.SwitchEditMode(); // switch to plain
  569. var text = oEditorIns.GetData( oEditorIns.Config.FormatSource );
  570. // copy from FCKeditor to textarea
  571. SRCtextarea.value = text;
  572. if( saveSetting ){
  573. sajax_request_type = 'GET';
  574. sajax_do_call( 'wfSajaxToggleFCKeditor', ['hide'], function(){} ); //remember closing in session
  575. }
  576. if( oToggleLink ) oToggleLink.innerHTML = editorMsgOn;
  577. if( oPopupLink ) oPopupLink.style.display = '';
  578. showFCKEditor -= RTE_VISIBLE;
  579. oEditorIframe.style.display = 'none';
  580. FCKtoolbar.style.display = '';
  581. SRCtextarea.style.display = '';
  582. } else {
  583. // FCKeditor hidden -> visible
  584. if ( bIsWysiwyg ) oEditorIns.SwitchEditMode(); // switch to plain
  585. SRCtextarea.style.display = 'none';
  586. // copy from textarea to FCKeditor
  587. oEditorIns.EditingArea.Textarea.value = SRCtextarea.value;
  588. FCKtoolbar.style.display = 'none';
  589. oEditorIframe.style.display = '';
  590. if ( !bIsWysiwyg ) oEditorIns.SwitchEditMode(); // switch to WYSIWYG
  591. showFCKEditor += RTE_VISIBLE; // showFCKEditor+=RTE_VISIBLE
  592. if( oToggleLink ) oToggleLink.innerHTML = editorMsgOff;
  593. if( oPopupLink ) oPopupLink.style.display = 'none';
  594. }
  595. return true;
  596. }
  597. HEREDOC;
  598. }
  599. if( $this->showFCKEditor & RTE_POPUP ){
  600. $script .= <<<HEREDOC
  601. function FCKeditor_OpenPopup(jsID, textareaID){
  602. popupUrl = wgFCKEditorExtDir + '/FCKeditor.popup.html';
  603. popupUrl = popupUrl + '?var='+ jsID + '&el=' + textareaID;
  604. window.open(popupUrl, null, 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=1,dependent=yes');
  605. return 0;
  606. }
  607. HEREDOC;
  608. }
  609. $script .= '</script>';
  610. $wgOut->addScript( $script );
  611. return true;
  612. }
  613. }