Added feature #10182: htmlArea RTE: Add support for editing lang attribute
authorStanislas Rolland <typo3@sjbr.ca>
Mon, 26 Jan 2009 13:59:29 +0000 (13:59 +0000)
committerStanislas Rolland <typo3@sjbr.ca>
Mon, 26 Jan 2009 13:59:29 +0000 (13:59 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@4860 709f56b5-9817-0410-a4d7-c38de5d9e867

28 files changed:
ChangeLog
typo3/sysext/rtehtmlarea/ChangeLog
typo3/sysext/rtehtmlarea/class.tx_rtehtmlarea_base.php
typo3/sysext/rtehtmlarea/doc/manual.sxw
typo3/sysext/rtehtmlarea/ext_tables.sql
typo3/sysext/rtehtmlarea/extensions/Acronym/class.tx_rtehtmlarea_acronym.php
typo3/sysext/rtehtmlarea/extensions/Language/class.tx_rtehtmlarea_language.php
typo3/sysext/rtehtmlarea/extensions/Language/locallang.xml [new file with mode: 0644]
typo3/sysext/rtehtmlarea/extensions/Language/skin/htmlarea.css
typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js
typo3/sysext/rtehtmlarea/htmlarea/locallang_dialogs.xml
typo3/sysext/rtehtmlarea/htmlarea/plugins/Acronym/acronym.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/Language/language.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/Language/locallang.xml
typo3/sysext/rtehtmlarea/htmlarea/plugins/TableOperations/table-operations.js
typo3/sysext/rtehtmlarea/htmlarea/skins/default/htmlarea-edited-content.css
typo3/sysext/rtehtmlarea/htmlarea/skins/default/htmlarea.css
typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/language-marker.gif [new file with mode: 0644]
typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/show-language-marks.gif [new file with mode: 0644]
typo3/sysext/rtehtmlarea/locallang_db.xml
typo3/sysext/rtehtmlarea/mod2/class.tx_rtehtmlarea_acronym_mod.php
typo3/sysext/rtehtmlarea/mod2/locallang.xml
typo3/sysext/rtehtmlarea/mod4/class.tx_rtehtmlarea_select_image.php
typo3/sysext/rtehtmlarea/tca.php
typo3/sysext/t3skin/rtehtmlarea/htmlarea-edited-content.css
typo3/sysext/t3skin/rtehtmlarea/htmlarea.css
typo3/sysext/t3skin/rtehtmlarea/images/language-marker.gif [new file with mode: 0644]
typo3/sysext/t3skin/rtehtmlarea/images/show-language-marks.gif [new file with mode: 0644]

index 4644499..8ac28a6 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2009-01-26  Stanislas Rolland  <typo3@sjbr.ca>
+
+       * Added feature #10182: htmlArea RTE: Add support for editing lang attribute
+
 2009-01-24  Ingmar Schlecht  <ingmar@typo3.org>
 
        * Fixed bug #10205: DB session record is only created when user is authenticated (thanks also to Michael Stucki)
index 52e1e04..7ffa467 100644 (file)
@@ -1,3 +1,7 @@
+2009-01-26  Stanislas Rolland  <typo3@sjbr.ca>
+
+       * Added feature #10182: htmlArea RTE: Add support for editing lang attribute
+
 2009-01-21  Stanislas Rolland  <typo3@sjbr.ca>
 
        * Follow-up to #10195: htmlArea RTE: Update RTE about info
index ec83df3..a84d1bf 100644 (file)
@@ -567,7 +567,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                        bar, formattext, bold,  strong, italic, emphasis, big, small, insertedtext, deletedtext, citation, code, definition, keyboard, monospaced, quotation, sample, variable, bidioverride, strikethrough, subscript, superscript, underline, span,
                        bar, fontstyle, space, fontsize, bar, formatblock, insertparagraphbefore, insertparagraphafter, blockquote,
                        bar, left, center, right, justifyfull,
-                       bar, orderedlist, unorderedlist, definitionlist, definitionitem, outdent, indent,  bar, lefttoright, righttoleft,
+                       bar, orderedlist, unorderedlist, definitionlist, definitionitem, outdent, indent,  bar, lefttoright, righttoleft, language, showlanguagemarks,
                        bar, textcolor, bgcolor, textindicator,
                        bar, emoticon, insertcharacter, line, link, unlink, image, table,' . (($this->thisConfig['hideTableOperationsInToolbar'] && is_array($this->thisConfig['buttons.']) && is_array($this->thisConfig['buttons.']['toggleborders.']) && $this->thisConfig['buttons.']['toggleborders.']['keepInToolbar']) ? ' toggleborders,': '') . ' user, acronym, bar, findreplace, spellcheck,
                        bar, chMode, inserttag, removeformat, bar, copy, cut, paste, bar, undo, redo, bar, showhelp, about, linebreak,
@@ -579,7 +579,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                if($this->client['BROWSER'] == 'gecko' && $this->client['VERSION'] == '1.3')  {
                        $this->defaultToolbarOrder = $this->TCEform->docLarge ? 'bar, blockstylelabel, blockstyle, space, textstylelabel, textstyle, linebreak,
                                bar, fontstyle, space, fontsize, space, formatblock, insertparagraphbefore, insertparagraphafter, blockquote, bar, bold, italic, underline, strikethrough,
-                               subscript, superscript, lefttoright, righttoleft, bar, left, center, right, justifyfull, linebreak,
+                               subscript, superscript, lefttoright, righttoleft, language, showlanguagemarks, bar, left, center, right, justifyfull, linebreak,
                                bar, orderedlist, unorderedlist, definitionlist, definitionitem, outdent, indent, bar, textcolor, bgcolor, textindicator, bar, emoticon,
                                insertcharacter, line, link, unlink, image, table, user, acronym, bar, findreplace, spellcheck, bar, chMode, inserttag,
                                removeformat, bar, copy, cut, paste, bar, undo, redo, bar, showhelp, about, linebreak,
@@ -588,7 +588,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                                cellproperties, cellinsertbefore, cellinsertafter, celldelete, cellsplit, cellmerge'
                                : 'bar, blockstylelabel, blockstyle, space, textstylelabel, textstyle, linebreak,
                                bar, fontstyle, space, fontsize, space, formatblock, insertparagraphbefore, insertparagraphafter, blockquote, bar, bold, italic, underline, strikethrough,
-                               subscript, superscript, linebreak, bar, lefttoright, righttoleft, bar, left, center, right, justifyfull,
+                               subscript, superscript, linebreak, bar, lefttoright, righttoleft, language, showlanguagemarks, bar, left, center, right, justifyfull,
                                orderedlist, unorderedlist, definitionlist, definitionitem, outdent, indent, bar, textcolor, bgcolor, textindicator, bar, emoticon,
                                insertcharacter, line, link, unlink, image, table, user, acronym, linebreak, bar, findreplace, spellcheck, bar, chMode, inserttag,
                                removeformat, bar, copy, cut, paste, bar, undo, redo, bar, showhelp, about, linebreak,
index 09a67ab..79958c4 100644 (file)
Binary files a/typo3/sysext/rtehtmlarea/doc/manual.sxw and b/typo3/sysext/rtehtmlarea/doc/manual.sxw differ
index 3069b0f..a416d8d 100644 (file)
@@ -14,6 +14,7 @@ CREATE TABLE tx_rtehtmlarea_acronym (
   type tinyint(3) unsigned DEFAULT '1' NOT NULL,
   term varchar(255) DEFAULT '' NOT NULL,
   acronym varchar(255) DEFAULT '' NOT NULL,
+  static_lang_isocode int(11) unsigned DEFAULT '0' NOT NULL,
 
   PRIMARY KEY (uid),
   KEY parent (pid)
index 1721772..f756bb0 100644 (file)
@@ -48,7 +48,12 @@ class tx_rtehtmlarea_acronym extends tx_rtehtmlareaapi {
                'acronym'       => 'Acronym',
                );
        protected $acronymIndex = 0;
-       protected $abbraviationIndex = 0;
+       protected $abbreviationIndex = 0;
+
+       public function main($parentObject) {
+
+               return parent::main($parentObject) && t3lib_extMgm::isLoaded('static_info_tables');
+       }
 
        /**
         * Return tranformed content
@@ -94,11 +99,11 @@ class tx_rtehtmlarea_acronym extends tx_rtehtmlareaapi {
 
                                // <abbr> was not supported by IE before version 7
                        if ($this->htmlAreaRTE->client['BROWSER'] == 'msie' && $this->htmlAreaRTE->client['VERSION'] < 7) {
-                               $this->AbbreviationIndex = 0;
+                               $this->abbreviationIndex = 0;
                        }
                        $registerRTEinJavascriptString .= '
                        RTEarea['.$RTEcounter.'].buttons.'. $button .'.noAcronym = ' . ($this->acronymIndex ? 'false' : 'true') . ';
-                       RTEarea['.$RTEcounter.'].buttons.'. $button .'.noAbbr =  ' . ($this->AbbreviationIndex ? 'false' : 'true') . ';';
+                       RTEarea['.$RTEcounter.'].buttons.'. $button .'.noAbbr =  ' . ($this->abbreviationIndex ? 'false' : 'true') . ';';
                }
 
                return $registerRTEinJavascriptString;
@@ -110,42 +115,57 @@ class tx_rtehtmlarea_acronym extends tx_rtehtmlareaapi {
         * @return      string          acronym Javascript array
         */
        function buildJSAcronymArray($languageUid) {
-               global $TYPO3_DB;
 
                $charset = $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] ? $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] : 'iso-8859-1';
-
                $button = 'acronym';
                $PIDList = 0;
-               if (is_array($this->thisConfig['buttons.']) && is_array($this->thisConfig['buttons.'][$button.'.']) && trim($this->thisConfig['buttons.'][$button.'.']['PIDList'])) {
+               if (is_array($this->thisConfig['buttons.']) && is_array($this->thisConfig['buttons.'][$button.'.']) && isset($this->thisConfig['buttons.'][$button.'.']['PIDList'])) {
                        $PIDList = implode(',', t3lib_div::trimExplode(',', $this->thisConfig['buttons.'][$button.'.']['PIDList']));
                }
                $linebreak = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->htmlAreaRTE->ID]['enableCompressedScripts'] ? '' : chr(10);
                $JSAcronymArray .= 'acronyms = { ' . $linebreak;
+               $JSAcronymLanguageArray .= 'acronymLanguage = { ' . $linebreak;
                $JSAbbreviationArray .= 'abbreviations = { ' . $linebreak;
-               $table = 'tx_rtehtmlarea_acronym';
+               $JSAbbreviationLanguageArray .= 'abbreviationLanguage = { ' . $linebreak;
+               $tableA = 'tx_rtehtmlarea_acronym';
+               $tableB = 'static_languages';
+               $fields = $tableA.'.type,' . $tableA . '.term,' . $tableA . '.acronym,' . $tableB . '.lg_iso_2';
+               $tableAB = $tableA . ' LEFT JOIN ' . $tableB . ' ON ' . $tableA . '.static_lang_isocode=' . $tableB . '.uid';
                if ($languageUid > -1) {
-                       $whereClause = '(sys_language_uid=' . $languageUid . ' OR sys_language_uid=-1) ';
+                       $whereClause = '(' . $tableA . '.sys_language_uid=' . $languageUid . ' OR ' . $tableA . '.sys_language_uid=-1) ';
                } else {
                        $whereClause = '1 = 1 ';
                }
-               $whereClause .= ($PIDList ? ' AND '. $table . '.pid IN (' . $TYPO3_DB->fullQuoteStr($PIDList, $table) . ') ' : '');
-               $whereClause .= t3lib_BEfunc::BEenableFields($table);
-               $whereClause .= t3lib_BEfunc::deleteClause($table);
-               $res = $TYPO3_DB->exec_SELECTquery('type,term,acronym', $table, $whereClause);
-               while($acronymRow = $TYPO3_DB->sql_fetch_assoc($res))    {
-                       if( $acronymRow['type'] == 1) $JSAcronymArray .= (($this->acronymIndex++)?',':'') . '"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['term'], $charset) . '":"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['acronym'], $charset) . '"' . $linebreak;
-                       if ($acronymRow['type'] == 2) $JSAbbreviationArray .= (($this->AbbreviationIndex++)?',':'') . '"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['term'], $charset) . '":"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['acronym'], $charset) . '"' . $linebreak;
+               $whereClause .= ' AND '. $tableA . '.pid IN (' . $GLOBALS['TYPO3_DB']->fullQuoteStr($PIDList, $tableA) . ') ';
+               if (is_array($this->thisConfig['buttons.']) && is_array($this->thisConfig['buttons.']['language.']) && isset($this->thisConfig['buttons.']['language.']['items'])) {
+                       $languageList = implode("','", t3lib_div::trimExplode(',', $GLOBALS['TYPO3_DB']->fullQuoteStr(strtoupper($this->thisConfig['buttons.']['language.']['items']), $tableB)));
+                       $whereClause .= ' AND '. $tableB . '.lg_iso_2 IN (' . $languageList . ') ';
+               }
+               $whereClause .= t3lib_BEfunc::BEenableFields($tableA);
+               $whereClause .= t3lib_BEfunc::deleteClause($tableA);
+               $whereClause .= t3lib_BEfunc::BEenableFields($tableB);
+               $whereClause .= t3lib_BEfunc::deleteClause($tableB);
+               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($fields, $tableAB, $whereClause);
+               while ($acronymRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+                       if( $acronymRow['type'] == 1) {
+                               $JSAcronymArray .= (($this->acronymIndex++)?',':'') . '"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['term'], $charset) . '":"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['acronym'], $charset) . '"' . $linebreak;
+                               $JSAcronymLanguageArray .= (($this->acronymIndex-1)?',':'') . '"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['term'], $charset) . '":"' . $GLOBALS['LANG']->csConvObj->utf8_encode(strtolower($acronymRow['lg_iso_2']), $charset) . '"' . $linebreak;
+                       }
+                       if ($acronymRow['type'] == 2) {
+                               $JSAbbreviationArray .= (($this->abbreviationIndex++)?',':'') . '"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['term'], $charset) . '":"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['acronym'], $charset) . '"' . $linebreak;
+                               $JSAbbreviationLanguageArray .= (($this->abbreviationIndex-1)?',':'') . '"' . $GLOBALS['LANG']->csConvObj->utf8_encode($acronymRow['term'], $charset) . '":"' . $GLOBALS['LANG']->csConvObj->utf8_encode(strtolower($acronymRow['lg_iso_2']), $charset) . '"' . $linebreak;
+                       }
                }
                $JSAcronymArray .= '};' . $linebreak;
+               $JSAcronymLanguageArray .= '};' . $linebreak;
                $JSAbbreviationArray .= '};' . $linebreak;
+               $JSAbbreviationLanguageArray .= '};' . $linebreak;
 
-               return $JSAcronymArray . $JSAbbreviationArray;
+               return $JSAcronymArray . $JSAcronymLanguageArray . $JSAbbreviationArray . $JSAbbreviationLanguageArray;
        }
-
-} // end of class
+}
 
 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/extensions/Acronym/class.tx_rtehtmlarea_acronym.php']) {
        include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/extensions/Acronym/class.tx_rtehtmlarea_acronym.php']);
 }
-
 ?>
\ No newline at end of file
index 6c4df20..2bdf9ab 100644 (file)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2008 Stanislas Rolland <stanislas.rolland(arobas)fructifor.ca>
+*  (c) 2008-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the Typo3 project. The Typo3 project is
@@ -24,7 +24,7 @@
 /**
  * Language plugin for htmlArea RTE
  *
- * @author Stanislas Rolland <stanislas.rolland(arobas)fructifor.ca>
+ * @author Stanislas Rolland <typo3(arobas)sjbr.ca>
  *
  * TYPO3 SVN ID: $Id$
  *
@@ -36,19 +36,30 @@ class tx_rtehtmlarea_language extends tx_rtehtmlareaapi {
 
        protected $extensionKey = 'rtehtmlarea';        // The key of the extension that is extending htmlArea RTE
        protected $pluginName = 'Language';             // The name of the plugin registered by the extension
-       protected $relativePathToLocallangFile = '';    // Path to this main locallang file of the extension relative to the extension dir.
+       protected $relativePathToLocallangFile = 'extensions/Language/locallang.xml';   // Path to this main locallang file of the extension relative to the extension dir.
        protected $relativePathToSkin = 'extensions/Language/skin/htmlarea.css';                // Path to the skin (css) file relative to the extension dir.
        protected $htmlAreaRTE;                         // Reference to the invoking object
        protected $thisConfig;                          // Reference to RTE PageTSConfig
        protected $toolbar;                             // Reference to RTE toolbar array
        protected $LOCAL_LANG;                          // Frontend language array
-       
-       protected $pluginButtons = 'lefttoright,righttoleft';
+
+       protected $pluginButtons = 'lefttoright,righttoleft,language,showlanguagemarks';
        protected $convertToolbarForHtmlAreaArray = array (
-               'lefttoright'           => 'LeftToRight',
-               'righttoleft'           => 'RightToLeft',
+               'lefttoright'                   => 'LeftToRight',
+               'righttoleft'                   => 'RightToLeft',
+               'language'                      => 'Language',
+               'showlanguagemarks'             => 'ShowLanguageMarks',
                );
-       
+
+       public function main($parentObject) {
+               if (!t3lib_extMgm::isLoaded('static_info_tables')) {
+                       $this->pluginButtons = t3lib_div::rmFromList('language', $this->pluginButtons);
+               } else {
+                       require_once(t3lib_extMgm::extPath('static_info_tables').'class.tx_staticinfotables_div.php');
+               }
+               return parent::main($parentObject);
+       }
+
        /**
         * Return JS configuration of the htmlArea plugins registered by the extension
         *
@@ -64,8 +75,68 @@ class tx_rtehtmlarea_language extends tx_rtehtmlareaapi {
                global $TSFE, $LANG;
                
                $registerRTEinJavascriptString = '';
+               if (in_array('language', $this->toolbar)) {
+                       if (!is_array( $this->thisConfig['buttons.']) || !is_array($this->thisConfig['buttons.']['language.'])) {
+                               $registerRTEinJavascriptString .= '
+                       RTEarea['.$RTEcounter.'].buttons.language = new Object();';
+                       }
+                       $prefixLabelWithCode = !$this->thisConfig['buttons.']['language.']['prefixLabelWithCode'] ? false : true;
+                       $postfixLabelWithCode = !$this->thisConfig['buttons.']['language.']['postfixLabelWithCode'] ? false : true;
+                       $languageCodes = t3lib_div::trimExplode(',', $this->thisConfig['buttons.']['language.']['items'] ? $this->thisConfig['buttons.']['language.']['items'] : 'en', 1);
+                       $labelsArray = $this->getStaticInfoName(implode(',', $languageCodes));
+                       if ($this->htmlAreaRTE->is_FE()) {
+                               $first = $GLOBALS['TSFE']->getLLL('No language mark',$this->LOCAL_LANG);
+                       } else {
+                               $first = $GLOBALS['LANG']->getLL('No language mark');
+                       }
+                               // Generating the JavaScript options
+                       $languageOptions = '{
+                       "'. $first.'" : "none"';
+                       foreach ($languageCodes as $index => $code) {
+                               $label = ($prefixLabelWithCode ? ($code . ' - ') : '') . $labelsArray[$index] . ($postfixLabelWithCode ? (' - ' . $code) : '');
+                               $label = (!$this->htmlAreaRTE->is_FE() && $this->htmlAreaRTE->TCEform->inline->isAjaxCall) ? $GLOBALS['LANG']->csConvObj->utf8_encode($label, $GLOBALS['LANG']->charSet) : $label;
+                               $languageOptions .= ',
+                       "' . $label . '" : "' . $code . '"';
+                       }
+                       $languageOptions .= '};';
+
+                       $registerRTEinJavascriptString .= '
+                       RTEarea['.$RTEcounter.'].buttons.language.dropDownOptions = '. $languageOptions;
+               }
                return $registerRTEinJavascriptString;
        }
+       
+       /**
+        * Getting the name of a language
+        * We assume that the Static Info Tables are in 
+        *
+        * @param       string          $code: the ISO alpha-2 code of a language; or a comma-separated list of such
+        * @param       boolean         $local: local name only - if set local title is returned
+        * @return      array           names of the language(s) in the current language
+        */
+       function getStaticInfoName($code, $local=FALSE) {
+               $table = 'static_languages';
+               $lang = tx_staticinfotables_div::getCurrentLanguage();
+               if (!t3lib_extMgm::isLoaded('static_info_tables_'.strtolower($lang))) {
+                       $lang = '';
+               }
+               $codeArray = t3lib_div::trimExplode(',', $code);
+               $namesArray = array();
+               foreach ($codeArray as $isoCode){
+                       $isoCodeArray = t3lib_div::trimExplode( '_', $isoCode, 1);
+                       $name = tx_staticinfotables_div::getTitleFromIsoCode($table, $isoCodeArray, $lang, $local);
+                       if (!$name && $lang != 'EN') {
+                                       // use the default English name if there is not text in another language
+                               $name = tx_staticinfotables_div::getTitleFromIsoCode($table, $isoCodeArray, '', $local);
+                       }
+                       if ($this->htmlAreaRTE->is_FE()) {
+                               $namesArray[] = $GLOBALS['TSFE']->csConvObj->conv($name, 'utf-8', $this->htmlAreaRTE->OutputCharset);
+                       } else {
+                               $namesArray[] = $GLOBALS['LANG']->csConvObj->conv($name, 'utf-8', $this->htmlAreaRTE->OutputCharset);
+                       }
+               }
+               return $namesArray;
+       }
 
 } // end of class
 
diff --git a/typo3/sysext/rtehtmlarea/extensions/Language/locallang.xml b/typo3/sysext/rtehtmlarea/extensions/Language/locallang.xml
new file mode 100644 (file)
index 0000000..8934be8
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<!-- TYPO3 SVN ID: $Id: locallang.xml 3135 2008-02-08 16:08:16Z stan $ -->
+<T3locallang>
+       <meta type="array">
+               <description>Labels for LanguageMarks extension of htmlArea RTE</description>
+               <type>module</type>
+       </meta>
+       <data type="array">
+               <languageKey index="default" type="array">
+                       <label index="No language mark">No language mark</label>
+               </languageKey>
+       </data>
+       <orig_hash type="array">
+               <languageKey index="default" type="array">
+               </languageKey>
+       </orig_hash>
+       <orig_text type="array">
+               <languageKey index="default" type="array">
+               </languageKey>
+       </orig_text>
+</T3locallang>
\ No newline at end of file
index be72357..cb62431 100644 (file)
@@ -1,4 +1,12 @@
-/* Selectors for the Language plugin of htmlArea RTE */
+/* Selectors for the LanguageMarks plugin of htmlArea RTE */
 /* TYPO3 SVN ID: $Id: htmlarea.css 2862 2008-01-05 19:32:58Z stanrolland $ */
-.htmlarea .toolbar .LeftToRight {background-image:url("images/left_to_right.gif");}
-.htmlarea .toolbar .RightToLeft {background-image:url("images/right_to_left.gif");}
+
+.htmlarea .toolbar .LeftToRight {
+       background-image:url("images/left_to_right.gif");
+}
+.htmlarea .toolbar .RightToLeft {
+       background-image:url("images/right_to_left.gif");
+}
+.htmlarea .toolbar .ShowLanguageMarks {
+       background-image:url("images/show-language-marks.gif");
+}
index eab1b2e..67c8e64 100644 (file)
@@ -2785,6 +2785,16 @@ HTMLArea.Plugin = HTMLArea.Base.extend({
        },
 
        /**
+        * Returns a plugin object
+        *
+        * @param       string          pluinName: the name of some plugin
+        * @return      object          the plugin object or null
+        */
+       getPluginInstance : function(pluginName) {
+               return this.editor.getPluginInstance(pluginName);
+       },
+
+       /**
         * Returns true if the button is enabled in the toolbar configuration
         *
         * @param       string          buttonId: identification of the button
index 20a1868..725a9c3 100644 (file)
                        <label index="style">Paragraph:</label>
                        <label index="Block style label">Block style:</label>
                        <label index="text_style">Text style:</label>
+                       <label index="LeftToRight">Left to right1</label>
+                       <label index="RightToLeft">Right to left1</label>
+                       <label index="Language">Language</label>
+                       <label index="Text direction">Text direction</label>
+                       <label index="Language:">Language:</label>
+                       <label index="Text direction:">Text direction:</label>
+                       <label index="No language mark">No language</label>
+                       <label index="Remove language mark">Remove language</label>
                </languageKey>
        </data>
        <orig_hash type="array">
index 20b5278..50370cd 100644 (file)
@@ -48,12 +48,12 @@ Acronym = HTMLArea.Plugin.extend({
                 * Registering plugin "About" information
                 */
                var pluginInformation = {
-                       version         : "1.6",
+                       version         : "1.7",
                        developer       : "Stanislas Rolland",
-                       developerUrl    : "http://www.fructifor.ca/",
+                       developerUrl    : "http://www.sjbr.ca/",
                        copyrightOwner  : "Stanislas Rolland",
-                       sponsor         : "Fructifor Inc.",
-                       sponsorUrl      : "http://www.fructifor.ca/",
+                       sponsor         : "SJBR",
+                       sponsorUrl      : "http://www.sjbr.ca/",
                        license         : "GPL"
                };
                this.registerPluginInformation(pluginInformation);
index c603e82..b3ca7d0 100644 (file)
@@ -1,7 +1,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2008 Stanislas Rolland <stanislas.rolland(arobas)fructifor.ca>
+*  (c) 2008-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
  * TYPO3 SVN ID: $Id: language.js 2862 2008-01-05 19:32:58Z stanrolland $
  */
 Language = HTMLArea.Plugin.extend({
-               
+
        constructor : function(editor, pluginName) {
                this.base(editor, pluginName);
        },
-       
+
        /*
         * This function gets called by the class constructor
         */
        configurePlugin : function (editor) {
-               
+
+               /*
+                * Setting up some properties from PageTSConfig
+                */
+               this.buttonsConfiguration = this.editorConfiguration.buttons;
+               this.useAttribute = {};
+               this.useAttribute.lang = (this.buttonsConfiguration.language && this.buttonsConfiguration.language.useLangAttribute) ? this.buttonsConfiguration.language.useLangAttribute : true;
+               this.useAttribute.xmlLang = (this.buttonsConfiguration.language && this.buttonsConfiguration.language.useXmlLangAttribute) ? this.buttonsConfiguration.language.useXmlLangAttribute : false;
+               if (!this.useAttribute.lang && !this.useAttribute.xmlLang) {
+                       this.useAttribute.lang = true;
+               }
+
+                       // Importing list of allowed attributes
+               if (this.editor.getPluginInstance("TextStyle")) {
+                       this.allowedAttributes = this.editor.getPluginInstance("TextStyle").allowedAttributes;
+               }                       
+               if (!this.allowedAttributes && this.editor.getPluginInstance("InlineElements")) {
+                       this.allowedAttributes = this.editor.getPluginInstance("InlineElements").allowedAttributes;
+               }
+               if (!this.allowedAttributes && this.editor.getPluginInstance("BlockElements")) {
+                       this.allowedAttributes = this.editor.getPluginInstance("BlockElements").allowedAttributes;
+               }
+               if (!this.allowedAttributes) {
+                       this.allowedAttributes = new Array("id", "title", "lang", "xml:lang", "dir", (HTMLArea.is_gecko?"class":"className"));
+               }
+
                /*
                 * Registering plugin "About" information
                 */
                var pluginInformation = {
-                       version         : "1.0",
+                       version         : "0.1",
                        developer       : "Stanislas Rolland",
-                       developerUrl    : "http://www.fructifor.ca/",
+                       developerUrl    : "http://www.sjbr.ca/",
                        copyrightOwner  : "Stanislas Rolland",
-                       sponsor         : "Fructifor Inc.",
-                       sponsorUrl      : "http://www.fructifor.ca/",
+                       sponsor         : this.localize("Technische Universitat Ilmenau"),
+                       sponsorUrl      : "http://www.tu-ilmenau.de/",
                        license         : "GPL"
                };
                this.registerPluginInformation(pluginInformation);
-               
+
                /*
                 * Registering the buttons
                 */
@@ -69,16 +94,58 @@ Language = HTMLArea.Plugin.extend({
                        };
                        this.registerButton(buttonConfiguration);
                }
-               
+
+               /*
+                * Registering the dropdown list
+                */
+               var buttonId = "Language";
+               var dropDownConfiguration = {
+                       id              : buttonId,
+                       tooltip         : this.localize(buttonId + "-Tooltip"),
+                       options         : ((this.buttonsConfiguration.language && this.buttonsConfiguration.language.dropDownOptions) ? this.buttonsConfiguration.language.dropDownOptions : null),
+                       action          : "onChange",
+                       refresh         : null,
+                       context         : null
+               };
+               this.registerDropDown(dropDownConfiguration);
+
                return true;
         },
-        
+
        /* The list of buttons added by this plugin */
        buttonList : [
                ["LeftToRight", null],
-               ["RightToLeft", null]
+               ["RightToLeft", null],
+               ["ShowLanguageMarks", null]
        ],
-        
+
+       /*
+        * This function gets called when the editor is generated
+        */
+       onGenerate : function () {
+                       // Add rules to the stylesheet for language mark highlighting
+                       // Model: body.htmlarea-show-language-marks *[lang=en]:before { content: "en: "; }
+                       // Such rule is not supported by Internet Explorer
+               if (HTMLArea.is_gecko) {
+                       var obj = this.getDropDownConfiguration("Language");
+                       if ((typeof(obj) !== "undefined") && (typeof(this.editor._toolbarObjects[obj.id]) !== "undefined")) {
+                               var styleSheet = this.editor._doc.styleSheets[0];
+                               var select = document.getElementById(this.editor._toolbarObjects[obj.id].elementId);
+                               var options = select.options;
+                               var rule;
+                               for (var i = options.length; --i >= 0;) {
+                                       if (this.useAttribute.lang) {
+                                               rule = 'body.htmlarea-show-language-marks *[lang=' + options[i].value + ']:before { content: "' + options[i].value + ': "; }';
+                                               styleSheet.insertRule(rule, styleSheet.cssRules.length);
+                                       } else if (this.useAttribute.xmlLang) {
+                                               rule = 'body.htmlarea-show-language-marks *[xml:lang=' + options[i].value + ']:before { content: "' + options[i].value + ': "; }';
+                                               styleSheet.insertRule(rule, styleSheet.cssRules.length);
+                                       }
+                               }
+                       }
+               }
+       },
+
        /*
         * This function gets called when a button was pressed.
         *
@@ -92,37 +159,302 @@ Language = HTMLArea.Plugin.extend({
                var buttonId = this.translateHotKey(id);
                buttonId = buttonId ? buttonId : id;
                
+               switch (buttonId) {
+                       case "RightToLeft" :
+                       case "LeftToRight" :
+                               this.setDirAttribute(buttonId);
+                               break;
+                       case "ShowLanguageMarks":
+                               this.toggleLanguageMarks();
+                               break;
+                       default :
+                               break;
+               }
+               return false;
+       },
+       
+       /*
+        * Sets the dir attribute
+        *
+        * @param       string          buttonId: the button id
+        *
+        * @return      void
+        */
+       setDirAttribute : function (buttonId) {
                var direction = (buttonId == "RightToLeft") ? "rtl" : "ltr";
-               var el = this.editor.getParentElement();
-               if (el) {
-                       if (el.nodeName.toLowerCase() === "bdo") {
-                               el.dir = direction;
+               var element = this.editor.getParentElement();
+               if (element) {
+                       if (element.nodeName.toLowerCase() === "bdo") {
+                               element.dir = direction;
                        } else {
-                               el.dir = (el.dir == direction || el.style.direction == direction) ? "" : direction;
+                               element.dir = (element.dir == direction || element.style.direction == direction) ? "" : direction;
                        }
-                       el.style.direction = "";
+                       element.style.direction = "";
                }
-               
-               return false;
+        },
+       
+       /*
+        * Toggles the display of language marks
+        *
+        * @param       boolean         forceLanguageMarks: if set, language marks are displayed whatever the current state
+        *
+        * @return      void
+        */
+       toggleLanguageMarks : function (forceLanguageMarks) {
+               var body = this.editor._doc.body;
+               if (!HTMLArea._hasClass(body, 'htmlarea-show-language-marks')) {
+                       HTMLArea._addClass(body,'htmlarea-show-language-marks');
+               } else if (!forceLanguageMarks) {
+                       HTMLArea._removeClass(body,'htmlarea-show-language-marks');
+               }
+       },
+
+       /*
+        * This function gets called when some language was selected in the drop-down list
+        */
+       onChange : function (editor, buttonId) {
+               var tbobj = this.editor._toolbarObjects[buttonId];
+               var language = document.getElementById(tbobj.elementId).value;
+               this.applyLanguageMark(language);
+       },
+
+       /*
+        * This function applies the langauge mark to the selection
+        */
+       applyLanguageMark : function (language) {
+               var selection = this.editor._getSelection();
+               var statusBarSelection = this.editor.getPluginInstance("StatusBar") ? this.editor.getPluginInstance("StatusBar").getSelection() : null;
+               var range = this.editor._createRange(selection);
+               var parent = this.editor.getParentElement(selection, range);
+               var selectionEmpty = this.editor._selectionEmpty(selection);
+               var endPointsInSameBlock = this.editor.endPointsInSameBlock();
+               var fullNodeSelected = false;
+               if (!selectionEmpty) {
+                       if (endPointsInSameBlock) {
+                               var ancestors = this.editor.getAllAncestors();
+                               for (var i = 0; i < ancestors.length; ++i) {
+                                       fullNodeSelected = (statusBarSelection === ancestors[i])
+                                               && ((HTMLArea.is_gecko && ancestors[i].textContent === range.toString()) || (HTMLArea.is_ie && ((selection.type !== "Control" && ancestors[i].innerText === range.text) || (selection.type === "Control" && ancestors[i].innerText === range.item(0).text))));
+                                       if (fullNodeSelected) {
+                                               parent = ancestors[i];
+                                               break;
+                                       }
+                               }
+                                       // Working around bug in Safari selectNodeContents
+                               if (!fullNodeSelected && HTMLArea.is_safari && statusBarSelection && statusBarSelection.textContent === range.toString()) {
+                                       fullNodeSelected = true;
+                                       parent = statusBarSelection;
+                               }
+                       }
+               }
+               if (selectionEmpty || fullNodeSelected) {
+                               // Selection is empty or parent is selected in the status bar
+                       if (parent) {
+                                       // Set language attributes
+                               this.setLanguageAttributes(parent, language);
+                       }
+               } else if (endPointsInSameBlock) {
+                               // The selection is not empty, nor full element
+                       if (language != "none") {
+                                       // Add span element with lang attribute(s)
+                               var newElement = this.editor._doc.createElement("span");
+                               this.setLanguageAttributes(newElement, language);
+                               this.editor.wrapWithInlineElement(newElement, selection, range);
+                               if (HTMLArea.is_gecko) {
+                                       range.detach();
+                               }
+                       }
+               } else {
+                       this.setLanguageAttributeOnBlockElements(language);
+               }
+       },
+
+       /*
+        * This function gets the language attribute on the given element
+        *
+        * @param       object          element: the element from which to retrieve the attribute value
+        *
+        * @return      string          value of the lang attribute, or of the xml:lang attribute
+        */
+       getLanguageAttribute : function (element) {
+               return element.getAttribute("lang") ? element.getAttribute("lang") : (element.getAttribute("xml:lang") ? element.getAttribute("xml:lang") : "none");
        },
        
        /*
+        * This function sets the language attributes on the given element
+        *
+        * @param       object          element: the element on which to set the value of the lang and/or xml:lang attribute
+        * @param       string          language: value of the lang attributes, or "none", in which case, the attribute(s) is(are) removed
+        *
+        * @return      void
+        */
+       setLanguageAttributes : function (element, language) {
+               if (language == "none") {
+                               // Remove language mark, if any
+                       element.removeAttribute("lang");
+                       element.removeAttribute("xml:lang");
+                               // Remove the span tag if it has no more attribute
+                       if ((element.nodeName.toLowerCase() == "span") && !HTMLArea.hasAllowedAttributes(element, this.allowedAttributes)) {
+                               this.editor.removeMarkup(element);
+                       }
+               } else {
+                       if (this.useAttribute.lang) {
+                               element.setAttribute("lang", language);
+                       }
+                       if (this.useAttribute.xmlLang) {
+                               element.setAttribute("xml:lang", language);
+                       }
+               }
+       },
+
+       /*
+        * This function gets the language attributes from blocks sibling of the block containing the start container of the selection
+        *
+        * @return      string          value of the lang attribute, or of the xml:lang attribute, or "none", if all blocks sibling do not have the same attribute value as the block containing the start container
+        */
+       getLanguageAttributeFromBlockElements : function() {
+               var selection = this.editor._getSelection();
+               var endBlocks = this.editor.getEndBlocks(selection);
+               var startAncestors = this.editor.getBlockAncestors(endBlocks.start);
+               var endAncestors = this.editor.getBlockAncestors(endBlocks.end);
+               var index = 0;
+               while (index < startAncestors.length && index < endAncestors.length && startAncestors[index] === endAncestors[index]) {
+                       ++index;
+               }
+               if (endBlocks.start === endBlocks.end) {
+                       --index;
+               }
+               var language = this.getLanguageAttribute(startAncestors[index]);
+               for (var block = startAncestors[index]; block; block = block.nextSibling) {
+                       if (HTMLArea.isBlockElement(block)) {
+                               if (this.getLanguageAttribute(block) != language || this.getLanguageAttribute(block) == "none") {
+                                       language = "none";
+                                       break;
+                               }
+                       }
+                       if (block == endAncestors[index]) {
+                               break;
+                       }
+               }
+               return language;
+       },
+
+       /*
+        * This function sets the language attributes on blocks sibling of the block containing the start container of the selection
+        */
+       setLanguageAttributeOnBlockElements : function(language) {
+               var selection = this.editor._getSelection();
+               var endBlocks = this.editor.getEndBlocks(selection);
+               var startAncestors = this.editor.getBlockAncestors(endBlocks.start);
+               var endAncestors = this.editor.getBlockAncestors(endBlocks.end);
+               var index = 0;
+               while (index < startAncestors.length && index < endAncestors.length && startAncestors[index] === endAncestors[index]) {
+                       ++index;
+               }
+               if (endBlocks.start === endBlocks.end) {
+                       --index;
+               }
+               for (var block = startAncestors[index]; block; block = block.nextSibling) {
+                       if (HTMLArea.isBlockElement(block)) {
+                               this.setLanguageAttributes(block, language);
+                       }
+                       if (block == endAncestors[index]) {
+                               break;
+                       }
+               }
+       },
+
+       /*
         * This function gets called when the toolbar is updated
         */
        onUpdateToolbar : function () {
                if (this.editor.getMode() === "wysiwyg" && this.editor.isEditable()) {
+                       var selection = this.editor._getSelection();
+                       var statusBarSelection = this.editor.getPluginInstance("StatusBar") ? this.editor.getPluginInstance("StatusBar").getSelection() : null;
+                       var range = this.editor._createRange(selection);
+                       var parent = this.editor.getParentElement(selection);
+                               // Updating the direction buttons
                        var buttonList = this.buttonList, buttonId;
                        for (var i = 0, n = buttonList.length; i < n; ++i) {
                                buttonId = buttonList[i][0];
                                if (this.isButtonInToolbar(buttonId)) {
-                                       var el = this.editor.getParentElement();
-                                       if (el) {
-                                               var direction = (buttonId === "RightToLeft") ? "rtl" : "ltr";
-                                               this.editor._toolbarObjects[buttonId].state("active",(el.dir == direction || el.style.direction == direction));
+                                       switch (buttonId) {
+                                               case "RightToLeft" :
+                                               case "LeftToRight" :
+                                                       if (parent) {
+                                                               var direction = (buttonId === "RightToLeft") ? "rtl" : "ltr";
+                                                               this.editor._toolbarObjects[buttonId].state("active",(parent.dir == direction || parent.style.direction == direction));
+                                                       }
+                                                       break;
+                                               case "ShowLanguageMarks":
+                                                       this.editor._toolbarObjects[buttonId].state("active", HTMLArea._hasClass(this.editor._doc.body, 'htmlarea-show-language-marks'));
+                                                       break;
+                                               default :
+                                                       break;
                                        }
                                }
                        }
+                               // Updating the language drop-down
+                       var fullNodeSelected = false;
+                       var language = this.getLanguageAttribute(parent);
+                       var selectionEmpty = this.editor._selectionEmpty(selection);
+                       var endPointsInSameBlock = this.editor.endPointsInSameBlock();
+                       if (!selectionEmpty) {
+                               if (endPointsInSameBlock) {
+                                       var ancestors = this.editor.getAllAncestors();
+                                       for (var i = 0; i < ancestors.length; ++i) {
+                                               fullNodeSelected = (statusBarSelection === ancestors[i])
+                                                       && ((HTMLArea.is_gecko && ancestors[i].textContent === range.toString()) || (HTMLArea.is_ie && ((selection.type !== "Control" && ancestors[i].innerText === range.text) || (selection.type === "Control" && ancestors[i].innerText === range.item(0).text))));
+                                               if (fullNodeSelected) {
+                                                       parent = ancestors[i];
+                                                       break;
+                                               }
+                                       }
+                                               // Working around bug in Safari selectNodeContents
+                                       if (!fullNodeSelected && HTMLArea.is_safari && statusBarSelection && statusBarSelection.textContent === range.toString()) {
+                                               fullNodeSelected = true;
+                                               parent = statusBarSelection;
+                                       }
+                                       language = this.getLanguageAttribute(parent);
+                               } else {
+                                       language = this.getLanguageAttributeFromBlockElements();
+                               }
+                       }
+                       var obj = this.getDropDownConfiguration("Language");
+                       if ((typeof(obj) !== "undefined") && (typeof(this.editor._toolbarObjects[obj.id]) !== "undefined")) {
+                               this.updateValue(obj, language, selectionEmpty, fullNodeSelected, endPointsInSameBlock);
+                       }
+               }
+       },
+
+       /*
+       * This function updates the language drop-down list
+       */
+       updateValue : function (obj, language, selectionEmpty, fullNodeSelected, endPointsInSameBlock) {
+               var select = document.getElementById(this.editor._toolbarObjects[obj.id]["elementId"]);
+               var options = select.options;
+               for (var i = options.length; --i >= 0;) {
+                       options[i].selected = false;
+               }
+               select.selectedIndex = 0;
+               options[0].selected = true;
+               select.options[0].text = this.localize("No language mark");
+               if (language != "none") {
+                       for (i = options.length; --i >= 0;) {
+                               if (language == options[i].value) {
+                                       if (selectionEmpty || fullNodeSelected || !endPointsInSameBlock) {
+                                               options[i].selected = true;
+                                               select.selectedIndex = i;
+                                               select.options[0].text = this.localize("Remove language mark");
+                                       }
+                                       break;
+                               }
+                       }
+               }
+               select.disabled = !(options.length>1) || (selectionEmpty && this.editor.getParentElement().nodeName.toLowerCase() === "body");
+               select.className = "";
+               if (select.disabled) {
+                       select.className = "buttonDisabled";
                }
        }
 });
-
index 193aedf..bc1813d 100644 (file)
@@ -9,6 +9,9 @@
                <languageKey index="default" type="array">
                        <label index="LeftToRight-Tooltip">Direction left to right</label>
                        <label index="RightToLeft-Tooltip">Direction right to left</label>
+                       <label index="Language-Tooltip">Language</label>
+                       <label index="ShowLanguageMarks-Tooltip">Show language marks</label>
+                       <label index="Technische Universitat Ilmenau">Technische Universit├Ąt Ilmenau</label>
                </languageKey>
        </data>
        <orig_hash type="array">
index 275fa3e..9f573f5 100644 (file)
@@ -3,7 +3,7 @@
 *
 *  (c) 2002 interactivetools.com, inc. Authored by Mihai Bazon, sponsored by http://www.bloki.com.
 *  (c) 2005 Xinha, http://xinha.gogo.co.nz/ for the original toggle borders function.
-*  (c) 2004-2008 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2004-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -200,6 +200,7 @@ TableOperations = HTMLArea.Plugin.extend({
                                TableOperations.insertSpace(doc, content);
                        }
                }
+               this.buildLanguageFieldset(doc, table, content, "floating");
                if (this.removedFieldsets.indexOf("layout") == -1) this.buildLayoutFieldset(doc, table, content, "floating");
                if (this.removedFieldsets.indexOf("alignment") == -1) this.buildAlignmentFieldset(doc, table, content);
                TableOperations.insertSpace(doc, content);
@@ -340,6 +341,12 @@ TableOperations = HTMLArea.Plugin.extend({
                                                this.editor.plugins.BlockStyle.instance.applyClassChange(tpart, val);
                                        }
                                        break;
+                                   case "f_lang":
+                                       this.getPluginInstance("Language").setLanguageAttributes(table, val);
+                                       break;
+                                   case "f_dir":
+                                       table.dir = (val != "not set") ? val : "";
+                                       break;
                                }
                        }
                }
@@ -416,6 +423,7 @@ TableOperations = HTMLArea.Plugin.extend({
                } else {
                        TableOperations.insertSpace(doc, content);
                }
+               this.buildLanguageFieldset(doc, element, content, "floating");
                if (this.removedFieldsets.indexOf("layout") == -1) this.buildLayoutFieldset(doc, element, content, "floating");
                if (this.removedFieldsets.indexOf("alignment") == -1) this.buildAlignmentFieldset(doc, element, content);
                if (this.removedFieldsets.indexOf("borders") == -1) this.buildBordersFieldset(dialog.dialogWindow, doc, dialog.editor, element, content);
@@ -479,6 +487,12 @@ TableOperations = HTMLArea.Plugin.extend({
                                    case "f_class":
                                        this.editor.plugins.BlockStyle.instance.applyClassChange(element, val);
                                        break;
+                                   case "f_lang":
+                                       this.getPluginInstance("Language").setLanguageAttributes(element, val);
+                                       break;
+                                   case "f_dir":
+                                       element.dir = (val != "not set") ? val : "";
+                                       break;
                                }
                        }
                }
@@ -1646,6 +1660,48 @@ TableOperations = HTMLArea.Plugin.extend({
                content.appendChild(fieldset);
        },
        
+       buildLanguageFieldset : function (doc, el, content, fieldsetClass) {
+               if (this.removedFieldsets.indexOf("language") == -1 && (this.removedProperties.indexOf("language") == -1 || this.removedProperties.indexOf("direction") == -1) && this.getPluginInstance("Language") && (this.isButtonInToolbar("Language") || this.isButtonInToolbar("LeftToRight") || this.isButtonInToolbar("RightToLeft"))) {
+                       var languageObject = this.getPluginInstance("Language");
+                       var fieldset = doc.createElement("fieldset");
+                       if (fieldsetClass) {
+                               fieldset.className = fieldsetClass;
+                       }
+                       TableOperations.insertLegend(doc, fieldset, "Language");
+                       var ul = doc.createElement("ul");
+                       fieldset.appendChild(ul);
+                       if (this.removedProperties.indexOf("language") == -1 && this.isButtonInToolbar("Language")) {
+                               var languageOptions = this.getDropDownConfiguration("Language").options;
+                               var select,
+                                       selected = "",
+                                       options = new Array(),
+                                       values = new Array();
+                               for (var option in languageOptions) {
+                                       if (languageOptions.hasOwnProperty(option)) {
+                                               options.push(option);
+                                               values.push(languageOptions[option]);
+                                       }
+                               }
+                               selected = el ? languageObject.getLanguageAttribute(el) : "none";
+                               if (selected != "none") {
+                                       options[0] = languageObject.localize("Remove language mark");
+                               }
+                               (selected.match(/([^\s]*)\s/)) && (selected = RegExp.$1);
+                               var li = doc.createElement("li");
+                               ul.appendChild(li);
+                               select = TableOperations.buildSelectField(doc, li, "f_lang", "Language:", "fr", "", "Language", options, values, new RegExp((selected ? selected : "none"), "i"));
+                       }
+                       if (this.removedProperties.indexOf("direction") == -1 && (this.isButtonInToolbar("LeftToRight") || this.isButtonInToolbar("RightToLeft"))) {
+                               var li = doc.createElement("li");
+                               ul.appendChild(li);
+                               selected = el ? el.dir : "";
+                               (selected.match(/([^\s]*)\s/)) && (selected = RegExp.$1);
+                               select = TableOperations.buildSelectField(doc, li, "f_dir", "Text direction:", "fr", "", "Text direction", ["Not set", "Right to left", "Left to right"], ["not set", "rtl", "ltr"], new RegExp((selected ? selected : "not set"), "i"));
+                       }
+                       content.appendChild(fieldset);
+               }
+       },
+       
        buildCellTypeFieldset : function (doc, el, content, column, fieldsetClass) {
                var fieldset = doc.createElement("fieldset");
                if (fieldsetClass) fieldset.className = fieldsetClass;
index 585e5fb..9709f1d 100644 (file)
@@ -14,6 +14,14 @@ body.htmlarea-showtableborders table, body.htmlarea-showtableborders td, body.ht
        padding: 3px; border:1px dashed #316ac5 ! important;
 }
 
+/* Make language marks visible */
+body.htmlarea-show-language-marks *[lang] {
+       background: url("images/language-marker.gif") left bottom no-repeat; padding-left: 14px; text-decoration: underline;
+}
+body.htmlarea-show-language-marks *[xml:lang] {
+       background-image: url("images/language-marker.gif"); background-position: left bottom; background-repeat: no-repeat; padding-left: 14px; text-decoration: underline;
+}
+
 /* Selectors for the Abbreviation plugin */
 body.htmlarea-content-body abbr, body.htmlarea-content-body acronym {
        border-bottom:1px dashed #000;
index 19f8f6b..06dac0f 100644 (file)
@@ -83,6 +83,7 @@
 .htmlarea .toolbar .Variable {background-image:url("images/InlineElements/variable.gif");}
 .htmlarea .toolbar .LeftToRight {background-image:url("images/ed_left_to_right.gif");}
 .htmlarea .toolbar .RightToLeft {background-image:url("images/ed_right_to_left.gif");}
+.htmlarea .toolbar .ShowLanguageMarks {background-image:url("images/show-language-marks.gif");}
 .htmlarea .toolbar .Indent {background-image:url("images/BlockElements/indent.gif");}
 .htmlarea .toolbar .Outdent {background-image:url("images/BlockElements/outdent.gif");}
 .htmlarea .toolbar .Blockquote {background-image:url("images/BlockElements/blockquote.gif");}
diff --git a/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/language-marker.gif b/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/language-marker.gif
new file mode 100644 (file)
index 0000000..b1d3a00
Binary files /dev/null and b/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/language-marker.gif differ
diff --git a/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/show-language-marks.gif b/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/show-language-marks.gif
new file mode 100644 (file)
index 0000000..b4f0876
Binary files /dev/null and b/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/show-language-marks.gif differ
index c2219b2..269c87d 100644 (file)
@@ -12,6 +12,7 @@
                        <label index="tx_rtehtmlarea_acronym.type.I.1">Abbreviation</label>
                        <label index="tx_rtehtmlarea_acronym.term">Term</label>
                        <label index="tx_rtehtmlarea_acronym.acronym">Abridged form</label>
+                       <label index="tx_rtehtmlarea_acronym.static_lang_isocode">Language of term</label>
                </languageKey>
        </data>
        <orig_hash type="array">
index b3f30b6..e867216 100644 (file)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2005-2008 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2005-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -57,6 +57,7 @@ class tx_rtehtmlarea_acronym_mod {
                $this->doc->form = '<form action="" id="content" name="content" method="POST">';
                $JScode='
                        var dialog = window.opener.HTMLArea.Dialog.Acronym;
+                       var plugin = dialog.plugin;
                        var editor = dialog.plugin.editor;
                        var param = null;
                        var html = editor.getSelectedHTML();
@@ -64,8 +65,8 @@ class tx_rtehtmlarea_acronym_mod {
                        var range = editor._createRange(sel);
                        var abbr = editor._activeElement(sel);
                                // Working around Safari issue
-                       if (!abbr && editor._statusBarTree.selected) {
-                               abbr = editor._statusBarTree.selected;
+                       if (!abbr && plugin.getPluginInstance("StatusBar") && plugin.getPluginInstance("StatusBar").getSelection()) {
+                               abbr = plugin.getPluginInstance("StatusBar").getSelection();
                        }
                        var abbrType = null;
                        var acronyms = new Object();
@@ -81,7 +82,7 @@ class tx_rtehtmlarea_acronym_mod {
                        }
 
                        function setType() {
-                               if(document.content.acronym.checked) {
+                               if (document.content.acronym.checked) {
                                        abbrType = "acronym";
                                        document.getElementById("abbrType").innerHTML = "' . $LANG->getLL('Acronym') . '";
                                } else {
@@ -89,6 +90,7 @@ class tx_rtehtmlarea_acronym_mod {
                                        document.getElementById("abbrType").innerHTML = "' . $LANG->getLL('Abbreviation') . '";
                                }
                                document.getElementById("title").value = param["title"];
+                               rtehtmlareaAcronymFillLanguage();
                                fillSelect(param);
                                dialog.resize();
                        }
@@ -150,6 +152,7 @@ class tx_rtehtmlarea_acronym_mod {
                                                        }
                                                        if (selectedOption == i) {
                                                                document.content.title.value = i;
+                                                               rtehtmlareaAcronymSelectedLanguage(i);
                                                        }
                                                }
                                        }
@@ -168,6 +171,11 @@ class tx_rtehtmlarea_acronym_mod {
                                        }
                                } else {
                                        var doc = editor._doc;
+                                       var languageObject = plugin.getPluginInstance("Language");
+                                       if (plugin.isButtonInToolbar("Language")) {
+                                               var select = document.getElementById("termLanguageSelector");
+                                               var language = select.options[select.selectedIndex].value;
+                                       }
                                        if (!abbr) {
                                                abbr = doc.createElement(abbrType);
                                                abbr.title = title;
@@ -175,15 +183,69 @@ class tx_rtehtmlarea_acronym_mod {
                                                        html = document.content.acronymSelector.options[document.content.acronymSelector.selectedIndex].value;
                                                }
                                                abbr.innerHTML = html;
+                                               if (languageObject && plugin.isButtonInToolbar("Language")) {
+                                                       languageObject.setLanguageAttributes(abbr, language);
+                                               }
                                                if (HTMLArea.is_ie) range.pasteHTML(abbr.outerHTML);
                                                        else editor.insertNodeAtSelection(abbr);
                                        } else {
                                                abbr.title = title;
-                                               if(document.content.acronymSelector.options.length != 1 && document.content.termSelector.selectedIndex > 0 && document.content.termSelector.options[document.content.termSelector.selectedIndex].value == title) abbr.innerHTML = document.content.acronymSelector.options[document.content.acronymSelector.selectedIndex].value;
+                                               if (languageObject && plugin.isButtonInToolbar("Language")) {
+                                                       languageObject.setLanguageAttributes(abbr, language);
+                                               }
+                                               if (document.content.acronymSelector.options.length != 1 && document.content.termSelector.selectedIndex > 0 && document.content.termSelector.options[document.content.termSelector.selectedIndex].value == title) {
+                                                       abbr.innerHTML = document.content.acronymSelector.options[document.content.acronymSelector.selectedIndex].value;
+                                               }
+                                       }
+                               }
+                       };
+
+                       function rtehtmlareaAcronymFillLanguage() {
+                               if (plugin.isButtonInToolbar("Language")) {
+                                       var languageOptions = plugin.getDropDownConfiguration("Language").options;
+                                       var select = document.getElementById("termLanguageSelector");
+                                       while (select.options.length > 0) {
+                                               select.options[select.length-1] = null;
+                                       }
+                                       for (var option in languageOptions) {
+                                               if (languageOptions.hasOwnProperty(option)) {
+                                                       var addOption = document.createElement("option");
+                                                       addOption.innerHTML = option;
+                                                       addOption.value = languageOptions[option];
+                                                       select.appendChild(addOption);
+                                               }
                                        }
+                               } else {
+                                       document.getElementById("languageSelector").style.display = "none";
                                }
                        };
 
+                       function rtehtmlareaAcronymSelectedLanguage(term) {
+                               if (abbrType == "acronym") {
+                                       var languages = acronymLanguage;
+                               } else {
+                                       var languages = abbreviationLanguage;
+                               }
+                               if (document.getElementById("languageSelector").style.display != "none") {
+                                       var select = document.getElementById("termLanguageSelector");
+                                       var options = select.options;
+                                       for (var i = options.length; --i >= 0;) {
+                                               options[i].selected = false;
+                                       }
+                                       select.selectedIndex = 0;
+                                       options[0].selected = true;
+                                       if (languages[term]) {
+                                               for (i = options.length; --i >= 0;) {
+                                                       if (languages[term] == options[i].value) {
+                                                               options[i].selected = true;
+                                                               select.selectedIndex = i;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
                        function onOK() {
                                processAcronym(document.getElementById("title").value);
                                dialog.close();
@@ -254,17 +316,26 @@ class tx_rtehtmlarea_acronym_mod {
                <div>
                        <label class="fl" for="termSelector" id="termSelectorLabel" title="' . $LANG->getLL('Select_a_term',1) . '">' . $LANG->getLL('Unabridged_term',1) . '</label>
                        <select id="termSelector" name="termSelector"  title="' . $LANG->getLL('Select_a_term',1) . '"
-                               onChange="document.content.acronymSelector.selectedIndex=document.content.termSelector.selectedIndex; document.content.title.value=document.content.termSelector.options[document.content.termSelector.selectedIndex].value;">
+                               onChange="document.content.acronymSelector.selectedIndex=document.content.termSelector.selectedIndex;
+                                       document.content.title.value=document.content.termSelector.options[document.content.termSelector.selectedIndex].value;
+                                       rtehtmlareaAcronymSelectedLanguage(document.content.title.value);">
                                <option value=""></option>
                        </select>
                </div>
                <div>
                        <label class="fl" for="acronymSelector" id="acronymSelectorLabel" title="' . $LANG->getLL('Select_an_acronym',1) . '">' . $LANG->getLL('Abridged_term',1) . '</label>
                        <select id="acronymSelector" name="acronymSelector"  title="' . $LANG->getLL('Select_an_acronym',1) . '"
-                               onChange="document.content.termSelector.selectedIndex=document.content.acronymSelector.selectedIndex; document.content.title.value=document.content.termSelector.options[document.content.termSelector.selectedIndex].value;">
+                               onChange="document.content.termSelector.selectedIndex=document.content.acronymSelector.selectedIndex;
+                                       document.content.title.value=document.content.termSelector.options[document.content.termSelector.selectedIndex].value;
+                                       rtehtmlareaAcronymSelectedLanguage(document.content.title.value);">
                                <option value=""></option>
                        </select>
                </div>
+               <div id="languageSelector">
+                       <label class="fl" for="termLanguageSelector" id="termLanguageSelectorLabel" title="' . $LANG->getLL('Select_a_language',1) . '">' . $LANG->getLL('Language',1) . '</label>
+                       <select id="termLanguageSelector" name="termLanguageSelector"  title="' . $LANG->getLL('Select_a_language',1) . '">
+                       </select>
+               </div>
        </fieldset>
        <fieldset>
                <legend>' . $LANG->getLL('Term_to_abridge',1) . '</legend>
index c511940..d236241 100644 (file)
@@ -21,6 +21,8 @@
                        <label index="OK">OK</label>
                        <label index="Delete">Delete</label>
                        <label index="Cancel">Cancel</label>
+                       <label index="Language">Language:</label>
+                       <label index="Select_a_language">Select a language</label>
                </languageKey>
        </data>
        <orig_hash type="array">
index bc20440..d7d3b64 100644 (file)
@@ -3,7 +3,7 @@
 *  Copyright notice
 *
 *  (c) 1999-2008 Kasper Skaarhoj (kasper@typo3.com)
-*  (c) 2004-2008 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2004-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -494,6 +494,16 @@ class tx_rtehtmlarea_select_image extends browse_links {
                                var classesImage = ' . ($this->thisConfig['classesImage']?'true':'false') . ';
                                if (classesImage) var styleSelector=\'<select id="iClass" name="iClass" style="width:140px;">' . $classesImageJSOptions  . '</select>\';
                                var floatSelector=\'<select id="iFloat" name="iFloat"><option value="">' . $LANG->getLL('notSet') . '</option><option value="none">' . $LANG->getLL('nonFloating') . '</option><option value="left">' . $LANG->getLL('left') . '</option><option value="right">' . $LANG->getLL('right') . '</option></select>\';
+                               if (plugin.isButtonInToolbar("Language")) {
+                                       var languageOptions = plugin.getDropDownConfiguration("Language").options;
+                                       var languageSelector = \'<select id="iLang" name="iLang">\';
+                                       for (var option in languageOptions) {
+                                               if (languageOptions.hasOwnProperty(option)) {
+                                                       languageSelector +=\'<option value="\' + languageOptions[option] + \'">\' + option + \'</option>\';
+                                               }
+                                       }
+                                       languageSelector += \'</select>\';
+                               }
                                var bgColor=\' class="bgColor4"\';
                                var sz="";
                                sz+=\'<table border=0 cellpadding=1 cellspacing=1><form action="" name="imageData">\';
@@ -525,6 +535,10 @@ class tx_rtehtmlarea_select_image extends browse_links {
                                sz+=\'<tr><td\'+bgColor+\'><label for="iTitle">'.$LANG->getLL('title').': </label></td><td><input type="text" id="iTitle" name="iTitle"'.$GLOBALS['TBE_TEMPLATE']->formWidth(20).' /></td></tr>\';')
                                .(in_array('alt', $removedProperties)?'':'
                                sz+=\'<tr><td\'+bgColor+\'><label for="iAlt">'.$LANG->getLL('alt').': </label></td><td><input type="text" id="iAlt" name="iAlt"'.$GLOBALS['TBE_TEMPLATE']->formWidth(20).' /></td></tr>\';')
+                               .(in_array('lang', $removedProperties)?'':'
+                               if (plugin.isButtonInToolbar("Language")) {
+                                       sz+=\'<tr><td\'+bgColor+\'><label for="iLang">\' + plugin.getPluginInstance("Language").localize(\'Language-Tooltip\') + \': </label></td><td>\' + languageSelector + \'</td></tr>\';
+                               }')
                                .(in_array('clickenlarge', $removedProperties)?'':'
                                sz+=\'<tr><td\'+bgColor+\'><label for="iClickEnlarge">'.$LANG->sL('LLL:EXT:cms/locallang_ttc.php:image_zoom',1).' </label></td><td><input type="checkbox" name="iClickEnlarge" id="iClickEnlarge" value="0" /></td></tr>\';').'
                                sz+=\'<tr><td><input type="submit" value="'.$LANG->getLL('update').'" onClick="return setImageProperties();"></td></tr>\';
@@ -580,7 +594,6 @@ class tx_rtehtmlarea_select_image extends browse_links {
                                        if (document.imageData.iAlt) {
                                                selectedImageRef.alt=document.imageData.iAlt.value;
                                        }
-
                                        if (document.imageData.iBorder) {
                                                selectedImageRef.style.borderStyle = "";
                                                selectedImageRef.style.borderWidth = "";
@@ -599,7 +612,6 @@ class tx_rtehtmlarea_select_image extends browse_links {
                                                }
                                                selectedImageRef.removeAttribute("border");
                                        }
-
                                        if (document.imageData.iFloat) {
                                                var iFloat = document.imageData.iFloat.options[document.imageData.iFloat.selectedIndex].value;
                                                if (iFloat || selectedImageRef.style.cssFloat || selectedImageRef.style.styleFloat) {
@@ -610,7 +622,6 @@ class tx_rtehtmlarea_select_image extends browse_links {
                                                        }
                                                }
                                        }
-
                                        if (classesImage && document.imageData.iClass) {
                                                var iClass = document.imageData.iClass.options[document.imageData.iClass.selectedIndex].value;
                                                if (iClass || (selectedImageRef.attributes["class"] && selectedImageRef.attributes["class"].value)) {
@@ -619,7 +630,15 @@ class tx_rtehtmlarea_select_image extends browse_links {
                                                        selectedImageRef.className = "";
                                                }
                                        }
-
+                                       if (document.imageData.iLang) {
+                                               var iLang = document.imageData.iLang.options[document.imageData.iLang.selectedIndex].value;
+                                               var languageObject = plugin.getPluginInstance("Language");
+                                               if (iLang || languageObject.getLanguageAttribute(selectedImageRef)) {
+                                                       languageObject.setLanguageAttributes(selectedImageRef, iLang);
+                                               } else {
+                                                       languageObject.setLanguageAttributes(selectedImageRef, "none");
+                                               }
+                                       }
                                        if (document.imageData.iClickEnlarge) {
                                                if (document.imageData.iClickEnlarge.checked) {
                                                        selectedImageRef.setAttribute("clickenlarge","1");
@@ -694,17 +713,28 @@ class tx_rtehtmlarea_select_image extends browse_links {
                                                        }
                                                }
                                        }
-
                                        if (classesImage && document.imageData.iClass) {
                                                var fObj=document.imageData.iClass;
                                                var value=selectedImageRef.className;
                                                var l=fObj.length;
-                                               for (var a=0;a < l; a++)        {
-                                                       if (fObj.options[a].value == value)     {
+                                               for (var a=0;a < l; a++) {
+                                                       if (fObj.options[a].value == value) {
                                                                fObj.selectedIndex = a;
                                                        }
                                                }
                                        }
+                                       if (document.imageData.iLang) {
+                                               var fObj=document.imageData.iLang;
+                                               var value=plugin.getPluginInstance("Language").getLanguageAttribute(selectedImageRef);
+                                               for (var i = 0, n = fObj.length; i < n; i++) {
+                                                       if (fObj.options[i].value == value) {
+                                                               fObj.selectedIndex = i;
+                                                               if (i) {
+                                                                       fObj.options[0].text = plugin.getPluginInstance("Language").localize("Remove language mark");
+                                                               }
+                                                       }
+                                               }
+                                       }
                                        if (document.imageData.iClickEnlarge) {
                                                if (selectedImageRef.getAttribute("clickenlarge") == "1") {
                                                        document.imageData.iClickEnlarge.checked = 1;
index 35b3b2f..da0d0af 100644 (file)
@@ -71,7 +71,7 @@ $TCA['tx_rtehtmlarea_acronym'] = Array (
                ),
                'term' => Array (               
                        'exclude' => 0,         
-                       'label' => 'LLL:EXT:rtehtmlarea/locallang_db.xml:tx_rtehtmlarea_acronym.term',          
+                       'label' => 'LLL:EXT:rtehtmlarea/locallang_db.xml:tx_rtehtmlarea_acronym.term',
                        'config' => Array (
                                'type' => 'input',
                                'size' => '30',
@@ -80,16 +80,36 @@ $TCA['tx_rtehtmlarea_acronym'] = Array (
                ),
                'acronym' => Array (            
                        'exclude' => 0,         
-                       'label' => 'LLL:EXT:rtehtmlarea/locallang_db.xml:tx_rtehtmlarea_acronym.acronym',               
+                       'label' => 'LLL:EXT:rtehtmlarea/locallang_db.xml:tx_rtehtmlarea_acronym.acronym',
                        'config' => Array (
                                'type' => 'input',
                                'size' => '30',
                                'eval' => 'trim,required',
                        )
                ),
+               'static_lang_isocode' => Array (                
+                       'exclude' => 0,
+                       'label' => 'LLL:EXT:rtehtmlarea/locallang_db.xml:tx_rtehtmlarea_acronym.static_lang_isocode',
+                       'displayCond' => 'EXT:static_info_tables:LOADED:true',
+                       'config' => array(
+                               'type' => 'select',
+                               'items' => array(
+                                       array('', 0),
+                               ),
+                               'itemsProcFunc' => 'tx_staticinfotables_div->selectItemsTCA',
+                               'itemsProcFunc_config' => array(
+                                       'table' => 'static_languages',
+                                       'indexField' => 'uid',
+                                       'prependHotlist' => 1,
+                               ),
+                               'size' => 1,
+                               'minitems' => 0,
+                               'maxitems' => 1,
+                       )
+               ),
        ),
        'types' => Array (
-               '0' => Array( 'showitem' => 'hidden;;1;;1-1-1, sys_language_uid, type, term, acronym')
+               '0' => Array( 'showitem' => 'hidden;;1;;1-1-1, sys_language_uid, type, term, acronym, static_lang_isocode')
        ),
        "palettes" => Array (
                "1" => Array("showitem" => "starttime, endtime")
index 585e5fb..9709f1d 100644 (file)
@@ -14,6 +14,14 @@ body.htmlarea-showtableborders table, body.htmlarea-showtableborders td, body.ht
        padding: 3px; border:1px dashed #316ac5 ! important;
 }
 
+/* Make language marks visible */
+body.htmlarea-show-language-marks *[lang] {
+       background: url("images/language-marker.gif") left bottom no-repeat; padding-left: 14px; text-decoration: underline;
+}
+body.htmlarea-show-language-marks *[xml:lang] {
+       background-image: url("images/language-marker.gif"); background-position: left bottom; background-repeat: no-repeat; padding-left: 14px; text-decoration: underline;
+}
+
 /* Selectors for the Abbreviation plugin */
 body.htmlarea-content-body abbr, body.htmlarea-content-body acronym {
        border-bottom:1px dashed #000;
index f1e5d13..0a74c14 100644 (file)
@@ -93,6 +93,7 @@
 .htmlarea .toolbar .Variable {background-image:url("images/InlineElements/variable.gif");}
 .htmlarea .toolbar .LeftToRight {background-image:url("images/ed_left_to_right.gif");}
 .htmlarea .toolbar .RightToLeft {background-image:url("images/ed_right_to_left.gif");}
+.htmlarea .toolbar .ShowLanguageMarks {background-image:url("images/show-language-marks.gif");}
 .htmlarea .toolbar .Indent {background-image:url("images/BlockElements/indent.gif");}
 .htmlarea .toolbar .Outdent {background-image:url("images/BlockElements/outdent.gif");}
 .htmlarea .toolbar .Blockquote {background-image:url("images/BlockElements/blockquote.gif");}
diff --git a/typo3/sysext/t3skin/rtehtmlarea/images/language-marker.gif b/typo3/sysext/t3skin/rtehtmlarea/images/language-marker.gif
new file mode 100644 (file)
index 0000000..b1d3a00
Binary files /dev/null and b/typo3/sysext/t3skin/rtehtmlarea/images/language-marker.gif differ
diff --git a/typo3/sysext/t3skin/rtehtmlarea/images/show-language-marks.gif b/typo3/sysext/t3skin/rtehtmlarea/images/show-language-marks.gif
new file mode 100644 (file)
index 0000000..b4f0876
Binary files /dev/null and b/typo3/sysext/t3skin/rtehtmlarea/images/show-language-marks.gif differ