r68792 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r68791‎ | r68792 | r68793 >
Date:21:38, 30 June 2010
Author:werdna
Status:deferred
Tags:
Comment:
Update LiquidThreads alpha to trunk state
Modified paths:
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha (modified) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/LiquidThreads.php (modified) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/api/ApiQueryLQTThreads.php (modified) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/api/ApiThreadAction.php (modified) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/classes/Hooks.php (modified) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/classes/Thread.php (modified) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/classes/View.php (modified) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/i18n/Lqt.i18n.php (modified) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/js (added) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/lqt.css (modified) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/lqt.js (modified) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/lqt.sql (modified) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/schema-changes/thread_pending_relationship.sql (added) (history)
  • /branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/schema-changes/thread_reactions.sql (added) (history)

Diff [purge]

Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/i18n/Lqt.i18n.php
@@ -5643,7 +5643,7 @@
56445644 'lqt-drag-setsortkey' => 'Modifier la position du message dans la page',
56455645 'lqt-drag-bump' => 'Déplacer le message vers le haut de la page de discussion',
56465646 'lqt-drag-save' => 'Confirmer',
5647 - 'lqt-drag-reason' => 'Raison :',
 5647+ 'lqt-drag-reason' => 'Motif :',
56485648 'lqt-drag-subject' => 'Sujet du nouveau fil de discussion',
56495649 'lqt-edit-signature' => '(modifier la signature)',
56505650 'lqt-preview-signature' => '(prévisualiser)',
@@ -13777,6 +13777,13 @@
1377813778 'lqt-reply-subpage' => 'ответить',
1377913779 );
1378013780
 13781+/** Rusyn (русиньскый язык)
 13782+ * @author Gazeb
 13783+ */
 13784+$messages['rue'] = array(
 13785+ 'lqt-reply-subpage' => 'одповісти',
 13786+);
 13787+
1378113788 /** Yakut (Саха тыла)
1378213789 * @author HalanTul
1378313790 */
@@ -16822,6 +16829,7 @@
1682316830 * Xung đột với tiền tố liên wiki hay tên của không gian tên.',
1682416831 'lqt_empty_subject' => 'Bạn cần phải nhập chủ đề.',
1682516832 'lqt_reply' => 'Hồi âm',
 16833+ 'lqt-parent' => 'Mẹ',
1682616834 'lqt_delete' => 'Xóa',
1682716835 'lqt_undelete' => 'Phục hồi',
1682816836 'lqt_permalink' => 'Liên kết tới đây',
@@ -16983,7 +16991,10 @@
1698416992 'lqt-log-header' => 'Nhật trình này liệt kê các tác vụ luồng thảo luận.',
1698516993 'lqt-log-action-move' => 'di chuyển [[$1]] từ [[$2]] đến [[$3]].',
1698616994 'lqt-log-action-split' => 'chia [[$1]] khỏi [[$3]] với chủ đề mới là “$2”',
 16995+ 'lqt-log-action-merge-across' => 'đã di chuyển [[$1]] từ [[$2]] sang [[$3]]',
1698716996 'lqt-log-action-merge-down' => 'hợp nhất [[$1]] vào dưới [[$3]]',
 16997+ 'lqt-log-action-subjectedit' => 'đã đổi tiêu đề [[$1]] từ “$2” thành “$3”',
 16998+ 'lqt-log-action-resort' => 'đã thay đổi thứ tự sắp xếp của [[$1]] bằng cách đổi từ khóa sắp xếp từ $2 thành $3',
1698816999 'lqt-preference-notify-talk' => 'Gửi thư cho tôi khi ai trả lời luồng tôi đang theo dõi',
1698917000 'lqt-preference-watch-threads' => 'Theo dõi các luồng tôi tạo hay trả lời',
1699017001 'prefs-lqt' => 'Thảo luận theo luồng',
@@ -17087,8 +17098,24 @@
1708817099 * @author פוילישער
1708917100 */
1709017101 $messages['yi'] = array(
 17102+ 'lqt_contents_title' => 'אינהאַלטן',
 17103+ 'lqt_new_thread' => 'אָנהייבן אַ נייַע דיסקוסיע',
 17104+ 'lqt_empty_subject' => 'איר מוזט אַרײַנגעבן א טעמע',
 17105+ 'lqt_reply' => 'ענטפער',
 17106+ 'lqt-parent' => 'פֿאָטער',
1709117107 'lqt_delete' => 'אויסמעקן',
1709217108 'lqt_undelete' => 'מבטל זיין אויסמעקן',
 17109+ 'lqt_permalink' => 'לינק צו',
 17110+ 'lqt_fragment' => 'פֿראַגמענט פון אַ $1 פֿון $2',
 17111+ 'lqt_discussion_link' => 'דיסקוסיע',
 17112+ 'lqt_from_talk' => 'פֿון $1',
 17113+ 'lqt_newer' => '← נייַערער',
 17114+ 'lqt_older' => 'עלטערער →',
 17115+ 'lqt-history-title' => 'פֿאָדעם געשיכטע',
 17116+ 'lqt_hist_summary_changed' => 'רעזומע געענדערט',
 17117+ 'lqt_hist_deleted' => 'אויסגעמעקט',
 17118+ 'lqt_hist_undeleted' => 'צוריקגעשטעלט',
 17119+ 'lqt_hist_moved_talkpage' => 'באַװעגט',
1709317120 'lqt_move_torename_edit' => 'באַאַרבעטס עס',
1709417121 'lqt-title' => 'טיטל',
1709517122 'lqt-history-time' => 'צײַט',
Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/lqt.css
@@ -39,7 +39,16 @@
4040 float: left;
4141 width: 100%;
4242 }
43 -
 43+.lqt_thread_heading {
 44+ border-bottom: 1px solid #AAAAAA;
 45+ margin-bottom: 0.6em;
 46+ padding: 10px 0 0;
 47+}
 48+.lqt_header {
 49+ border: none;
 50+ margin-bottom: 0;
 51+ display: inline;
 52+}
4453 .lqt_header_commands {
4554 float: right;
4655 clear: both;
@@ -113,19 +122,17 @@
114123 }
115124
116125 .lqt_threadlevel_commands {
117 - /* shift up to be in line with the h2. */
118 - position: relative;
119 - top: -2.9em;
120 - margin-bottom: -2.9em;
121126 float: right;
122 -
123 - color: #777;
 127+ color: #777;
 128+ margin-bottom: 0 !important;
 129+ margin-top: 0;
124130 }
125131
126132 .lqt_threadlevel_commands li {
127133 display: inline;
128134 list-style-type: none;
129135 padding-right: 0.6em;
 136+ line-height: 1em;
130137 }
131138 #lqt_subject_field {
132139 margin-top: 0.7em;
@@ -471,3 +478,28 @@
472479 .lqt-new-messages {
473480 table-layout: fixed;
474481 }
 482+.lqt-loader {
 483+ top: 15px;
 484+ height: 32px;
 485+}
 486+
 487+/* Float Clearing - If you confused, http://www.positioniseverything.net/easyclearing.html */
 488+.lqt_thread_heading:after
 489+{
 490+ content: ".";
 491+ display: block;
 492+ height: 0;
 493+ clear: both;
 494+ visibility: hidden;
 495+}
 496+
 497+.lqt_thread_heading
 498+{display: inline-block;}
 499+
 500+/* Hides from IE-mac */
 501+* html .lqt_thread_heading
 502+{height: 1%;}
 503+
 504+.lqt_thread_heading
 505+{display: block;}
 506+/* End hide from IE-mac */
Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/LiquidThreads.php
@@ -201,9 +201,11 @@
202202
203203 $wgGroupPermissions['user']['lqt-split'] = true;
204204 $wgGroupPermissions['user']['lqt-merge'] = true;
 205+$wgGroupPermissions['user']['lqt-react'] = true;
205206
206207 $wgAvailableRights[] = 'lqt-split';
207208 $wgAvailableRights[] = 'lqt-merge';
 209+$wgAvailableRights[] = 'lqt-react';
208210
209211 /* Allows activation of LiquidThreads on individual pages */
210212 $wgLqtPages = array();
Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/classes/View.php
@@ -436,7 +436,7 @@
437437
438438 if ( $this->output->getRedirect() != '' ) {
439439 $redirectTitle = clone $talkpage->getTitle();
440 - if ( $thread ) {
 440+ if ( !empty($thread) ) {
441441 $redirectTitle->setFragment( '#' . $this->anchorName( $thread ) );
442442 }
443443 $this->output->redirect( $this->title->getFullURL() );
@@ -543,7 +543,7 @@
544544
545545 if ( $this->output->getRedirect() != '' ) {
546546 $redirectTitle = clone $talkpage->getTitle();
547 - if ( !is_null( $newThread ) ) {
 547+ if ( !empty( $newThread ) ) {
548548 $redirectTitle->setFragment( '#' .
549549 $this->anchorName( $newThread ) );
550550 }
@@ -1211,7 +1211,13 @@
12121212 $wgOut->addScriptFile( "$basePath/jquery/jquery.autogrow.js" );
12131213
12141214 $wgOut->addScriptFile( "$basePath/lqt.js" );
 1215+ $wgOut->addScriptFile( "$basePath/js/lqt.toolbar.js" );
12151216 $wgOut->addExtensionStyle( "$basePath/lqt.css?{$wgStyleVersion}" );
 1217+
 1218+ if ( class_exists( 'WikiEditorHooks' ) ) {
 1219+ $temp = null;
 1220+ WikiEditorHooks::addModules( $temp );
 1221+ }
12161222
12171223 self::$stylesAndScriptsDone = true;
12181224 }
@@ -1556,7 +1562,11 @@
15571563 array( 'class' => 'lqt_header', 'id' => $id ),
15581564 $html ) . $commands_html;
15591565 }
1560 -
 1566+
 1567+ // wrap it all in a container
 1568+ $html = Xml::tags( 'div',
 1569+ array( 'class' => 'lqt_thread_heading' ),
 1570+ $html );
15611571 return $html;
15621572 }
15631573
@@ -1591,7 +1601,7 @@
15921602
15931603 if ( !$target ) {
15941604 throw new MWException( "Thread " . $thread->id() . ' purports to be moved, ' .
1595 - 'but no redirect found in text of ' .
 1605+ 'but no redirect found in text (' . $article->getContent() . ') of ' .
15961606 $thread->root()->getTitle()->getPrefixedText() . '. Dying.' );
15971607 }
15981608
Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/classes/Hooks.php
@@ -313,6 +313,8 @@
314314 $wgExtNewTables[] = array( 'thread', "$dir/lqt.sql" );
315315 $wgExtNewTables[] = array( 'user_message_state', "$dir/lqt.sql" );
316316 $wgExtNewTables[] = array( 'thread_history', "$dir/schema-changes/thread_history_table.sql" );
 317+ $wgExtNewTables[] = array( 'thread_pending_relationship', "$dir/schema-changes/thread_pending_relationship.sql" );
 318+ $wgExtNewTables[] = array( 'thread_reaction', "$dir/schema-changes/thread_reactions.sql" );
317319
318320 $wgExtNewFields[] = array( "thread", "thread_article_namespace", "$dir/schema-changes/split-thread_article.sql" );
319321 $wgExtNewFields[] = array( "thread", "thread_article_title", "$dir/schema-changes/split-thread_article.sql" );
Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/classes/Thread.php
@@ -45,12 +45,14 @@
4646 protected $editors = null;
4747
4848 protected $replies;
 49+ protected $reactions;
4950
5051 public $dbVersion; // A copy of the thread as it exists in the database.
5152
5253 static $titleCacheById = array();
5354 static $replyCacheById = array();
5455 static $articleCacheById = array();
 56+ static $reactionCacheById = array();
5557
5658 static $VALID_TYPES = array( Threads::TYPE_NORMAL, Threads::TYPE_MOVED, Threads::TYPE_DELETED );
5759
@@ -549,6 +551,7 @@
550552 // Load a list of threads in bulk, including all subthreads.
551553 static function bulkLoad( $rows ) {
552554 // Preload subthreads
 555+ $all_thread_ids = array();
553556 $top_thread_ids = array();
554557 $all_thread_rows = $rows;
555558 $pageIds = array();
@@ -581,6 +584,8 @@
582585 self::$replyCacheById[$row->thread_id] = array();
583586 }
584587 }
 588+
 589+ $all_thread_ids = $top_thread_ids;
585590
586591 // Pull replies to the threads provided, and as above, pull page IDs to pull data for,
587592 // pre-initialise the reply cache, and stash the row object for later use.
@@ -598,8 +603,40 @@
599604 $pageIds[] = $row->thread_summary_page;
600605
601606 $all_thread_rows[] = $row;
 607+ $all_thread_ids[$row->thread_id] = $row->thread_id;
602608 }
603609 }
 610+
 611+ // Pull thread reactions
 612+ if ( count( $all_thread_ids ) ) {
 613+ $res = $dbr->select( 'thread_reaction', '*',
 614+ array( 'tr_thread' => $all_thread_ids ),
 615+ __METHOD__ );
 616+
 617+ foreach( $res as $row ) {
 618+ $thread_id = $row->tr_thread;
 619+ $user = $row->tr_user_text;
 620+ $info = array(
 621+ 'type' => $row->tr_type,
 622+ 'user-id' => $row->tr_user,
 623+ 'user-name' => $row->tr_user_text,
 624+ 'value' => $row->tr_value,
 625+ );
 626+
 627+ $type = $info['type'];
 628+ $user = $info['user-name'];
 629+
 630+ if ( ! isset( self::$reactionCacheById[$thread_id] ) ) {
 631+ self::$reactionCacheById[$thread_id] = array();
 632+ }
 633+
 634+ if ( ! isset( self::$reactionCacheById[$thread_id][$type] ) ) {
 635+ self::$reactionCacheById[$thread_id][$type] = array();
 636+ }
 637+
 638+ self::$reactionCacheById[$thread_id][$type][$user] = $info;
 639+ }
 640+ }
604641
605642 // Preload page data (restrictions, and preload Article object with everything from
606643 // the page table. Also, precache the title and article objects for pulling later.
@@ -1547,4 +1584,84 @@
15481585 public function getTitle() {
15491586 return $this->article()->getTitle();
15501587 }
 1588+
 1589+ public function getReactions( $requestedType = null ) {
 1590+ if ( is_null( $this->reactions ) ) {
 1591+ if ( isset( self::$reactionCacheById[$this->id()] ) ) {
 1592+ $this->reactions = self::$reactionCacheById[$this->id()];
 1593+ } else {
 1594+ $reactions = array();
 1595+
 1596+ $res = $dbr->select( 'thread_reaction',
 1597+ array( 'tr_thread' => $this->id() ),
 1598+ __METHOD__ );
 1599+
 1600+ foreach( $res as $row ) {
 1601+ $thread_id = $row->tr_thread;
 1602+ $user = $row->tr_user_text;
 1603+ $info = array(
 1604+ 'type' => $row->tr_type,
 1605+ 'user-id' => $row->tr_user,
 1606+ 'user-name' => $row->tr_user_text,
 1607+ 'value' => $row->tr_value,
 1608+ );
 1609+
 1610+ if ( ! isset( $reactions[$type] ) ) {
 1611+ $reactions[$type] = array();
 1612+ }
 1613+
 1614+ $reactions[$type][$user] = $info;
 1615+ }
 1616+
 1617+ $this->reactions = $reactions;
 1618+ }
 1619+ }
 1620+
 1621+ if ( is_null($requestedType) ) {
 1622+ return $this->reactions;
 1623+ } else {
 1624+ return $this->reactions[$requestedType];
 1625+ }
 1626+ }
 1627+
 1628+ public function addReaction( $user, $type, $value ) {
 1629+ $info = array(
 1630+ 'type' => $type,
 1631+ 'user-id' => $user->getId(),
 1632+ 'user-name' => $user->getName(),
 1633+ 'value' => $value,
 1634+ );
 1635+
 1636+ if ( ! isset( $this->reactions[$type] ) ) {
 1637+ $this->reactions[$type] = array();
 1638+ }
 1639+
 1640+ $this->reactions[$type][$user->getName()] = $info;
 1641+
 1642+ $row = array(
 1643+ 'tr_type' => $type,
 1644+ 'tr_thread' => $this->id(),
 1645+ 'tr_user' => $user->getId(),
 1646+ 'tr_user_text' => $user->getName(),
 1647+ 'tr_value' => $value,
 1648+ );
 1649+
 1650+ $dbw = wfGetDB( DB_MASTER );
 1651+
 1652+ $dbw->insert( 'thread_reaction', $row, __METHOD__ );
 1653+ }
 1654+
 1655+ public function deleteReaction( $user, $type ) {
 1656+ $dbw = wfGetDB( DB_MASTER );
 1657+
 1658+ if ( isset( $this->reactions[$type][$user->getName()] ) ) {
 1659+ unset( $this->reactions[$type][$user->getName()] );
 1660+ }
 1661+
 1662+ $dbw->delete( 'thread_reaction',
 1663+ array( 'tr_thread' => $this->id(),
 1664+ 'tr_user' => $user->getId(),
 1665+ 'tr_type' => $type ),
 1666+ __METHOD__ );
 1667+ }
15511668 }
Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/lqt.sql
@@ -91,7 +91,19 @@
9292 CREATE TABLE /*_*/thread_pending_relationship (
9393 tpr_thread int unsigned NOT NULL,
9494 tpr_relationship varbinary(64) NOT NULL,
95 - tpr_title varbinary(1024) NOT NULL,
 95+ tpr_title varbinary(255) NOT NULL,
9696 tpr_type varbinary(32) NOT NULL,
9797 PRIMARY KEY (tpr_thread,tpr_relationship)
9898 ) /*$wgDBTableOptions*/;
 99+
 100+-- Storage for reactions
 101+CREATE TABLE /*_*/thread_reaction (
 102+ tr_thread int unsigned NOT NULL,
 103+ tr_user int unsigned NOT NULL,
 104+ tr_user_text varbinary(255) NOT NULL,
 105+ tr_type varbinary(64) NOT NULL,
 106+ tr_value int NOT NULL,
 107+
 108+ PRIMARY KEY (tr_thread,tr_user,tr_user_text,tr_type,tr_value),
 109+ KEY (tr_user,tr_user_text,tr_type,tr_value)
 110+) /*$wgDBTableOptions*/;
Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/schema-changes/thread_pending_relationship.sql
@@ -0,0 +1,8 @@
 2+-- Storage for "pending" relationships from import
 3+CREATE TABLE /*_*/thread_pending_relationship (
 4+ tpr_thread int unsigned NOT NULL,
 5+ tpr_relationship varbinary(64) NOT NULL,
 6+ tpr_title varbinary(255) NOT NULL,
 7+ tpr_type varbinary(32) NOT NULL,
 8+ PRIMARY KEY (tpr_thread,tpr_relationship)
 9+) /*$wgDBTableOptions*/;
Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/schema-changes/thread_reactions.sql
@@ -0,0 +1,11 @@
 2+-- Storage for reactions
 3+CREATE TABLE /*_*/thread_reaction (
 4+ tr_thread int unsigned NOT NULL,
 5+ tr_user int unsigned NOT NULL,
 6+ tr_user_text varbinary(255) NOT NULL,
 7+ tr_type varbinary(64) NOT NULL,
 8+ tr_value int NOT NULL,
 9+
 10+ PRIMARY KEY (tr_thread,tr_user,tr_user_text,tr_type,tr_value),
 11+ KEY (tr_user,tr_user_text,tr_type,tr_value)
 12+) /*$wgDBTableOptions*/;
Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/api/ApiQueryLQTThreads.php
@@ -36,6 +36,7 @@
3737 'summaryid' => 'thread_summary_page',
3838 'rootid' => 'thread_root',
3939 'type' => 'thread_type',
 40+ 'reactions' => null,
4041 );
4142
4243 public function __construct( $query, $moduleName ) {
@@ -93,7 +94,9 @@
9495 if ( $params['render'] ) {
9596 $threads = Threads::loadFromResult( $res, $this->getDB() );
9697 }
97 -
 98+
 99+
 100+ $ids = array();
98101 $count = 0;
99102 foreach ( $res as $row )
100103 {
@@ -108,22 +111,47 @@
109112 $fields = self::$propRelations[$name];
110113 self::formatProperty( $name, $fields, $row, $entry );
111114 }
 115+
 116+ if ( isset( $entry['reactions'] ) ) {
 117+ $result->setIndexedTagName( $entry['reactions'], 'reaction' );
 118+ }
112119
113120 // Render if requested
114121 if ( $params['render'] ) {
115122 self::renderThread( $row, $params, $entry );
116123 }
 124+
 125+ $ids[$row->thread_id] = $row->thread_id;
117126
118127 if ( $entry ) {
119128 $fit = $result->addValue( array( 'query',
120129 $this->getModuleName() ),
121 - null, $entry );
 130+ $row->thread_id, $entry );
122131 if ( !$fit ) {
123132 $this->setContinueEnumParameter( 'startid', $row->thread_id );
124133 break;
125134 }
126135 }
127136 }
 137+
 138+ if ( isset( $prop['reactions'] ) ) {
 139+ $dbr = wfGetDB( DB_SLAVE );
 140+ $res = $dbr->select( 'thread_reaction', '*', array( 'tr_thread' => $ids ),
 141+ __METHOD__ );
 142+
 143+ foreach( $res as $row ) {
 144+ $info = array(
 145+ 'type' => $row->tr_type,
 146+ 'user-id' => $row->tr_user,
 147+ 'user-name' => $row->tr_user_text,
 148+ 'value' => $row->tr_value,
 149+ );
 150+
 151+ $result->addValue( array( 'query', $this->getModuleName(), $row->tr_thread, 'reactions' ),
 152+ null, $info );
 153+ }
 154+ }
 155+
128156 $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'thread' );
129157 }
130158
@@ -168,10 +196,12 @@
169197 }
170198
171199 static function formatProperty( $name, $fields, $row, &$entry ) {
172 - if ( !is_array( $fields ) ) {
 200+ if ( is_null( $fields ) ) {
 201+ $entry[$name] = array();
 202+ } elseif ( !is_array( $fields ) ) {
173203 // Common case.
174204 $entry[$name] = $row->$fields;
175 - } else if ( $name == 'page' ) {
 205+ } elseif ( $name == 'page' ) {
176206 // Special cases
177207 $nsField = $fields['namespace'];
178208 $tField = $fields['title'];
Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/api/ApiThreadAction.php
@@ -691,6 +691,76 @@
692692 $this->getResult()->addValue( null, $this->getModuleName(), $result );
693693 }
694694
 695+ public function actionAddReaction( $threads, $params ) {
 696+ global $wgUser;
 697+
 698+ if ( !count( $threads ) ) {
 699+ $this->dieUsage( 'You must specify a thread to add a reaction for',
 700+ 'no-specified-threads' );
 701+ }
 702+
 703+ if ( ! $wgUser->isAllowed( 'lqt-react' ) ) {
 704+ $this->dieUsage( 'You are not allowed to react to threads.', 'permission-denied' );
 705+ }
 706+
 707+ $required = array( 'type', 'value' );
 708+
 709+ if ( count( array_diff( $required, array_keys($params) ) ) ) {
 710+ $this->dieUsage( 'You must specify both a type and a value for the reaction',
 711+ 'missing-parameter' );
 712+ }
 713+
 714+ $result = array();
 715+
 716+ foreach( $threads as $thread ) {
 717+ $thread->addReaction( $wgUser, $params['type'], $params['value'] );
 718+
 719+ $result[] = array(
 720+ 'result' => 'Success',
 721+ 'action' => 'addreaction',
 722+ 'id' => $thread->id(),
 723+ );
 724+ }
 725+
 726+ $this->getResult()->setIndexedTagName( $result, 'thread' );
 727+ $this->getResult()->addValue( null, 'threadaction', $result );
 728+ }
 729+
 730+ public function actionDeleteReaction( $threads, $params ) {
 731+ global $wgUser;
 732+
 733+ if ( !count( $threads ) ) {
 734+ $this->dieUsage( 'You must specify a thread to delete a reaction for',
 735+ 'no-specified-threads' );
 736+ }
 737+
 738+ if ( ! $wgUser->isAllowed( 'lqt-react' ) ) {
 739+ $this->dieUsage( 'You are not allowed to react to threads.', 'permission-denied' );
 740+ }
 741+
 742+ $required = array( 'type', 'value' );
 743+
 744+ if ( count( array_diff( $required, array_keys($params) ) ) ) {
 745+ $this->dieUsage( 'You must specify both a type for the reaction',
 746+ 'missing-parameter' );
 747+ }
 748+
 749+ $result = array();
 750+
 751+ foreach( $threads as $thread ) {
 752+ $thread->deleteReaction( $wgUser, $params['type'] );
 753+
 754+ $result[] = array(
 755+ 'result' => 'Success',
 756+ 'action' => 'deletereaction',
 757+ 'id' => $thread->id(),
 758+ );
 759+ }
 760+
 761+ $this->getResult()->setIndexedTagName( $result, 'thread' );
 762+ $this->getResult()->addValue( null, 'threadaction', $result );
 763+ }
 764+
695765 public function getDescription() {
696766 return 'Allows actions to be taken on threads and posts in threaded discussions.';
697767 }
@@ -706,6 +776,8 @@
707777 'setsubject' => 'actionSetSubject',
708778 'setsortkey' => 'actionSetSortkey',
709779 'edit' => 'actionEdit',
 780+ 'addreaction' => 'actionAddReaction',
 781+ 'deletereaction' => 'actionDeleteReaction',
710782 );
711783 }
712784
@@ -731,6 +803,8 @@
732804 "a unix timestamp or 'now'.",
733805 'signature' => 'Specifies the signature to use for that post. Can be ' .
734806 'NULL to specify the default signature',
 807+ 'type' => 'Specifies the type of reaction to add',
 808+ 'value' => 'Specifies the value associated with the reaction to add',
735809 );
736810 }
737811
@@ -788,6 +862,8 @@
789863 'bump' => null,
790864 'sortkey' => null,
791865 'signature' => null,
 866+ 'type' => null,
 867+ 'value' => null,
792868 );
793869 }
794870
Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/lqt.js
@@ -1,7 +1,7 @@
22 // Prototype in string.trim on browsers that haven't yet implemented
33 if ( typeof String.prototype.trim !== "function" )
44 String.prototype.trim = function() { return this.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); };
5 -
 5+var wgWikiEditorIconVersion = 0;
66 var liquidThreads = {
77 currentReplyThread : null,
88 currentToolbar : null,
@@ -19,7 +19,8 @@
2020 var container = $j(target).closest('.lqt_thread')[0];
2121 var thread_id = $j(this).data('thread-id');
2222
23 - if (thread_id == liquidThreads.currentReplyThread) {
 23+ // hide the form for this thread if it's currently being shown
 24+ if ( thread_id == liquidThreads.currentReplyThread && $j( '#wpTextbox1' ).is( ':visible' ) ) {
2425 liquidThreads.cancelEdit({});
2526 return;
2627 }
@@ -117,7 +118,7 @@
118119
119120 var isIE7 = $j.browser.msie && $j.browser.version.substr(0,1) == '7';
120121
121 - var loadSpinner = $j('<div class="mw-ajax-loader"/>');
 122+ var loadSpinner = $j('<div class="mw-ajax-loader lqt-loader"/>');
122123 $j(container).before( loadSpinner );
123124
124125 var finishShow = function() {
@@ -170,9 +171,16 @@
171172 $j(container).find('#wpTextbox1').attr( 'rows', 12 );
172173 $j(container).find('#wpDiff').hide();
173174
174 - // Add toolbar
175 - mwSetupToolbar();
176 -
 175+ if ( $j.fn.wikiEditor && $j.wikiEditor.isSupported( $j.wikiEditor.modules.toolbar ) ) {
 176+ if ( wgWikiEditorPreferences.toolbar.dialogs && $j.wikiEditor.isSupported( $j.wikiEditor.modules.dialogs ) ) {
 177+ $j( '#wpTextbox1' ).addClass( 'toolbar-dialogs' );
 178+ }
 179+ // Add wikiEditor toolbar
 180+ $j( '#wpTextbox1' ).wikiEditor( 'addModule', { 'toolbar': liquidThreads.toolbar.config, 'dialogs': liquidThreads.toolbar.dialogs } );
 181+ } else {
 182+ // Add old toolbar
 183+ mwSetupToolbar()
 184+ }
177185 currentFocused = $j(container).find('#wpTextbox1');
178186 $j(container).find('#wpTextbox1,#wpSummary').focus(
179187 function() {
@@ -1590,6 +1598,7 @@
15911599
15921600 // Update the new thread link
15931601 var newThreadLink = $j('.lqt_start_discussion a');
 1602+ newThreadLink = newThreadLink.add( $j('li#ca-addsection a') );
15941603
15951604 if (newThreadLink) {
15961605 newThreadLink.click( liquidThreads.handleNewLink );
Index: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha/js/lqt.toolbar.js
@@ -0,0 +1,1981 @@
 2+/* JavaScript config for the WikiEditor Toolbar module */
 3+
 4+liquidThreads.toolbar = {
 5+ 'config': {
 6+ // Main section
 7+ 'main': {
 8+ type: 'toolbar',
 9+ groups: {
 10+ 'format': {
 11+ tools: {
 12+ 'bold': {
 13+ labelMsg: 'wikieditor-toolbar-tool-bold',
 14+ type: 'button',
 15+ offset: {
 16+ 'default': [2, -574],
 17+ 'en': [2, -142],
 18+ 'cs': [2, -142],
 19+ 'de': [2, -214],
 20+ 'fr': [2, -286],
 21+ 'es': [2, -358],
 22+ 'he': [2, -142],
 23+ 'it': [2, -286],
 24+ 'nl': [2, -502],
 25+ 'pt': [2, -358],
 26+ 'pt-br': [2, -358],
 27+ 'pl': [2, -142]
 28+ },
 29+ icon: {
 30+ 'default': 'format-bold.png',
 31+ 'en': 'format-bold-B.png',
 32+ 'cs': 'format-bold-B.png',
 33+ 'de': 'format-bold-F.png',
 34+ 'fr': 'format-bold-G.png',
 35+ 'es': 'format-bold-N.png',
 36+ 'he': 'format-bold-B.png',
 37+ 'it': 'format-bold-G.png',
 38+ 'ka': 'format-bold-ka.png',
 39+ 'nl': 'format-bold-V.png',
 40+ 'pt': 'format-bold-N.png',
 41+ 'pt-br': 'format-bold-N.png',
 42+ 'pl': 'format-bold-B.png',
 43+ 'ru': 'format-bold-ru.png'
 44+ },
 45+ action: {
 46+ type: 'encapsulate',
 47+ options: {
 48+ pre: "'''",
 49+ periMsg: 'wikieditor-toolbar-tool-bold-example',
 50+ post: "'''"
 51+ }
 52+ }
 53+ },
 54+ 'italic': {
 55+ section: 'main',
 56+ group: 'format',
 57+ id: 'italic',
 58+ labelMsg: 'wikieditor-toolbar-tool-italic',
 59+ type: 'button',
 60+ offset: {
 61+ 'default': [2, -718],
 62+ 'en': [2, -862],
 63+ 'cs': [2, -862],
 64+ 'de': [2, -934],
 65+ 'fr': [2, -862],
 66+ 'es': [2, -790],
 67+ 'he': [2, -862],
 68+ 'it': [2, -790],
 69+ 'nl': [2, -790],
 70+ 'pt': [2, -862],
 71+ 'pt-br': [2, -862],
 72+ 'pl': [2, -862],
 73+ 'ru': [2, -934]
 74+ },
 75+ icon: {
 76+ 'default': 'format-italic.png',
 77+ 'en': 'format-italic-I.png',
 78+ 'cs': 'format-italic-I.png',
 79+ 'de': 'format-italic-K.png',
 80+ 'fr': 'format-italic-I.png',
 81+ 'es': 'format-italic-C.png',
 82+ 'he': 'format-italic-I.png',
 83+ 'it': 'format-italic-C.png',
 84+ 'ka': 'format-italic-ka.png',
 85+ 'nl': 'format-italic-C.png',
 86+ 'pt': 'format-italic-I.png',
 87+ 'pt-br': 'format-italic-I.png',
 88+ 'pl': 'format-italic-I.png',
 89+ 'ru': 'format-italic-K.png'
 90+ },
 91+ action: {
 92+ type: 'encapsulate',
 93+ options: {
 94+ pre: "''",
 95+ periMsg: 'wikieditor-toolbar-tool-italic-example',
 96+ post: "''"
 97+ }
 98+ }
 99+ }
 100+ }
 101+ },
 102+ 'insert': {
 103+ tools: {
 104+ 'xlink': {
 105+ labelMsg: 'wikieditor-toolbar-tool-xlink',
 106+ type: 'button',
 107+ icon: 'insert-xlink.png',
 108+ offset: [-70, 2],
 109+ filters: [ '#wpTextbox1:not(.toolbar-dialogs)' ],
 110+ action: {
 111+ type: 'encapsulate',
 112+ options: {
 113+ pre: "[",
 114+ periMsg: 'wikieditor-toolbar-tool-xlink-example',
 115+ post: "]"
 116+ }
 117+ }
 118+ },
 119+ 'ilink': {
 120+ labelMsg: 'wikieditor-toolbar-tool-ilink',
 121+ type: 'button',
 122+ icon: 'insert-ilink.png',
 123+ offset: [2, -1582],
 124+ filters: [ '#wpTextbox1:not(.toolbar-dialogs)' ],
 125+ action: {
 126+ type: 'encapsulate',
 127+ options: {
 128+ pre: "[[",
 129+ periMsg: 'wikieditor-toolbar-tool-ilink-example',
 130+ post: "]]"
 131+ }
 132+ }
 133+ },
 134+ 'linkCGD': {
 135+ labelMsg: 'wikieditor-toolbar-tool-link',
 136+ type: 'button',
 137+ icon: 'insert-link.png',
 138+ offset: [2, -1654],
 139+ filters: [ '#wpTextbox1.toolbar-dialogs' ],
 140+ action: {
 141+ type: 'dialog',
 142+ module: 'insert-link'
 143+ }
 144+ },
 145+ 'file': {
 146+ labelMsg: 'wikieditor-toolbar-tool-file',
 147+ type: 'button',
 148+ icon: 'insert-file.png',
 149+ offset: [2, -1438],
 150+ action: {
 151+ type: 'encapsulate',
 152+ options: {
 153+ // FIXME: Why the hell was this done this way?
 154+ preMsg: [ 'wikieditor-toolbar-tool-file-pre', '[[' ],
 155+ periMsg: 'wikieditor-toolbar-tool-file-example',
 156+ post: "]]"
 157+ }
 158+ }
 159+ },
 160+ 'referenceCGD': {
 161+ labelMsg: 'wikieditor-toolbar-tool-reference',
 162+ type: 'button',
 163+ icon: 'insert-reference.png',
 164+ offset: [2, -1798],
 165+ filters: [ 'body.ns-subject', '#wpTextbox1.toolbar-dialogs' ],
 166+ action: {
 167+ type: 'dialog',
 168+ module: 'insert-reference'
 169+ }
 170+ },
 171+ 'reference': {
 172+ labelMsg: 'wikieditor-toolbar-tool-reference',
 173+ filters: [ 'body.ns-subject', '#wpTextbox1:not(.toolbar-dialogs)' ],
 174+ type: 'button',
 175+ offset: [2, -1798],
 176+ icon: 'insert-reference.png',
 177+ action: {
 178+ type: 'encapsulate',
 179+ options: {
 180+ pre: "<ref>",
 181+ periMsg: 'wikieditor-toolbar-tool-reference-example',
 182+ post: "</ref>"
 183+ }
 184+ }
 185+ }
 186+ }
 187+ }
 188+ }
 189+ },
 190+ // Format section
 191+ 'advanced': {
 192+ labelMsg: 'wikieditor-toolbar-section-advanced',
 193+ type: 'toolbar',
 194+ groups: {
 195+ 'heading': {
 196+ tools: {
 197+ 'heading': {
 198+ labelMsg: 'wikieditor-toolbar-tool-heading',
 199+ type: 'select',
 200+ list: {
 201+ 'heading-2' : {
 202+ labelMsg: 'wikieditor-toolbar-tool-heading-2',
 203+ action: {
 204+ type: 'encapsulate',
 205+ options: {
 206+ pre: '== ',
 207+ periMsg: 'wikieditor-toolbar-tool-heading-example',
 208+ post: ' ==',
 209+ regex: /^(\s*)(={1,6})(.*?)\2(\s*)$/,
 210+ regexReplace: "\$1==\$3==\$4",
 211+ ownline: true
 212+ }
 213+ }
 214+ },
 215+ 'heading-3' : {
 216+ labelMsg: 'wikieditor-toolbar-tool-heading-3',
 217+ action: {
 218+ type: 'encapsulate',
 219+ options: {
 220+ pre: '=== ',
 221+ periMsg: 'wikieditor-toolbar-tool-heading-example',
 222+ post: ' ===',
 223+ regex: /^(\s*)(={1,6})(.*?)\2(\s*)$/,
 224+ regexReplace: "\$1===\$3===\$4",
 225+ ownline: true
 226+ }
 227+ }
 228+ },
 229+ 'heading-4' : {
 230+ labelMsg: 'wikieditor-toolbar-tool-heading-4',
 231+ action: {
 232+ type: 'encapsulate',
 233+ options: {
 234+ pre: '==== ',
 235+ periMsg: 'wikieditor-toolbar-tool-heading-example',
 236+ post: ' ====',
 237+ regex: /^(\s*)(={1,6})(.*?)\2(\s*)$/,
 238+ regexReplace: "\$1====\$3====\$4",
 239+ ownline: true
 240+ }
 241+ }
 242+ },
 243+ 'heading-5' : {
 244+ labelMsg: 'wikieditor-toolbar-tool-heading-5',
 245+ action: {
 246+ type: 'encapsulate',
 247+ options: {
 248+ pre: '===== ',
 249+ periMsg: 'wikieditor-toolbar-tool-heading-example',
 250+ post: ' =====',
 251+ regex: /^(\s*)(={1,6})(.*?)\2(\s*)$/,
 252+ regexReplace: "\$1=====\$3=====\$4",
 253+ ownline: true
 254+ }
 255+ }
 256+ }
 257+ }
 258+ }
 259+ }
 260+ },
 261+ 'format': {
 262+ labelMsg: 'wikieditor-toolbar-group-format',
 263+ tools: {
 264+ 'ulist': {
 265+ labelMsg: 'wikieditor-toolbar-tool-ulist',
 266+ type: 'button',
 267+ icon: 'format-ulist.png',
 268+ offset: [2, -1366],
 269+ action: {
 270+ type: 'encapsulate',
 271+ options: {
 272+ pre: "* ",
 273+ periMsg: 'wikieditor-toolbar-tool-ulist-example',
 274+ post: "",
 275+ ownline: true
 276+ }
 277+ }
 278+ },
 279+ 'olist': {
 280+ labelMsg: 'wikieditor-toolbar-tool-olist',
 281+ type: 'button',
 282+ icon: 'format-olist.png',
 283+ offset: [2, -1078],
 284+ action: {
 285+ type: 'encapsulate',
 286+ options: {
 287+ pre: "# ",
 288+ periMsg: 'wikieditor-toolbar-tool-olist-example',
 289+ post: "",
 290+ ownline: true
 291+ }
 292+ }
 293+ },
 294+ 'indent': {
 295+ labelMsg: 'wikieditor-toolbar-tool-indent',
 296+ type: 'button',
 297+ icon: 'format-indent.png',
 298+ offset: [2, -646],
 299+ action: {
 300+ type: 'encapsulate',
 301+ options: {
 302+ pre: ":",
 303+ periMsg: 'wikieditor-toolbar-tool-indent-example',
 304+ post: "",
 305+ ownline: true,
 306+ splitlines: true
 307+ }
 308+ }
 309+ },
 310+ 'nowiki': {
 311+ labelMsg: 'wikieditor-toolbar-tool-nowiki',
 312+ type: 'button',
 313+ icon: 'insert-nowiki.png',
 314+ offset: [-70, -70],
 315+ action: {
 316+ type: 'encapsulate',
 317+ options: {
 318+ pre: "<nowiki>",
 319+ periMsg: 'wikieditor-toolbar-tool-nowiki-example',
 320+ post: "</nowiki>"
 321+ }
 322+ }
 323+ },
 324+ 'newline': {
 325+ labelMsg: 'wikieditor-toolbar-tool-newline',
 326+ type: 'button',
 327+ icon: 'insert-newline.png',
 328+ offset: [2, -1726],
 329+ action: {
 330+ type: 'encapsulate',
 331+ options: {
 332+ pre: "<br />\n"
 333+ }
 334+ }
 335+ }
 336+ }
 337+ },
 338+ 'size': {
 339+ tools: {
 340+ 'big': {
 341+ labelMsg: 'wikieditor-toolbar-tool-big',
 342+ type: 'button',
 343+ icon: 'format-big.png',
 344+ offset: [2, 2],
 345+ action: {
 346+ type: 'encapsulate',
 347+ options: {
 348+ pre: "<big>",
 349+ periMsg: 'wikieditor-toolbar-tool-big-example',
 350+ post: "</big>"
 351+ }
 352+ }
 353+ },
 354+ 'small': {
 355+ labelMsg: 'wikieditor-toolbar-tool-small',
 356+ type: 'button',
 357+ icon: 'format-small.png',
 358+ offset: [2, -1150],
 359+ action: {
 360+ type: 'encapsulate',
 361+ options: {
 362+ pre: "<small>",
 363+ periMsg: 'wikieditor-toolbar-tool-small-example',
 364+ post: "</small>"
 365+ }
 366+ }
 367+ },
 368+ 'superscript': {
 369+ labelMsg: 'wikieditor-toolbar-tool-superscript',
 370+ type: 'button',
 371+ icon: 'format-superscript.png',
 372+ offset: [2, -1294],
 373+ action: {
 374+ type: 'encapsulate',
 375+ options: {
 376+ pre: "<sup>",
 377+ periMsg: 'wikieditor-toolbar-tool-superscript-example',
 378+ post: "</sup>"
 379+ }
 380+ }
 381+ },
 382+ 'subscript': {
 383+ labelMsg: 'wikieditor-toolbar-tool-subscript',
 384+ type: 'button',
 385+ icon: 'format-subscript.png',
 386+ offset: [2, -1222],
 387+ action: {
 388+ type: 'encapsulate',
 389+ options: {
 390+ pre: "<sub>",
 391+ periMsg: 'wikieditor-toolbar-tool-subscript-example',
 392+ post: "</sub>"
 393+ }
 394+ }
 395+ }
 396+ }
 397+ },
 398+ 'insert': {
 399+ labelMsg: 'wikieditor-toolbar-group-insert',
 400+ tools: {
 401+ 'gallery': {
 402+ labelMsg: 'wikieditor-toolbar-tool-gallery',
 403+ type: 'button',
 404+ icon: 'insert-gallery.png',
 405+ offset: [2, -1510],
 406+ action: {
 407+ type: 'encapsulate',
 408+ options: {
 409+ pre: "<gallery>\n",
 410+ periMsg: 'wikieditor-toolbar-tool-gallery-example',
 411+ post: "\n</gallery>",
 412+ ownline: true
 413+ }
 414+ }
 415+ },
 416+ 'tableCGD': {
 417+ labelMsg: 'wikieditor-toolbar-tool-table',
 418+ type: 'button',
 419+ icon: 'insert-table.png',
 420+ offset: [2, -1942],
 421+ filters: [ '#wpTextbox1.toolbar-dialogs' ],
 422+ action: {
 423+ type: 'dialog',
 424+ module: 'insert-table'
 425+ }
 426+ },
 427+ 'table': {
 428+ labelMsg: 'wikieditor-toolbar-tool-table',
 429+ type: 'button',
 430+ icon: 'insert-table.png',
 431+ offset: [2, -1942],
 432+ filters: [ '#wpTextbox1:not(.toolbar-dialogs)' ],
 433+ action: {
 434+ type: 'encapsulate',
 435+ options: {
 436+ pre: "{| class=\"wikitable\" border=\"1\"\n|",
 437+ periMsg: 'wikieditor-toolbar-tool-table-example-old',
 438+ post: "\n|}",
 439+ ownline: true
 440+ }
 441+ }
 442+ },
 443+ 'redirect': {
 444+ labelMsg: 'wikieditor-toolbar-tool-redirect',
 445+ type: 'button',
 446+ icon: 'insert-redirect.png',
 447+ offset: [-70, -142],
 448+ action: {
 449+ type: 'encapsulate',
 450+ options: {
 451+ pre: "#REDIRECT [[",
 452+ periMsg: 'wikieditor-toolbar-tool-redirect-example',
 453+ post: "]]",
 454+ ownline: true
 455+ }
 456+ }
 457+ }
 458+ }
 459+ },
 460+ 'search': {
 461+ tools: {
 462+ 'replace': {
 463+ labelMsg: 'wikieditor-toolbar-tool-replace',
 464+ type: 'button',
 465+ icon: 'search-replace.png',
 466+ offset: [-70, -214],
 467+ filters: [ '#wpTextbox1.toolbar-dialogs' ],
 468+ action: {
 469+ type: 'dialog',
 470+ module: 'search-and-replace'
 471+ }
 472+ }
 473+ }
 474+ }
 475+ }
 476+ },
 477+ 'characters': {
 478+ labelMsg: 'wikieditor-toolbar-section-characters',
 479+ type: 'booklet',
 480+ deferLoad: true,
 481+ pages: {
 482+ 'latin': {
 483+ 'labelMsg': 'wikieditor-toolbar-characters-page-latin',
 484+ 'layout': 'characters',
 485+ 'characters': [
 486+ "\u00c1", "\u00e1", "\u00c0", "\u00e0", "\u00c2", "\u00e2", "\u00c4", "\u00e4", "\u00c3", "\u00e3",
 487+ "\u01cd", "\u01ce", "\u0100", "\u0101", "\u0102", "\u0103", "\u0104", "\u0105", "\u00c5", "\u00e5",
 488+ "\u0106", "\u0107", "\u0108", "\u0109", "\u00c7", "\u00e7", "\u010c", "\u010d", "\u010a", "\u010b",
 489+ "\u0110", "\u0111", "\u010e", "\u010f", "\u00c9", "\u00e9", "\u00c8", "\u00e8", "\u00ca", "\u00ea",
 490+ "\u00cb", "\u00eb", "\u011a", "\u011b", "\u0112", "\u0113", "\u0114", "\u0115", "\u0116", "\u0117",
 491+ "\u0118", "\u0119", "\u011c", "\u011d", "\u0122", "\u0123", "\u011e", "\u011f", "\u0120", "\u0121",
 492+ "\u0124", "\u0125", "\u0126", "\u0127", "\u00cd", "\u00ed", "\u00cc", "\u00ec", "\u00ce", "\u00ee",
 493+ "\u00cf", "\u00ef", "\u0128", "\u0129", "\u01cf", "\u01d0", "\u012a", "\u012b", "\u012c", "\u012d",
 494+ "\u0130", "\u0131", "\u012e", "\u012f", "\u0134", "\u0135", "\u0136", "\u0137", "\u0139", "\u013a",
 495+ "\u013b", "\u013c", "\u013d", "\u013e", "\u0141", "\u0142", "\u013f", "\u0140", "\u0143", "\u0144",
 496+ "\u00d1", "\u00f1", "\u0145", "\u0146", "\u0147", "\u0148", "\u00d3", "\u00f3", "\u00d2", "\u00f2",
 497+ "\u00d4", "\u00f4", "\u00d6", "\u00f6", "\u00d5", "\u00f5", "\u01d1", "\u01d2", "\u014c", "\u014d",
 498+ "\u014e", "\u014f", "\u01ea", "\u01eb", "\u0150", "\u0151", "\u0154", "\u0155", "\u0156", "\u0157",
 499+ "\u0158", "\u0159", "\u015a", "\u015b", "\u015c", "\u015d", "\u015e", "\u015f", "\u0160", "\u0161",
 500+ "\u0162", "\u0163", "\u0164", "\u0165", "\u00da", "\u00fa", "\u00d9", "\u00f9", "\u00db", "\u00fb",
 501+ "\u00dc", "\u00fc", "\u0168", "\u0169", "\u016e", "\u016f", "\u01d3", "\u01d4", "\u016a", "\u016b",
 502+ "\u01d6", "\u01d8", "\u01da", "\u01dc", "\u016c", "\u016d", "\u0172", "\u0173", "\u0170", "\u0171",
 503+ "\u0174", "\u0175", "\u00dd", "\u00fd", "\u0176", "\u0177", "\u0178", "\u00ff", "\u0232", "\u0233",
 504+ "\u0179", "\u017a", "\u017d", "\u017e", "\u017b", "\u017c", "\u00c6", "\u00e6", "\u01e2", "\u01e3",
 505+ "\u00d8", "\u00f8", "\u0152", "\u0153", "\u00df", "\u00f0", "\u00de", "\u00fe", "\u018f", "\u0259"
 506+ ]
 507+ },
 508+ 'latinextended': {
 509+ 'labelMsg': 'wikieditor-toolbar-characters-page-latinextended',
 510+ 'layout': 'characters',
 511+ 'characters': [
 512+ "\u1e00", "\u1e01", "\u1e9a", "\u1ea0", "\u1ea1", "\u1ea2", "\u1ea3", "\u1ea4", "\u1ea5", "\u1ea6",
 513+ "\u1ea7", "\u1ea8", "\u1ea9", "\u1eaa", "\u1eab", "\u1eac", "\u1ead", "\u1eae", "\u1eaf", "\u1eb0",
 514+ "\u1eb1", "\u1eb2", "\u1eb3", "\u1eb4", "\u1eb5", "\u1eb6", "\u1eb7", "\u1e02", "\u1e03", "\u1e04",
 515+ "\u1e05", "\u1e06", "\u1e07", "\u1e08", "\u1e09", "\u1e0a", "\u1e0b", "\u1e0c", "\u1e0d", "\u1e0e",
 516+ "\u1e0f", "\u1e10", "\u1e11", "\u1e12", "\u1e13", "\u1e14", "\u1e15", "\u1e16", "\u1e17", "\u1e18",
 517+ "\u1e19", "\u1e1a", "\u1e1b", "\u1e1c", "\u1e1d", "\u1eb8", "\u1eb9", "\u1eba", "\u1ebb", "\u1ebc",
 518+ "\u1ebd", "\u1ebe", "\u1ebf", "\u1ec0", "\u1ec1", "\u1ec2", "\u1ec3", "\u1ec4", "\u1ec5", "\u1ec6",
 519+ "\u1ec7", "\u1e1e", "\u1e1f", "\u1e20", "\u1e21", "\u1e22", "\u1e23", "\u1e24", "\u1e25", "\u1e26",
 520+ "\u1e27", "\u1e28", "\u1e29", "\u1e2a", "\u1e2b", "\u1e96", "\u1e2c", "\u1e2d", "\u1e2e", "\u1e2f",
 521+ "\u1ec8", "\u1ec9", "\u1eca", "\u1ecb", "\u1e30", "\u1e31", "\u1e32", "\u1e33", "\u1e34", "\u1e35",
 522+ "\u1e36", "\u1e37", "\u1e38", "\u1e39", "\u1e3a", "\u1e3b", "\u1e3c", "\u1e3d", "\u1efa", "\u1efb",
 523+ "\u1e3e", "\u1e3f", "\u1e40", "\u1e41", "\u1e42", "\u1e43", "\u1e44", "\u1e45", "\u1e46", "\u1e47",
 524+ "\u1e48", "\u1e49", "\u1e4a", "\u1e4b", "\u1e4c", "\u1e4d", "\u1e4e", "\u1e4f", "\u1e50", "\u1e51",
 525+ "\u1e52", "\u1e53", "\u1ecc", "\u1ecd", "\u1ece", "\u1ecf", "\u1ed0", "\u1ed1", "\u1ed2", "\u1ed3",
 526+ "\u1ed4", "\u1ed5", "\u1ed6", "\u1ed7", "\u1ed8", "\u1ed9", "\u1eda", "\u1edb", "\u1edc", "\u1edd",
 527+ "\u1ede", "\u1edf", "\u1ee0", "\u1ee1", "\u1ee2", "\u1ee3", "\u1e54", "\u1e55", "\u1e56", "\u1e57",
 528+ "\u1e58", "\u1e59", "\u1e5a", "\u1e5b", "\u1e5c", "\u1e5d", "\u1e5e", "\u1e5f", "\u1e60", "\u1e61",
 529+ "\u1e9b", "\u1e62", "\u1e63", "\u1e64", "\u1e65", "\u1e66", "\u1e67", "\u1e68", "\u1e69", "\u1e9c",
 530+ "\u1e9d", "\u1e6a", "\u1e6b", "\u1e6c", "\u1e6d", "\u1e6e", "\u1e6f", "\u1e70", "\u1e71", "\u1e97",
 531+ "\u1e72", "\u1e73", "\u1e74", "\u1e75", "\u1e76", "\u1e77", "\u1e78", "\u1e79", "\u1e7a", "\u1e7b",
 532+ "\u1ee4", "\u1ee5", "\u1ee6", "\u1ee7", "\u1ee8", "\u1ee9", "\u1eea", "\u1eeb", "\u1eec", "\u1eed",
 533+ "\u1eee", "\u1eef", "\u1ef0", "\u1ef1", "\u1e7c", "\u1e7d", "\u1e7e", "\u1e7f", "\u1efc", "\u1efd",
 534+ "\u1e80", "\u1e81", "\u1e82", "\u1e83", "\u1e84", "\u1e85", "\u1e86", "\u1e87", "\u1e88", "\u1e89",
 535+ "\u1e98", "\u1e8a", "\u1e8b", "\u1e8c", "\u1e8d", "\u1e8e", "\u1e8f", "\u1e99", "\u1ef2", "\u1ef3",
 536+ "\u1ef4", "\u1ef5", "\u1ef6", "\u1ef7", "\u1ef8", "\u1ef9", "\u1efe", "\u1eff", "\u1e90", "\u1e91",
 537+ "\u1e92", "\u1e93", "\u1e94", "\u1e95", "\u1e9e", "\u1e9f"
 538+ ]
 539+ },
 540+ 'ipa': {
 541+ labelMsg: 'wikieditor-toolbar-characters-page-ipa',
 542+ layout: 'characters',
 543+ characters: [
 544+ "p", "t\u032a", "t", "\u0288", "c", "k", "q", "\u02a1", "\u0294", "b","d\u032a", "d", "\u0256",
 545+ "\u025f", "\u0261", "\u0262", "\u0253", "\u0257", "\u0284", "\u0260", "\u029b", "t\u0361s",
 546+ "t\u0361\u0283", "t\u0361\u0255", "d\u0361z", "d\u0361\u0292", "d\u0361\u0291", "\u0278", "f",
 547+ "\u03b8", "s", "\u0283", "\u0285", "\u0286", "\u0282", "\u0255", "\u00e7", "\u0267", "x", "\u03c7",
 548+ "\u0127", "\u029c", "h", "\u03b2", "v", "\u028d", "\u00f0", "z", "\u0292", "\u0293", "\u0290",
 549+ "\u0291", "\u029d", "\u0263", "\u0281", "\u0295", "\u0296", "\u02a2", "\u0266", "\u026c", "\u026e",
 550+ "m", "m\u0329", "\u0271", "\u0271\u0329", "\u0271\u030d", "n\u032a", "n\u032a\u030d", "n",
 551+ "n\u0329", "\u0273", "\u0273\u0329", "\u0272", "\u0272\u0329", "\u014b", "\u014b\u030d",
 552+ "\u014b\u0329", "\u0274", "\u0274\u0329", "\u0299", "\u0299\u0329", "r", "r\u0329", "\u0280",
 553+ "\u0280\u0329", "\u027e", "\u027d", "\u027f", "\u027a", "l\u032a", "l\u032a\u0329", "l", "l\u0329",
 554+ "\u026b", "\u026b\u0329", "\u026d", "\u026d\u0329", "\u028e", "\u028e\u0329", "\u029f",
 555+ "\u029f\u0329", "w", "\u0265", "\u028b", "\u0279", "\u027b", "j", "\u0270", "\u0298", "\u01c2",
 556+ "\u01c0", "!", "\u01c1", "\u02b0", "\u02b1", "\u02b7", "\u02b8", "\u02b2", "\u02b3", "\u207f",
 557+ "\u02e1", "\u02b4", "\u02b5", "\u02e2", "\u02e3", "\u02e0", "\u02b6", "\u02e4", "\u02c1", "\u02c0",
 558+ "\u02bc", "i", "i\u032f", "\u0129", "y", "y\u032f", "\u1ef9", "\u026a", "\u026a\u032f",
 559+ "\u026a\u0303", "\u028f", "\u028f\u032f", "\u028f\u0303", "\u0268", "\u0268\u032f", "\u0268\u0303",
 560+ "\u0289", "\u0289\u032f", "\u0289\u0303", "\u026f", "\u026f\u032f", "\u026f\u0303", "u", "u\u032f",
 561+ "\u0169", "\u028a", "\u028a\u032f", "\u028a\u0303", "e", "e\u032f", "\u1ebd", "\u00f8",
 562+ "\u00f8\u032f", "\u00f8\u0303", "\u0258", "\u0258\u032f", "\u0258\u0303", "\u0275", "\u0275\u032f",
 563+ "\u0275\u0303", "\u0264", "\u0264\u032f", "\u0264\u0303", "o", "o\u032f", "\u00f5", "\u025b",
 564+ "\u025b\u032f", "\u025b\u0303", "\u0153", "\u0153\u032f", "\u0153\u0303", "\u025c", "\u025c\u032f",
 565+ "\u025c\u0303", "\u0259", "\u0259\u032f", "\u0259\u0303", "\u025e", "\u025e\u032f", "\u025e\u0303",
 566+ "\u028c", "\u028c\u032f", "\u028c\u0303", "\u0254", "\u0254\u032f", "\u0254\u0303", "\u00e6",
 567+ "\u00e6\u032f", "\u00e6\u0303", "\u0276", "\u0276\u032f", "\u0276\u0303", "a", "a\u032f", "\u00e3",
 568+ "\u0250", "\u0250\u032f", "\u0250\u0303", "\u0251", "\u0251\u032f", "\u0251\u0303", "\u0252",
 569+ "\u0252\u032f", "\u0252\u0303", "\u02c8", "\u02cc", "\u02d0", "\u02d1", "\u02d8", ".", "\u203f",
 570+ "|", "\u2016"
 571+ ]
 572+ },
 573+ 'symbols': {
 574+ 'labelMsg': 'wikieditor-toolbar-characters-page-symbols',
 575+ 'layout': 'characters',
 576+ 'characters': [
 577+ "~", "|", "\u00a1", "\u00bf", "\u2020", "\u2021", "\u2194", "\u2191", "\u2193", "\u2022", "\u00b6",
 578+ "#", "\u00bd", "\u2153", "\u2154", "\u00bc", "\u00be", "\u215b", "\u215c", "\u215d", "\u215e",
 579+ "\u221e", "\u2018", "\u201e", "\u201c", "\u2019", "\u201d",
 580+ {
 581+ 'label': "\u00ab\u00bb",
 582+ 'action': {
 583+ 'type': 'encapsulate', 'options': { 'pre': "\u00ab", 'post': "\u00bb" }
 584+ }
 585+ },
 586+ "\u00a4", "\u20b3", "\u0e3f", "\u20b5", "\u00a2", "\u20a1", "\u20a2", "$", "\u20ab", "\u20af",
 587+ "\u20ac", "\u20a0", "\u20a3", "\u0192", "\u20b4", "\u20ad", "\u20a4", "\u2133", "\u20a5", "\u20a6",
 588+ "\u2116", "\u20a7", "\u20b0", "\u00a3", "\u17db", "\u20a8", "\u20aa", "\u09f3", "\u20ae", "\u20a9",
 589+ "\u00a5", "\u2660", "\u2663", "\u2665", "\u2666", "m\u00b2", "m\u00b3", "\u2013", "\u2014",
 590+ "\u2026", "\u2018", "\u201c", "\u2019", "\u201d", "\u00b0", "\u2033", "\u2032", "\u2248", "\u2260",
 591+ "\u2264", "\u2265", "\u00b1", "\u2212", "\u00d7", "\u00f7", "\u2190", "\u2192", "\u00b7", "\u00a7"
 592+ ]
 593+ },
 594+ 'greek': {
 595+ 'labelMsg': 'wikieditor-toolbar-characters-page-greek',
 596+ 'layout': 'characters',
 597+ 'language': 'hl',
 598+ 'characters': [
 599+ "\u0391", "\u0386", "\u03b1", "\u03ac", "\u0392", "\u03b2", "\u0393", "\u03b3", "\u0394", "\u03b4",
 600+ "\u0395", "\u0388", "\u03b5", "\u03ad", "\u0396", "\u03b6", "\u0397", "\u0389", "\u03b7", "\u03ae",
 601+ "\u0398", "\u03b8", "\u0399", "\u038a", "\u03b9", "\u03af", "\u039a", "\u03ba", "\u039b", "\u03bb",
 602+ "\u039c", "\u03bc", "\u039d", "\u03bd", "\u039e", "\u03be", "\u039f", "\u038c", "\u03bf", "\u03cc",
 603+ "\u03a0", "\u03c0", "\u03a1", "\u03c1", "\u03a3", "\u03c3", "\u03c2", "\u03a4", "\u03c4", "\u03a5",
 604+ "\u038e", "\u03c5", "\u03cd", "\u03a6", "\u03c6", "\u03a7", "\u03c7", "\u03a8", "\u03c8", "\u03a9",
 605+ "\u038f", "\u03c9", "\u03ce"
 606+ ]
 607+ },
 608+ 'cyrillic': {
 609+ 'labelMsg': 'wikieditor-toolbar-characters-page-cyrillic',
 610+ 'layout': 'characters',
 611+ 'characters': [
 612+ "\u0410", "\u0430", "\u04d8", "\u04d9", "\u0411", "\u0431", "\u0412", "\u0432", "\u0413", "\u0433",
 613+ "\u0490", "\u0491", "\u0403", "\u0453", "\u0492", "\u0493", "\u0414", "\u0434", "\u0402", "\u0452",
 614+ "\u0415", "\u0435", "\u0404", "\u0454", "\u0401", "\u0451", "\u0416", "\u0436", "\u0417", "\u0437",
 615+ "\u0405", "\u0455", "\u0418", "\u0438", "\u0406", "\u0456", "\u0407", "\u0457", "\u0130", "\u0419",
 616+ "\u0439", "\u04e2", "\u04e3", "\u0408", "\u0458", "\u041a", "\u043a", "\u040c", "\u045c", "\u049a",
 617+ "\u049b", "\u041b", "\u043b", "\u0409", "\u0459", "\u041c", "\u043c", "\u041d", "\u043d", "\u040a",
 618+ "\u045a", "\u04a2", "\u04a3", "\u041e", "\u043e", "\u04e8", "\u04e9", "\u041f", "\u043f", "\u0420",
 619+ "\u0440", "\u0421", "\u0441", "\u0422", "\u0442", "\u040b", "\u045b", "\u0423", "\u0443", "\u040e",
 620+ "\u045e", "\u04ee", "\u04ef", "\u04b0", "\u04b1", "\u04ae", "\u04af", "\u0424", "\u0444", "\u0425",
 621+ "\u0445", "\u04b2", "\u04b3", "\u04ba", "\u04bb", "\u0426", "\u0446", "\u0427", "\u0447", "\u04b6",
 622+ "\u04b7", "\u040f", "\u045f", "\u0428", "\u0448", "\u0429", "\u0449", "\u042a", "\u044a", "\u042b",
 623+ "\u044b", "\u042c", "\u044c", "\u042d", "\u044d", "\u042e", "\u044e", "\u042f", "\u044f"
 624+ ]
 625+ },
 626+ 'arabic': {
 627+ 'labelMsg': 'wikieditor-toolbar-characters-page-arabic',
 628+ 'layout': 'characters',
 629+ 'language': 'ar',
 630+ 'direction': 'rtl',
 631+ 'characters': [
 632+ "\u061b", "\u061f", "\u0621", "\u0622", "\u0623", "\u0624", "\u0625", "\u0626", "\u0627", "\u0628",
 633+ "\u0629", "\u062a", "\u062b", "\u062c", "\u062d", "\u062e", "\u062f", "\u0630", "\u0631", "\u0632",
 634+ "\u0633", "\u0634", "\u0635", "\u0636", "\u0637", "\u0638", "\u0639", "\u063a", "\u0641", "\u0642",
 635+ "\u0643", "\u0644", "\u0645", "\u0646", "\u0647", "\u0648", "\u0649", "\u064a", "\u060c", "\u067e",
 636+ "\u0686", "\u0698", "\u06af", "\u06ad"
 637+ ]
 638+ },
 639+ 'hebrew': {
 640+ 'labelMsg': 'wikieditor-toolbar-characters-page-hebrew',
 641+ 'layout': 'characters',
 642+ 'direction': 'rtl',
 643+ 'characters': [
 644+ "\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", "\u05d6", "\u05d7", "\u05d8", "\u05d9",
 645+ "\u05db", "\u05da", "\u05dc", "\u05de", "\u05dd", "\u05e0", "\u05df", "\u05e1", "\u05e2", "\u05e4",
 646+ "\u05e3", "\u05e6", "\u05e5", "\u05e7", "\u05e8", "\u05e9", "\u05ea", "\u05f3", "\u05f4", "\u05f0",
 647+ "\u05f1", "\u05f2", "\u05d0", "\u05d3", "\u05d4", "\u05d5", "\u05d6", "\u05d7", "\u05d8", "\u05d9",
 648+ "\u05da", "\u05db", "\u05dc", "\u05dd", "\u05de", "\u05df", "\u05e0", "\u05e1", "\u05e2", "\u05e3",
 649+ "\u05e4", "\u05be", "\u05f3", "\u05f4",
 650+ [ "\u05b0\u25cc", "\u05b0" ], [ "\u05b1\u25cc", "\u05b1" ], [ "\u05b2\u25cc", "\u05b2" ],
 651+ [ "\u05b3\u25cc", "\u05b3" ], [ "\u05b4\u25cc", "\u05b4" ], [ "\u05b5\u25cc", "\u05b5" ],
 652+ [ "\u05b6\u25cc", "\u05b6" ], [ "\u05b7\u25cc", "\u05b7" ], [ "\u05b8\u25cc", "\u05b8" ],
 653+ [ "\u05b9\u25cc", "\u05b9" ], [ "\u05bb\u25cc", "\u05bb" ], [ "\u05bc\u25cc", "\u05bc" ],
 654+ [ "\u05c1\u25cc", "\u05c1" ], [ "\u05c2\u25cc", "\u05c2" ], [ "\u05c7\u25cc", "\u05c7" ],
 655+ [ "\u0591\u25cc", "\u0591" ], [ "\u0592\u25cc", "\u0592" ], [ "\u0593\u25cc", "\u0593" ],
 656+ [ "\u0594\u25cc", "\u0594" ], [ "\u0595\u25cc", "\u0595" ], [ "\u0596\u25cc", "\u0596" ],
 657+ [ "\u0597\u25cc", "\u0597" ], [ "\u0598\u25cc", "\u0598" ], [ "\u0599\u25cc", "\u0599" ],
 658+ [ "\u059a\u25cc", "\u059a" ], [ "\u059b\u25cc", "\u059b" ], [ "\u059c\u25cc", "\u059c" ],
 659+ [ "\u059d\u25cc", "\u059d" ], [ "\u059e\u25cc", "\u059e" ], [ "\u059f\u25cc", "\u059f" ],
 660+ [ "\u05a0\u25cc", "\u05a0" ], [ "\u05a1\u25cc", "\u05a1" ], [ "\u05a2\u25cc", "\u05a2" ],
 661+ [ "\u05a3\u25cc", "\u05a3" ], [ "\u05a4\u25cc", "\u05a4" ], [ "\u05a5\u25cc", "\u05a5" ],
 662+ [ "\u05a6\u25cc", "\u05a6" ], [ "\u05a7\u25cc", "\u05a7" ], [ "\u05a8\u25cc", "\u05a8" ],
 663+ [ "\u05a9\u25cc", "\u05a9" ], [ "\u05aa\u25cc", "\u05aa" ], [ "\u05ab\u25cc", "\u05ab" ],
 664+ [ "\u05ac\u25cc", "\u05ac" ], [ "\u05ad\u25cc", "\u05ad" ], [ "\u05ae\u25cc", "\u05ae" ],
 665+ [ "\u05af\u25cc", "\u05af" ], [ "\u05bf\u25cc", "\u05bf" ], [ "\u05c0\u25cc", "\u05c0" ],
 666+ [ "\u05c3\u25cc", "\u05c3" ]
 667+ ]
 668+ },
 669+ 'bangla': {
 670+ 'labelMsg': 'wikieditor-toolbar-characters-page-bangla',
 671+ 'language': 'bn',
 672+ 'layout': 'characters',
 673+ 'characters': [
 674+ "\u0985", "\u0986", "\u0987", "\u0988", "\u0989", "\u098a", "\u098b", "\u098f", "\u0990", "\u0993",
 675+ "\u0994", "\u09be", "\u09bf", "\u09c0", "\u09c1", "\u09c2", "\u09c3", "\u09c7", "\u09c8", "\u09cb",
 676+ "\u09cc", "\u0995", "\u0996", "\u0997", "\u0998", "\u0999", "\u099a", "\u099b", "\u099c", "\u099d",
 677+ "\u099e", "\u099f", "\u09a0", "\u09a1", "\u09a2", "\u09a3", "\u09a4", "\u09a5", "\u09a6", "\u09a7",
 678+ "\u09a8", "\u09aa", "\u09ab", "\u09ac", "\u09ad", "\u09ae", "\u09af", "\u09b0", "\u09b2", "\u09b6",
 679+ "\u09b7", "\u09b8", "\u09b9", "\u09a1\u09bc", "\u09a2\u09bc", "\u09af\u09bc", "\u09ce", "\u0982",
 680+ "\u0983", "\u0981", "\u09cd", "\u09e7", "\u09e8", "\u09e9", "\u09ea", "\u09eb", "\u09ec", "\u09ed",
 681+ "\u09ee", "\u09ef", "\u09e6"
 682+ ]
 683+ },
 684+ 'telugu': {
 685+ 'labelMsg': 'wikieditor-toolbar-characters-page-telugu',
 686+ 'language': 'te',
 687+ 'layout': 'characters',
 688+ 'characters': [
 689+ "\u0c01", "\u0c02", "\u0c03", "\u0c05", "\u0c06", "\u0c07", "\u0c08", "\u0c09", "\u0c0a", "\u0c0b",
 690+ "\u0c60", "\u0c0c", "\u0c61", "\u0c0e", "\u0c0f", "\u0c10", "\u0c12", "\u0c13", "\u0c14", "\u0c15",
 691+ "\u0c16", "\u0c17", "\u0c18", "\u0c19", "\u0c1a", "\u0c1b", "\u0c1c", "\u0c1d", "\u0c1e", "\u0c1f",
 692+ "\u0c20", "\u0c21", "\u0c22", "\u0c23", "\u0c24", "\u0c25", "\u0c26", "\u0c27", "\u0c28", "\u0c2a",
 693+ "\u0c2b", "\u0c2c", "\u0c2d", "\u0c2e", "\u0c2f", "\u0c30", "\u0c31", "\u0c32", "\u0c33", "\u0c35",
 694+ "\u0c36", "\u0c37", "\u0c38", "\u0c39", "\u0c3e", "\u0c3f", "\u0c40", "\u0c41", "\u0c42", "\u0c43",
 695+ "\u0c44", "\u0c46", "\u0c47", "\u0c48", "\u0c4a", "\u0c4b", "\u0c4c", "\u0c4d", "\u0c62", "\u0c63",
 696+ "\u0c58", "\u0c59", "\u0c66", "\u0c67", "\u0c68", "\u0c69", "\u0c6a", "\u0c6b", "\u0c6c", "\u0c6d",
 697+ "\u0c6e", "\u0c6f", "\u0c3d", "\u0c78", "\u0c79", "\u0c7a", "\u0c7b", "\u0c7c", "\u0c7d", "\u0c7e",
 698+ "\u0c7f"
 699+ ]
 700+ },
 701+ 'sinhala': {
 702+ 'labelMsg': 'wikieditor-toolbar-characters-page-sinhala',
 703+ 'language': 'si',
 704+ 'layout': 'characters',
 705+ 'characters': [
 706+ "\u0d85", "\u0d86", "\u0d87", "\u0d88", "\u0d89", "\u0d8a", "\u0d8b", "\u0d8c", "\u0d8d", "\u0d8e",
 707+ "\u0d8f", "\u0d90", "\u0d91", "\u0d92", "\u0d93", "\u0d94", "\u0d95", "\u0d96", "\u0d9a", "\u0d9b",
 708+ "\u0d9c", "\u0d9d", "\u0d9e", "\u0d9f", "\u0da0", "\u0da1", "\u0da2", "\u0da3", "\u0da4", "\u0da5",
 709+ "\u0da6", "\u0da7", "\u0da8", "\u0da9", "\u0daa", "\u0dab", "\u0dac", "\u0dad", "\u0dae", "\u0daf",
 710+ "\u0db0", "\u0db1", "\u0db3", "\u0db4", "\u0db5", "\u0db6", "\u0db7", "\u0db8", "\u0db9", "\u0dba",
 711+ "\u0dbb", "\u0dbd", "\u0dc0", "\u0dc1", "\u0dc2", "\u0dc3", "\u0dc4", "\u0dc5", "\u0dc6",
 712+ [ "\u25cc\u0dcf", "\u0dcf" ], [ "\u25cc\u0dd0", "\u0dd0" ], [ "\u25cc\u0dd1", "\u0dd1" ],
 713+ [ "\u25cc\u0dd2", "\u0dd2" ], [ "\u25cc\u0dd3", "\u0dd3" ], [ "\u25cc\u0dd4", "\u0dd4" ],
 714+ [ "\u25cc\u0dd6", "\u0dd6" ], [ "\u25cc\u0dd8", "\u0dd8" ], [ "\u25cc\u0df2", "\u0df2" ],
 715+ [ "\u25cc\u0ddf", "\u0ddf" ], [ "\u25cc\u0df3", "\u0df3" ], [ "\u25cc\u0dd9", "\u0dd9" ],
 716+ [ "\u25cc\u0dda", "\u0dda" ], [ "\u25cc\u0ddc", "\u0ddc" ], [ "\u25cc\u0ddd", "\u0ddd" ],
 717+ [ "\u25cc\u0dde", "\u0dde" ], [ "\u25cc\u0dca", "\u0dca" ]
 718+ ]
 719+ },
 720+ 'gujarati': {
 721+ 'labelMsg': 'wikieditor-toolbar-characters-page-gujarati',
 722+ 'language': 'gu',
 723+ 'layout': 'characters',
 724+ 'characters': [
 725+ "\u0ad0", "\u0a85", "\u0a86", "\u0a87", "\u0a88", "\u0a89", "\u0a8a", "\u0a8b", "\u0ae0", "\u0a8c",
 726+ "\u0ae1", "\u0a8d", "\u0a8f", "\u0a90", "\u0a91", "\u0a93", "\u0a94", "\u0a95", "\u0a96", "\u0a97",
 727+ "\u0a98", "\u0a99", "\u0a9a", "\u0a9b", "\u0a9c", "\u0a9d", "\u0a9e", "\u0a9f", "\u0aa0", "\u0aa1",
 728+ "\u0aa2", "\u0aa3", "\u0aa4", "\u0aa5", "\u0aa6", "\u0aa7", "\u0aa8", "\u0aaa", "\u0aab", "\u0aac",
 729+ "\u0aad", "\u0aae", "\u0aaf", "\u0ab0", "\u0ab2", "\u0ab5", "\u0ab6", "\u0ab7", "\u0ab8", "\u0ab9",
 730+ "\u0ab3", "\u0abd", [ "\u25cc\u0abe", "\u0abe" ], [ "\u25cc\u0abf", "\u0abf" ],
 731+ [ "\u25cc\u0ac0", "\u0ac0" ], [ "\u25cc\u0ac1", "\u0ac1" ], [ "\u25cc\u0ac2", "\u0ac2" ],
 732+ [ "\u25cc\u0ac3", "\u0ac3" ], [ "\u25cc\u0ac4", "\u0ac4" ], [ "\u25cc\u0ae2", "\u0ae2" ],
 733+ [ "\u25cc\u0ae3", "\u0ae3" ], [ "\u25cc\u0ac5", "\u0ac5" ], [ "\u25cc\u0ac7", "\u0ac7" ],
 734+ [ "\u25cc\u0ac8", "\u0ac8" ], [ "\u25cc\u0ac9", "\u0ac9" ], [ "\u25cc\u0acb", "\u0acb" ],
 735+ [ "\u25cc\u0acc", "\u0acc" ], [ "\u25cc\u0acd", "\u0acd" ]
 736+ ]
 737+ }
 738+ }
 739+ },
 740+ 'help': {
 741+ labelMsg: 'wikieditor-toolbar-section-help',
 742+ type: 'booklet',
 743+ deferLoad: true,
 744+ pages: {
 745+ 'format': {
 746+ labelMsg: 'wikieditor-toolbar-help-page-format',
 747+ layout: 'table',
 748+ headings: [
 749+ { textMsg: 'wikieditor-toolbar-help-heading-description' },
 750+ { textMsg: 'wikieditor-toolbar-help-heading-syntax' },
 751+ { textMsg: 'wikieditor-toolbar-help-heading-result' }
 752+ ],
 753+ rows: [
 754+ {
 755+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-italic-description' },
 756+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-italic-syntax' },
 757+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-italic-result' }
 758+ },
 759+ {
 760+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-bold-description' },
 761+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-bold-syntax' },
 762+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-bold-result' }
 763+ },
 764+ {
 765+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-bolditalic-description' },
 766+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-bolditalic-syntax' },
 767+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-bolditalic-result' }
 768+ }
 769+ ]
 770+ },
 771+ 'link': {
 772+ labelMsg: 'wikieditor-toolbar-help-page-link',
 773+ layout: 'table',
 774+ headings: [
 775+ { textMsg: 'wikieditor-toolbar-help-heading-description' },
 776+ { textMsg: 'wikieditor-toolbar-help-heading-syntax' },
 777+ { textMsg: 'wikieditor-toolbar-help-heading-result' }
 778+ ],
 779+ rows: [
 780+ {
 781+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-ilink-description' },
 782+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-ilink-syntax' },
 783+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-ilink-result' }
 784+ },
 785+ {
 786+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-xlink-description' },
 787+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-xlink-syntax' },
 788+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-xlink-result' }
 789+ }
 790+ ]
 791+ },
 792+ 'heading': {
 793+ labelMsg: 'wikieditor-toolbar-help-page-heading',
 794+ layout: 'table',
 795+ headings: [
 796+ { textMsg: 'wikieditor-toolbar-help-heading-description' },
 797+ { textMsg: 'wikieditor-toolbar-help-heading-syntax' },
 798+ { textMsg: 'wikieditor-toolbar-help-heading-result' }
 799+ ],
 800+ rows: [
 801+ {
 802+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-heading1-description' },
 803+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-heading1-syntax' },
 804+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-heading1-result' }
 805+ },
 806+ {
 807+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-heading2-description' },
 808+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-heading2-syntax' },
 809+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-heading2-result' }
 810+ },
 811+ {
 812+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-heading3-description' },
 813+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-heading3-syntax' },
 814+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-heading3-result' }
 815+ },
 816+ {
 817+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-heading4-description' },
 818+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-heading4-syntax' },
 819+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-heading4-result' }
 820+ },
 821+ {
 822+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-heading5-description' },
 823+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-heading5-syntax' },
 824+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-heading5-result' }
 825+ }
 826+ ]
 827+ },
 828+ 'list': {
 829+ labelMsg: 'wikieditor-toolbar-help-page-list',
 830+ layout: 'table',
 831+ headings: [
 832+ { textMsg: 'wikieditor-toolbar-help-heading-description' },
 833+ { textMsg: 'wikieditor-toolbar-help-heading-syntax' },
 834+ { textMsg: 'wikieditor-toolbar-help-heading-result' }
 835+ ],
 836+ rows: [
 837+ {
 838+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-ulist-description' },
 839+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-ulist-syntax' },
 840+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-ulist-result' }
 841+ },
 842+ {
 843+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-olist-description' },
 844+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-olist-syntax' },
 845+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-olist-result' }
 846+ }
 847+ ]
 848+ },
 849+ 'file': {
 850+ labelMsg: 'wikieditor-toolbar-help-page-file',
 851+ layout: 'table',
 852+ headings: [
 853+ { textMsg: 'wikieditor-toolbar-help-heading-description' },
 854+ { textMsg: 'wikieditor-toolbar-help-heading-syntax' },
 855+ { textMsg: 'wikieditor-toolbar-help-heading-result' }
 856+ ],
 857+ rows: [
 858+ {
 859+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-file-description' },
 860+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-file-syntax' },
 861+ 'result': { htmlMsg: [ 'wikieditor-toolbar-help-content-file-result', stylepath ] }
 862+ }
 863+ ]
 864+ },
 865+ 'reference': {
 866+ labelMsg: 'wikieditor-toolbar-help-page-reference',
 867+ layout: 'table',
 868+ headings: [
 869+ { textMsg: 'wikieditor-toolbar-help-heading-description' },
 870+ { textMsg: 'wikieditor-toolbar-help-heading-syntax' },
 871+ { textMsg: 'wikieditor-toolbar-help-heading-result' }
 872+ ],
 873+ rows: [
 874+ {
 875+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-reference-description' },
 876+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-reference-syntax' },
 877+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-reference-result' }
 878+ },
 879+ {
 880+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-rereference-description' },
 881+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-rereference-syntax' },
 882+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-rereference-result' }
 883+ },
 884+ {
 885+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-showreferences-description' },
 886+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-showreferences-syntax' },
 887+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-showreferences-result' }
 888+ }
 889+ ]
 890+ },
 891+ 'discussion': {
 892+ labelMsg: 'wikieditor-toolbar-help-page-discussion',
 893+ layout: 'table',
 894+ headings: [
 895+ { textMsg: 'wikieditor-toolbar-help-heading-description' },
 896+ { textMsg: 'wikieditor-toolbar-help-heading-syntax' },
 897+ { textMsg: 'wikieditor-toolbar-help-heading-result' }
 898+ ],
 899+ rows: [
 900+ {
 901+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-signaturetimestamp-description' },
 902+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-signaturetimestamp-syntax' },
 903+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-signaturetimestamp-result' }
 904+ },
 905+ {
 906+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-signature-description' },
 907+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-signature-syntax' },
 908+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-signature-result' }
 909+ },
 910+ {
 911+ 'description': { htmlMsg: 'wikieditor-toolbar-help-content-indent-description' },
 912+ 'syntax': { htmlMsg: 'wikieditor-toolbar-help-content-indent-syntax' },
 913+ 'result': { htmlMsg: 'wikieditor-toolbar-help-content-indent-result' }
 914+ }
 915+ ]
 916+ }
 917+ }
 918+ }
 919+ },
 920+ 'dialogs': {
 921+ 'insert-link': {
 922+ filters: [ '#wpTextbox1.toolbar-dialogs' ],
 923+ titleMsg: 'wikieditor-toolbar-tool-link-title',
 924+ id: 'wikieditor-toolbar-link-dialog',
 925+ html: '\
 926+ <fieldset>\
 927+ <div class="wikieditor-toolbar-field-wrapper">\
 928+ <label for="wikieditor-toolbar-link-int-target" rel="wikieditor-toolbar-tool-link-int-target" id="wikieditor-toolbar-tool-link-int-target-label"></label>\
 929+ <div id="wikieditor-toolbar-link-int-target-status"></div>\
 930+ <input type="text" id="wikieditor-toolbar-link-int-target" />\
 931+ </div>\
 932+ <div class="wikieditor-toolbar-field-wrapper">\
 933+ <label for="wikieditor-toolbar-link-int-text" rel="wikieditor-toolbar-tool-link-int-text"></label>\
 934+ <input type="text" id="wikieditor-toolbar-link-int-text" />\
 935+ </div>\
 936+ <div class="wikieditor-toolbar-field-wrapper">\
 937+ <div class="wikieditor-toolbar-floated-field-wrapper">\
 938+ <input type="radio" id="wikieditor-toolbar-link-type-int" name="wikieditor-toolbar-link-type" selected />\
 939+ <label for="wikieditor-toolbar-link-type-int" rel="wikieditor-toolbar-tool-link-int"></label>\
 940+ </div>\
 941+ <div class="wikieditor-toolbar-floated-field-wrapper">\
 942+ <input type="radio" id="wikieditor-toolbar-link-type-ext" name="wikieditor-toolbar-link-type" />\
 943+ <label for="wikieditor-toolbar-link-type-ext" rel="wikieditor-toolbar-tool-link-ext"></label>\
 944+ </div>\
 945+ </div>\
 946+ </fieldset>',
 947+ init: function() {
 948+ function isExternalLink( s ) {
 949+ // The following things are considered to be external links:
 950+ // * Starts a URL protocol
 951+ // * Starts with www.
 952+ // All of these are potentially valid titles, and the latter two
 953+ // categories match about 6300 titles in enwiki's ns0. Out of 6.9M
 954+ // titles, that's 0.09%
 955+ if ( typeof arguments.callee.regex == 'undefined' ) {
 956+ // Cache the regex
 957+ arguments.callee.regex =
 958+ new RegExp( "^(" + wgUrlProtocols + "|www\\.)", 'i');
 959+ }
 960+ return s.match( arguments.callee.regex );
 961+ }
 962+ // Updates the status indicator above the target link
 963+ function updateWidget( status ) {
 964+ $j( '#wikieditor-toolbar-link-int-target-status' ).children().hide();
 965+ $j( '#wikieditor-toolbar-link-int-target' ).parent()
 966+ .removeClass( 'status-invalid status-external status-notexists status-exists status-loading' );
 967+ if ( status ) {
 968+ $j( '#wikieditor-toolbar-link-int-target-status-' + status ).show();
 969+ $j( '#wikieditor-toolbar-link-int-target' ).parent().addClass( 'status-' + status );
 970+ }
 971+ if ( status == 'invalid' ) {
 972+ $j( '.ui-dialog:visible .ui-dialog-buttonpane button:first' )
 973+ .attr( 'disabled', true )
 974+ .addClass( 'disabled' );
 975+ } else {
 976+ $j( '.ui-dialog:visible .ui-dialog-buttonpane button:first' )
 977+ .removeAttr('disabled')
 978+ .removeClass('disabled');
 979+ }
 980+ }
 981+ // Updates the UI to show if the page title being inputed by the user exists or not
 982+ // accepts parameter internal for bypassing external link detection
 983+ function updateExistence( internal ) {
 984+ // ensure the internal parameter is a boolean
 985+ if ( internal != true ) internal = false;
 986+ // Abort previous request
 987+ var request = $j( '#wikieditor-toolbar-link-int-target-status' ).data( 'request' );
 988+ if ( request ) {
 989+ request.abort();
 990+ }
 991+ var target = $j( '#wikieditor-toolbar-link-int-target' ).val();
 992+ var cache = $j( '#wikieditor-toolbar-link-int-target-status' ).data( 'existencecache' );
 993+ if ( cache[target] ) {
 994+ updateWidget( cache[target] );
 995+ return;
 996+ }
 997+ if ( target.replace( /^\s+$/,'' ) == '' ) {
 998+ // Hide the widget when the textbox is empty
 999+ updateWidget( false );
 1000+ return;
 1001+ }
 1002+ // If the forced internal paremter was not true, check if the target is an external link
 1003+ if ( !internal && isExternalLink( target ) ) {
 1004+ updateWidget( 'external' );
 1005+ return;
 1006+ }
 1007+ if ( target.indexOf( '|' ) != -1 ) {
 1008+ // Title contains | , which means it's invalid
 1009+ // but confuses the API. Show invalid and bypass API
 1010+ updateWidget( 'invalid' );
 1011+ return;
 1012+ }
 1013+ // Show loading spinner while waiting for the API to respond
 1014+ updateWidget( 'loading' );
 1015+ // Call the API to check page status, saving the request object so it can be aborted if necessary
 1016+ $j( '#wikieditor-toolbar-link-int-target-status' ).data(
 1017+ 'request',
 1018+ $j.ajax( {
 1019+ url: wgScriptPath + '/api.php',
 1020+ dataType: 'json',
 1021+ data: {
 1022+ 'action': 'query',
 1023+ 'indexpageids': '',
 1024+ 'titles': target,
 1025+ 'format': 'json'
 1026+ },
 1027+ success: function( data ) {
 1028+ if ( !data ) {
 1029+ // This happens in some weird cases
 1030+ return;
 1031+ }
 1032+ var status;
 1033+ if ( typeof data.query == 'undefined' ) {
 1034+ status = 'invalid';
 1035+ } else {
 1036+ var page = data.query.pages[data.query.pageids[0]];
 1037+ status = 'exists';
 1038+ if ( typeof page.missing != 'undefined' )
 1039+ status = 'notexists';
 1040+ else if ( typeof page.invalid != 'undefined' )
 1041+ status = 'invalid';
 1042+ }
 1043+ // Cache the status of the link target if the force internal parameter was not passed
 1044+ if ( !internal ) cache[target] = status;
 1045+ updateWidget( status );
 1046+ }
 1047+ } )
 1048+ );
 1049+ }
 1050+ $j( '#wikieditor-toolbar-link-type-int, #wikieditor-toolbar-link-type-ext' ).click( function() {
 1051+ if( $j( '#wikieditor-toolbar-link-type-ext' ).is( ':checked' ) ) {
 1052+ // Abort previous request
 1053+ var request = $j( '#wikieditor-toolbar-link-int-target-status' ).data( 'request' );
 1054+ if ( request ) {
 1055+ request.abort();
 1056+ }
 1057+ updateWidget( 'external' );
 1058+ }
 1059+ if( $j( '#wikieditor-toolbar-link-type-int' ).is( ':checked' ) )
 1060+ updateExistence( true );
 1061+ });
 1062+ // Set labels of tabs based on rel values
 1063+ var u = mw.usability;
 1064+ $j(this).find( '[rel]' ).each( function() {
 1065+ $j(this).text( u.getMsg( $j(this).attr( 'rel' ) ) );
 1066+ });
 1067+ // Set tabindexes on form fields
 1068+ $j.wikiEditor.modules.dialogs.fn.setTabindexes( $j(this).find( 'input' ).not( '[tabindex]' ) );
 1069+ // Setup the tooltips in the textboxes
 1070+ $j( '#wikieditor-toolbar-link-int-target' )
 1071+ .data( 'tooltip', u.getMsg( 'wikieditor-toolbar-tool-link-int-target-tooltip' ) );
 1072+ $j( '#wikieditor-toolbar-link-int-text' )
 1073+ .data( 'tooltip', u.getMsg( 'wikieditor-toolbar-tool-link-int-text-tooltip' ) );
 1074+ $j( '#wikieditor-toolbar-link-int-target, #wikieditor-toolbar-link-int-text' )
 1075+ .each( function() {
 1076+ var tooltip = u.getMsg( $j( this ).attr( 'id' ) + '-tooltip' );
 1077+ if ( $j( this ).val() == '' )
 1078+ $j( this )
 1079+ .addClass( 'wikieditor-toolbar-dialog-hint' )
 1080+ .val( $j( this ).data( 'tooltip' ) )
 1081+ .data( 'tooltip-mode', true );
 1082+ } )
 1083+ .focus( function() {
 1084+ if( $j( this ).val() == $j( this ).data( 'tooltip' ) ) {
 1085+ $j( this )
 1086+ .val( '' )
 1087+ .removeClass( 'wikieditor-toolbar-dialog-hint' )
 1088+ .data( 'tooltip-mode', false );
 1089+ }
 1090+ })
 1091+ .bind( 'change', function() {
 1092+ if ( $j( this ).val() != $j( this ).data( 'tooltip' ) ) {
 1093+ $j( this )
 1094+ .removeClass( 'wikieditor-toolbar-dialog-hint' )
 1095+ .data( 'tooltip-mode', false );
 1096+ }
 1097+ })
 1098+ .bind( 'blur', function() {
 1099+ if ( $j( this ).val() == '' ) {
 1100+ $j( this )
 1101+ .addClass( 'wikieditor-toolbar-dialog-hint' )
 1102+ .val( $j( this ).data( 'tooltip' ) )
 1103+ .data( 'tooltip-mode', true );
 1104+ }
 1105+ });
 1106+
 1107+ // Automatically copy the value of the internal link page title field to the link text field unless the user
 1108+ // has changed the link text field - this is a convenience thing since most link texts are going to be the
 1109+ // the same as the page title
 1110+ // Also change the internal/external radio button accordingly
 1111+ $j( '#wikieditor-toolbar-link-int-target' ).bind( 'change keydown paste cut', function() {
 1112+ // $j(this).val() is the old value, before the keypress
 1113+ // Defer this until $j(this).val() has been updated
 1114+ setTimeout( function() {
 1115+ if ( isExternalLink( $j( '#wikieditor-toolbar-link-int-target' ).val() ) ) {
 1116+ $j( '#wikieditor-toolbar-link-type-ext' ).attr( 'checked', 'checked' );
 1117+ updateWidget( 'external' );
 1118+ } else {
 1119+ $j( '#wikieditor-toolbar-link-type-int' ).attr( 'checked', 'checked' );
 1120+ updateExistence();
 1121+ }
 1122+ if ( $j( '#wikieditor-toolbar-link-int-text' ).data( 'untouched' ) )
 1123+ if ( $j( '#wikieditor-toolbar-link-int-target' ).val() ==
 1124+ $j( '#wikieditor-toolbar-link-int-target' ).data( 'tooltip' ) ) {
 1125+ $j( '#wikieditor-toolbar-link-int-text' )
 1126+ .addClass( 'wikieditor-toolbar-dialog-hint' )
 1127+ .val( $j( '#wikieditor-toolbar-link-int-text' ).data( 'tooltip' ) )
 1128+ .change();
 1129+ } else {
 1130+ $j( '#wikieditor-toolbar-link-int-text' )
 1131+ .val( $j( '#wikieditor-toolbar-link-int-target' ).val() )
 1132+ .change();
 1133+ }
 1134+ }, 0 );
 1135+ });
 1136+ $j( '#wikieditor-toolbar-link-int-text' ).bind( 'change keydown paste cut', function() {
 1137+ var oldVal = $j(this).val();
 1138+ var that = this;
 1139+ setTimeout( function() {
 1140+ if ( $j(that).val() != oldVal )
 1141+ $j(that).data( 'untouched', false );
 1142+ }, 0 );
 1143+ });
 1144+ // Add images to the page existence widget, which will be shown mutually exclusively to communicate if the
 1145+ // page exists, does not exist or the title is invalid (like if it contains a | character)
 1146+ var existsMsg = u.getMsg( 'wikieditor-toolbar-tool-link-int-target-status-exists' );
 1147+ var notexistsMsg = u.getMsg( 'wikieditor-toolbar-tool-link-int-target-status-notexists' );
 1148+ var invalidMsg = u.getMsg( 'wikieditor-toolbar-tool-link-int-target-status-invalid' );
 1149+ var externalMsg = u.getMsg( 'wikieditor-toolbar-tool-link-int-target-status-external' );
 1150+ var loadingMsg = u.getMsg( 'wikieditor-toolbar-tool-link-int-target-status-loading' );
 1151+ $j( '#wikieditor-toolbar-link-int-target-status' )
 1152+ .append( $j( '<div />' )
 1153+ .attr( 'id', 'wikieditor-toolbar-link-int-target-status-exists' )
 1154+ .append( existsMsg )
 1155+ )
 1156+ .append( $j( '<div />' )
 1157+ .attr( 'id', 'wikieditor-toolbar-link-int-target-status-notexists' )
 1158+ .append( notexistsMsg )
 1159+ )
 1160+ .append( $j( '<div />' )
 1161+ .attr( 'id', 'wikieditor-toolbar-link-int-target-status-invalid' )
 1162+ .append( invalidMsg )
 1163+ )
 1164+ .append( $j( '<div />' )
 1165+ .attr( 'id', 'wikieditor-toolbar-link-int-target-status-external' )
 1166+ .append( externalMsg )
 1167+ )
 1168+ .append( $j( '<div />' )
 1169+ .attr( 'id', 'wikieditor-toolbar-link-int-target-status-loading' )
 1170+ .append( $j( '<img />' ).attr( {
 1171+ 'src': $j.wikiEditor.imgPath + 'dialogs/' + 'loading.gif',
 1172+ 'alt': loadingMsg,
 1173+ 'title': loadingMsg
 1174+ } ) )
 1175+ )
 1176+ .data( 'existencecache', {} )
 1177+ .children().hide();
 1178+
 1179+ $j( '#wikieditor-toolbar-link-int-target' )
 1180+ .bind( 'keyup paste cut', function() {
 1181+ // Cancel the running timer if applicable
 1182+ if ( typeof $j(this).data( 'timerID' ) != 'undefined' ) {
 1183+ clearTimeout( $j(this).data( 'timerID' ) );
 1184+ }
 1185+ // Delay fetch for a while
 1186+ // FIXME: Make 120 configurable elsewhere
 1187+ var timerID = setTimeout( updateExistence, 120 );
 1188+ $j(this).data( 'timerID', timerID );
 1189+ } )
 1190+ .change( function() {
 1191+ // Cancel the running timer if applicable
 1192+ if ( typeof $j(this).data( 'timerID' ) != 'undefined' ) {
 1193+ clearTimeout( $j(this).data( 'timerID' ) );
 1194+ }
 1195+ // Fetch right now
 1196+ updateExistence();
 1197+ } );
 1198+
 1199+ // Title suggestions
 1200+ $j( '#wikieditor-toolbar-link-int-target' ).data( 'suggcache', {} ).suggestions( {
 1201+ fetch: function( query ) {
 1202+ var that = this;
 1203+ var title = $j(this).val();
 1204+
 1205+ if ( isExternalLink( title ) || title.indexOf( '|' ) != -1 || title == '') {
 1206+ $j(this).suggestions( 'suggestions', [] );
 1207+ return;
 1208+ }
 1209+
 1210+ var cache = $j(this).data( 'suggcache' );
 1211+ if ( typeof cache[title] != 'undefined' ) {
 1212+ $j(this).suggestions( 'suggestions', cache[title] );
 1213+ return;
 1214+ }
 1215+
 1216+ var request = $j.ajax( {
 1217+ url: wgScriptPath + '/api.php',
 1218+ data: {
 1219+ 'action': 'opensearch',
 1220+ 'search': title,
 1221+ 'namespace': 0,
 1222+ 'suggest': '',
 1223+ 'format': 'json'
 1224+ },
 1225+ dataType: 'json',
 1226+ success: function( data ) {
 1227+ cache[title] = data[1];
 1228+ $j(that).suggestions( 'suggestions', data[1] );
 1229+ }
 1230+ });
 1231+ $j(this).data( 'request', request );
 1232+ },
 1233+ cancel: function() {
 1234+ var request = $j(this).data( 'request' );
 1235+ if ( request )
 1236+ request.abort();
 1237+ }
 1238+ });
 1239+ },
 1240+ dialog: {
 1241+ width: 500,
 1242+ dialogClass: 'wikiEditor-toolbar-dialog',
 1243+ buttons: {
 1244+ 'wikieditor-toolbar-tool-link-insert': function() {
 1245+ function escapeInternalText( s ) {
 1246+ // FIXME: Should this escape [[ too? Seems to work without that
 1247+ return s.replace( /(]{2,})/g, '<nowiki>$1</nowiki>' );
 1248+ }
 1249+ function escapeExternalTarget( s ) {
 1250+ return s.replace( / /g, '%20' )
 1251+ .replace( /\[/g, '%5B' )
 1252+ .replace( /]/g, '%5D' );
 1253+ }
 1254+ function escapeExternalText( s ) {
 1255+ // FIXME: Should this escape [ too? Seems to work without that
 1256+ return s.replace( /(]+)/g, '<nowiki>$1</nowiki>' );
 1257+ }
 1258+ var insertText = '';
 1259+ var whitespace = $j( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace' );
 1260+ var target = $j( '#wikieditor-toolbar-link-int-target' ).val();
 1261+ var text = $j( '#wikieditor-toolbar-link-int-text' ).val();
 1262+ // check if the tooltips were passed as target or text
 1263+ if ( $j( '#wikieditor-toolbar-link-int-target' ).data( 'tooltip-mode' ) )
 1264+ target = "";
 1265+ if ( $j( '#wikieditor-toolbar-link-int-text' ).data( 'tooltip-mode' ) )
 1266+ text = "";
 1267+ var u = mw.usability;
 1268+ if ( target == '' ) {
 1269+ alert( u.getMsg( 'wikieditor-toolbar-tool-link-empty' ) );
 1270+ return;
 1271+ }
 1272+ if ( $j.trim( text ) == '' ) {
 1273+ // [[Foo| ]] creates an invisible link
 1274+ // Instead, generate [[Foo|]]
 1275+ text = '';
 1276+ }
 1277+ if ( $j( '#wikieditor-toolbar-link-type-int' ).is( ':checked' ) ) {
 1278+ // FIXME: Exactly how fragile is this?
 1279+ if ( $j( '#wikieditor-toolbar-link-int-target-status-invalid' ).is( ':visible' ) ) {
 1280+ // Refuse to add links to invalid titles
 1281+ alert( u.getMsg( 'wikieditor-toolbar-tool-link-int-invalid' ) );
 1282+ return;
 1283+ }
 1284+
 1285+ if ( target == text || !text.length )
 1286+ insertText = '[[' + target + ']]';
 1287+ else
 1288+ insertText = '[[' + target + '|' + escapeInternalText( text ) + ']]';
 1289+ } else {
 1290+ // Prepend http:// if there is no protocol
 1291+ if ( !target.match( /^[a-z]+:\/\/./ ) )
 1292+ target = 'http://' + target;
 1293+
 1294+ // Detect if this is really an internal link in disguise
 1295+ var match = target.match( $j(this).data( 'articlePathRegex' ) );
 1296+ if ( match && !$j(this).data( 'ignoreLooksInternal' ) ) {
 1297+ var buttons = { };
 1298+ var that = this;
 1299+ buttons[ u.getMsg( 'wikieditor-toolbar-tool-link-lookslikeinternal-int' ) ] = function() {
 1300+ $j( '#wikieditor-toolbar-link-int-target' ).val( match[1] ).change();
 1301+ $j(this).dialog( 'close' );
 1302+ };
 1303+ buttons[ u.getMsg( 'wikieditor-toolbar-tool-link-lookslikeinternal-ext' ) ] = function() {
 1304+ $j(that).data( 'ignoreLooksInternal', true );
 1305+ $j(that).closest( '.ui-dialog' ).find( 'button:first' ).click();
 1306+ $j(that).data( 'ignoreLooksInternal', false );
 1307+ $j(this).dialog( 'close' );
 1308+ };
 1309+ $j.wikiEditor.modules.dialogs.quickDialog(
 1310+ u.getMsg( 'wikieditor-toolbar-tool-link-lookslikeinternal', match[1] ),
 1311+ { buttons: buttons }
 1312+ );
 1313+ return;
 1314+ }
 1315+
 1316+ var escTarget = escapeExternalTarget( target );
 1317+ var escText = escapeExternalText( text );
 1318+
 1319+ if ( escTarget == escText )
 1320+ insertText = escTarget;
 1321+ else if ( text == '' )
 1322+ insertText = '[' + escTarget + ']';
 1323+ else
 1324+ insertText = '[' + escTarget + ' ' + escText + ']';
 1325+ }
 1326+ // Preserve whitespace in selection when replacing
 1327+ if ( whitespace ) insertText = whitespace[0] + insertText + whitespace[1];
 1328+ $j(this).dialog( 'close' );
 1329+ $j.wikiEditor.modules.toolbar.fn.doAction( $j(this).data( 'context' ), {
 1330+ type: 'replace',
 1331+ options: {
 1332+ pre: insertText
 1333+ }
 1334+ }, $j(this) );
 1335+
 1336+ // Blank form
 1337+ $j( '#wikieditor-toolbar-link-int-target, #wikieditor-toolbar-link-int-text' ).val( '' );
 1338+ $j( '#wikieditor-toolbar-link-type-int, #wikieditor-toolbar-link-type-ext' ).attr( 'checked', '' );
 1339+ },
 1340+ 'wikieditor-toolbar-tool-link-cancel': function() {
 1341+ // Clear any saved selection state
 1342+ var context = $j(this).data( 'context' );
 1343+ context.fn.restoreStuffForIE();
 1344+ $j(this).dialog( 'close' );
 1345+ }
 1346+ },
 1347+ open: function() {
 1348+ // Cache the articlepath regex
 1349+ $j(this).data( 'articlePathRegex', new RegExp(
 1350+ '^' + RegExp.escape( wgServer + wgArticlePath )
 1351+ .replace( /\\\$1/g, '(.*)' ) + '$'
 1352+ ) );
 1353+ // Pre-fill the text fields based on the current selection
 1354+ var context = $j(this).data( 'context' );
 1355+ // Restore and immediately save selection state, needed for inserting stuff later
 1356+ context.fn.restoreStuffForIE();
 1357+ context.fn.saveStuffForIE();
 1358+ var selection = context.$textarea.textSelection( 'getSelection' );
 1359+ $j( '#wikieditor-toolbar-link-int-target' ).focus();
 1360+ // Trigger the change event, so the link status indicator is up to date
 1361+ $j( '#wikieditor-toolbar-link-int-target' ).change();
 1362+ $j( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [ '', '' ] );
 1363+ if ( selection != '' ) {
 1364+ var target, text, type;
 1365+ var matches;
 1366+ if ( ( matches = selection.match( /^(\s*)\[\[([^\]\|]+)(\|([^\]\|]*))?\]\](\s*)$/ ) ) ) {
 1367+ // [[foo|bar]] or [[foo]]
 1368+ target = matches[2];
 1369+ text = ( matches[4] ? matches[4] : matches[2] );
 1370+ type = 'int';
 1371+ // Preserve whitespace when replacing
 1372+ $j( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [ matches[1], matches[5] ] );
 1373+ } else if ( ( matches = selection.match( /^(\s*)\[([^\] ]+)( ([^\]]+))?\](\s*)$/ ) ) ) {
 1374+ // [http://www.example.com foo] or [http://www.example.com]
 1375+ target = matches[2];
 1376+ text = ( matches[4] ? matches[4] : '' );
 1377+ type = 'ext';
 1378+ // Preserve whitespace when replacing
 1379+ $j( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [ matches[1], matches[5] ] );
 1380+ } else {
 1381+ // Trim any leading and trailing whitespace from the selection,
 1382+ // but preserve it when replacing
 1383+ target = text = $j.trim( selection );
 1384+ if ( target.length < selection.length ) {
 1385+ $j( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [
 1386+ selection.substr( 0, selection.indexOf( target.charAt( 0 ) ) ),
 1387+ selection.substr(
 1388+ selection.lastIndexOf( target.charAt( target.length - 1 ) ) + 1
 1389+ ) ]
 1390+ );
 1391+ }
 1392+ }
 1393+
 1394+ // Change the value by calling val() doesn't trigger the change event, so let's do that ourselves
 1395+ if ( typeof text != 'undefined' )
 1396+ $j( '#wikieditor-toolbar-link-int-text' ).val( text ).change();
 1397+ if ( typeof target != 'undefined' )
 1398+ $j( '#wikieditor-toolbar-link-int-target' ).val( target ).change();
 1399+ if ( typeof type != 'undefined' )
 1400+ $j( '#wikieditor-toolbar-link-' + type ).attr( 'checked', 'checked' );
 1401+ }
 1402+ $j( '#wikieditor-toolbar-link-int-text' ).data( 'untouched',
 1403+ $j( '#wikieditor-toolbar-link-int-text' ).val() ==
 1404+ $j( '#wikieditor-toolbar-link-int-target' ).val() ||
 1405+ $j( '#wikieditor-toolbar-link-int-text' ).hasClass( 'wikieditor-toolbar-dialog-hint' )
 1406+ );
 1407+ $j( '#wikieditor-toolbar-link-int-target' ).suggestions();
 1408+
 1409+ //don't overwrite user's text
 1410+ if( selection != '' ){
 1411+ $j( '#wikieditor-toolbar-link-int-text' ).data( 'untouched', false );
 1412+ }
 1413+
 1414+ $j( '#wikieditor-toolbar-link-int-text, #wikiedit-toolbar-link-int-target' )
 1415+ .each( function() {
 1416+ if ( $j(this).val() == '' )
 1417+ $j(this).parent().find( 'label' ).show();
 1418+ });
 1419+
 1420+ if ( !( $j(this).data( 'dialogkeypressset' ) ) ) {
 1421+ $j(this).data( 'dialogkeypressset', true );
 1422+ // Execute the action associated with the first button
 1423+ // when the user presses Enter
 1424+ $j(this).closest( '.ui-dialog' ).keypress( function( e ) {
 1425+ if ( ( e.keyCode || e.which ) == 13 ) {
 1426+ var button = $j(this).data( 'dialogaction' ) || $j(this).find( 'button:first' );
 1427+ button.click();
 1428+ e.preventDefault();
 1429+ }
 1430+ });
 1431+
 1432+ // Make tabbing to a button and pressing
 1433+ // Enter do what people expect
 1434+ $j(this).closest( '.ui-dialog' ).find( 'button' ).focus( function() {
 1435+ $j(this).closest( '.ui-dialog' ).data( 'dialogaction', this );
 1436+ });
 1437+ }
 1438+ }
 1439+ }
 1440+ },
 1441+ 'insert-reference': {
 1442+ filters: [ '#wpTextbox1.toolbar-dialogs' ],
 1443+ titleMsg: 'wikieditor-toolbar-tool-reference-title',
 1444+ id: 'wikieditor-toolbar-reference-dialog',
 1445+ html: '\
 1446+ <div class="wikieditor-toolbar-dialog-wrapper">\
 1447+ <fieldset><div class="wikieditor-toolbar-table-form">\
 1448+ <div class="wikieditor-toolbar-field-wrapper">\
 1449+ <label for="wikieditor-toolbar-reference-text"\
 1450+ rel="wikieditor-toolbar-tool-reference-text"></label>\
 1451+ <input type="text" id="wikieditor-toolbar-reference-text" />\
 1452+ </div>\
 1453+ </div></fieldset>\
 1454+ </div>',
 1455+ init: function() {
 1456+ // Insert translated strings into labels
 1457+ $j( this ).find( '[rel]' ).each( function() {
 1458+ $j( this ).text( mw.usability.getMsg( $j( this ).attr( 'rel' ) ) );
 1459+ } );
 1460+
 1461+ },
 1462+ dialog: {
 1463+ dialogClass: 'wikiEditor-toolbar-dialog',
 1464+ width: 590,
 1465+ buttons: {
 1466+ 'wikieditor-toolbar-tool-reference-insert': function() {
 1467+ var insertText = $j( '#wikieditor-toolbar-reference-text' ).val();
 1468+ var whitespace = $j( '#wikieditor-toolbar-reference-dialog' ).data( 'whitespace' );
 1469+ var attributes = $j( '#wikieditor-toolbar-reference-dialog' ).data( 'attributes' );
 1470+ // Close the dialog
 1471+ $j( this ).dialog( 'close' );
 1472+ $j.wikiEditor.modules.toolbar.fn.doAction(
 1473+ $j( this ).data( 'context' ),
 1474+ {
 1475+ type: 'replace',
 1476+ options: {
 1477+ pre: whitespace[0] + '<ref' + attributes + '>',
 1478+ peri: insertText,
 1479+ post: '</ref>' + whitespace[1]
 1480+ }
 1481+ },
 1482+ $j( this )
 1483+ );
 1484+ // Restore form state
 1485+ $j( '#wikieditor-toolbar-reference-text' ).val( "" );
 1486+ },
 1487+ 'wikieditor-toolbar-tool-reference-cancel': function() {
 1488+ // Clear any saved selection state
 1489+ var context = $j( this ).data( 'context' );
 1490+ context.fn.restoreStuffForIE();
 1491+ $j( this ).dialog( 'close' );
 1492+ }
 1493+ },
 1494+ open: function() {
 1495+ // Pre-fill the text fields based on the current selection
 1496+ var context = $j(this).data( 'context' );
 1497+ // Restore and immediately save selection state, needed for inserting stuff later
 1498+ context.fn.restoreStuffForIE();
 1499+ context.fn.saveStuffForIE();
 1500+ var selection = context.$textarea.textSelection( 'getSelection' );
 1501+ // set focus
 1502+ $j( '#wikieditor-toolbar-reference-text' ).focus();
 1503+ $j( '#wikieditor-toolbar-reference-dialog' )
 1504+ .data( 'whitespace', [ '', '' ] )
 1505+ .data( 'attributes', '' );
 1506+ if ( selection != '' ) {
 1507+ var matches, text;
 1508+ if ( ( matches = selection.match( /^(\s*)<ref([^\>]*)>([^\<]*)<\/ref\>(\s*)$/ ) ) ) {
 1509+ text = matches[3];
 1510+ // Preserve whitespace when replacing
 1511+ $j( '#wikieditor-toolbar-reference-dialog' ).data( 'whitespace', [ matches[1], matches[4] ] );
 1512+ $j( '#wikieditor-toolbar-reference-dialog' ).data( 'attributes', matches[2] );
 1513+ } else {
 1514+ text = selection;
 1515+ }
 1516+ $j( '#wikieditor-toolbar-reference-text' ).val( text );
 1517+ }
 1518+ if ( !( $j( this ).data( 'dialogkeypressset' ) ) ) {
 1519+ $j( this ).data( 'dialogkeypressset', true );
 1520+ // Execute the action associated with the first button
 1521+ // when the user presses Enter
 1522+ $j( this ).closest( '.ui-dialog' ).keypress( function( e ) {
 1523+ if ( ( e.keyCode || e.which ) == 13 ) {
 1524+ var button = $j( this ).data( 'dialogaction' ) || $j( this ).find( 'button:first' );
 1525+ button.click();
 1526+ e.preventDefault();
 1527+ }
 1528+ } );
 1529+ // Make tabbing to a button and pressing
 1530+ // Enter do what people expect
 1531+ $j( this ).closest( '.ui-dialog' ).find( 'button' ).focus( function() {
 1532+ $j( this ).closest( '.ui-dialog' ).data( 'dialogaction', this );
 1533+ } );
 1534+ }
 1535+ }
 1536+ }
 1537+ },
 1538+ 'insert-table': {
 1539+ // For now, apply the old browser and iframe requirements to the link and table dialogs as well
 1540+ // This'll be removed once these dialogs are confirmed stable without the iframe and/or in more browsers
 1541+ filters: [ '#wpTextbox1.toolbar-dialogs' ],
 1542+ titleMsg: 'wikieditor-toolbar-tool-table-title',
 1543+ id: 'wikieditor-toolbar-table-dialog',
 1544+ // FIXME: Localize 'x'?
 1545+ html: '\
 1546+ <div class="wikieditor-toolbar-dialog-wrapper">\
 1547+ <fieldset><div class="wikieditor-toolbar-table-form">\
 1548+ <div class="wikieditor-toolbar-field-wrapper">\
 1549+ <input type="checkbox" id="wikieditor-toolbar-table-dimensions-header" checked />\
 1550+ <label for="wikieditor-toolbar-table-dimensions-header"\
 1551+ rel="wikieditor-toolbar-tool-table-dimensions-header"></label>\
 1552+ </div>\
 1553+ <div class="wikieditor-toolbar-field-wrapper">\
 1554+ <input type="checkbox" id="wikieditor-toolbar-table-wikitable" checked />\
 1555+ <label for="wikieditor-toolbar-table-wikitable" rel="wikieditor-toolbar-tool-table-wikitable"></label>\
 1556+ </div>\
 1557+ <div class="wikieditor-toolbar-field-wrapper">\
 1558+ <input type="checkbox" id="wikieditor-toolbar-table-sortable" />\
 1559+ <label for="wikieditor-toolbar-table-sortable" rel="wikieditor-toolbar-tool-table-sortable"></label>\
 1560+ </div>\
 1561+ <div class="wikieditor-toolbar-table-dimension-fields">\
 1562+ <div class="wikieditor-toolbar-field-wrapper">\
 1563+ <label for="wikieditor-toolbar-table-dimensions-rows"\
 1564+ rel="wikieditor-toolbar-tool-table-dimensions-rows"></label><br />\
 1565+ <input type="text" id="wikieditor-toolbar-table-dimensions-rows" size="4" />\
 1566+ </div>\
 1567+ <div class="wikieditor-toolbar-field-wrapper">\
 1568+ <label for="wikieditor-toolbar-table-dimensions-columns"\
 1569+ rel="wikieditor-toolbar-tool-table-dimensions-columns"></label><br />\
 1570+ <input type="text" id="wikieditor-toolbar-table-dimensions-columns" size="4" />\
 1571+ </div>\
 1572+ </div>\
 1573+ </div></fieldset>\
 1574+ <div class="wikieditor-toolbar-table-preview-wrapper" >\
 1575+ <span rel="wikieditor-toolbar-tool-table-example"></span>\
 1576+ <div class="wikieditor-toolbar-table-preview-content">\
 1577+ <table id="wikieditor-toolbar-table-preview" class="wikieditor-toolbar-table-preview wikitable">\
 1578+ <tr class="wikieditor-toolbar-table-preview-header">\
 1579+ <th rel="wikieditor-toolbar-tool-table-example-header"></th>\
 1580+ <th rel="wikieditor-toolbar-tool-table-example-header"></th>\
 1581+ <th rel="wikieditor-toolbar-tool-table-example-header"></th>\
 1582+ </tr><tr class="wikieditor-toolbar-table-preview-hidden" style="display: none;">\
 1583+ <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 1584+ <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 1585+ <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 1586+ </tr><tr>\
 1587+ <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 1588+ <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 1589+ <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 1590+ </tr><tr>\
 1591+ <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 1592+ <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 1593+ <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 1594+ </tr><tr>\
 1595+ <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 1596+ <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 1597+ <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 1598+ </tr>\
 1599+ </table>\
 1600+ </div>\
 1601+ </div></div>',
 1602+ init: function() {
 1603+ $j(this).find( '[rel]' ).each( function() {
 1604+ $j(this).text( mw.usability.getMsg( $j(this).attr( 'rel' ) ) );
 1605+ });
 1606+ // Set tabindexes on form fields
 1607+ $j.wikiEditor.modules.dialogs.fn.setTabindexes( $j(this).find( 'input' ).not( '[tabindex]' ) );
 1608+
 1609+ $j( '#wikieditor-toolbar-table-dimensions-rows' ).val( 3 );
 1610+ $j( '#wikieditor-toolbar-table-dimensions-columns' ).val( 3 );
 1611+ $j( '#wikieditor-toolbar-table-wikitable' ).click( function() {
 1612+ $j( '.wikieditor-toolbar-table-preview' ).toggleClass( 'wikitable' );
 1613+ });
 1614+
 1615+ // Hack for sortable preview: dynamically adding
 1616+ // sortable class doesn't work, so we use a clone
 1617+ // FIXME: Relies on sortable table internals
 1618+ $j( '#wikieditor-toolbar-table-preview' )
 1619+ .clone()
 1620+ .attr( 'id', 'wikieditor-toolbar-table-preview2' )
 1621+ .addClass( 'sortable' )
 1622+ .insertAfter( $j( '#wikieditor-toolbar-table-preview' ) )
 1623+ .hide();
 1624+ if ( typeof ts_makeSortable == 'function' )
 1625+ ts_makeSortable( $j( '#wikieditor-toolbar-table-preview2' ).get( 0 ) );
 1626+ $j( '#wikieditor-toolbar-table-sortable' ).click( function() {
 1627+ // Swap the currently shown one clone with the other one
 1628+ $j( '#wikieditor-toolbar-table-preview' )
 1629+ .hide()
 1630+ .attr( 'id', 'wikieditor-toolbar-table-preview3' );
 1631+ $j( '#wikieditor-toolbar-table-preview2' )
 1632+ .attr( 'id', 'wikieditor-toolbar-table-preview' )
 1633+ .show();
 1634+ $j( '#wikieditor-toolbar-table-preview3' ).attr( 'id', 'wikieditor-toolbar-table-preview2' );
 1635+ });
 1636+
 1637+ $j( '#wikieditor-toolbar-table-dimensions-header' ).click( function() {
 1638+ // Instead of show/hiding, switch the HTML around
 1639+ // We do this because the sortable tables script styles the first row,
 1640+ // visible or not
 1641+ var headerHTML = $j( '.wikieditor-toolbar-table-preview-header' ).html();
 1642+ var hiddenHTML = $j( '.wikieditor-toolbar-table-preview-hidden' ).html();
 1643+ $j( '.wikieditor-toolbar-table-preview-header' ).html( hiddenHTML );
 1644+ $j( '.wikieditor-toolbar-table-preview-hidden' ).html( headerHTML );
 1645+ if ( typeof ts_makeSortable == 'function' )
 1646+ ts_makeSortable(
 1647+ $j( '#wikieditor-toolbar-table-preview, #wikieditor-toolbar-table-preview2' )
 1648+ .filter( '.sortable' )
 1649+ .get( 0 )
 1650+ );
 1651+ });
 1652+
 1653+ },
 1654+ dialog: {
 1655+ resizable: false,
 1656+ dialogClass: 'wikiEditor-toolbar-dialog',
 1657+ width: 590,
 1658+ buttons: {
 1659+ 'wikieditor-toolbar-tool-table-insert': function() {
 1660+ var rowsVal = $j( '#wikieditor-toolbar-table-dimensions-rows' ).val();
 1661+ var colsVal = $j( '#wikieditor-toolbar-table-dimensions-columns' ).val();
 1662+ var rows = parseInt( rowsVal, 10 );
 1663+ var cols = parseInt( colsVal, 10 );
 1664+ var header = $j( '#wikieditor-toolbar-table-dimensions-header' ).is( ':checked' ) ? 1 : 0;
 1665+ var u = mw.usability;
 1666+ if ( isNaN( rows ) || isNaN( cols ) || rows != rowsVal || cols != colsVal ) {
 1667+ alert( u.getMsg( 'wikieditor-toolbar-tool-table-invalidnumber' ) );
 1668+ return;
 1669+ }
 1670+ if ( rows + header == 0 || cols == 0 ) {
 1671+ alert( u.getMsg( 'wikieditor-toolbar-tool-table-zero' ) );
 1672+ return;
 1673+ }
 1674+ if ( rows * cols > 1000 ) {
 1675+ alert( u.getMsg( 'wikieditor-toolbar-tool-table-toomany', 1000 ) );
 1676+ return;
 1677+ }
 1678+ var headerText = u.getMsg( 'wikieditor-toolbar-tool-table-example-header' );
 1679+ var normalText = u.getMsg( 'wikieditor-toolbar-tool-table-example' );
 1680+ var table = "";
 1681+ for ( var r = 0; r < rows + header; r++ ) {
 1682+ table += "|-\n";
 1683+ for ( var c = 0; c < cols; c++ ) {
 1684+ var isHeader = ( header && r == 0 );
 1685+ var delim = isHeader ? '!' : '|';
 1686+ if ( c > 0 ) {
 1687+ delim += delim;
 1688+ }
 1689+ table += delim + ' ' + ( isHeader ? headerText : normalText ) + ' ';
 1690+ }
 1691+ // Replace trailing space by newline
 1692+ // table[table.length - 1] is read-only
 1693+ table = table.substr( 0, table.length - 1 ) + "\n";
 1694+ }
 1695+ var classes = [];
 1696+ if ( $j( '#wikieditor-toolbar-table-wikitable' ).is( ':checked' ) )
 1697+ classes.push( 'wikitable' );
 1698+ if ( $j( '#wikieditor-toolbar-table-sortable' ).is( ':checked' ) )
 1699+ classes.push( 'sortable' );
 1700+ var classStr = classes.length > 0 ? ' class="' + classes.join( ' ' ) + '"' : '';
 1701+ $j(this).dialog( 'close' );
 1702+ $j.wikiEditor.modules.toolbar.fn.doAction(
 1703+ $j(this).data( 'context' ),
 1704+ {
 1705+ type: 'replace',
 1706+ options: {
 1707+ pre: '{|' + classStr + "\n",
 1708+ peri: table,
 1709+ post: '|}',
 1710+ ownline: true
 1711+ }
 1712+ },
 1713+ $j(this)
 1714+ );
 1715+
 1716+ // Restore form state
 1717+ $j( '#wikieditor-toolbar-table-dimensions-rows' ).val( 3 );
 1718+ $j( '#wikieditor-toolbar-table-dimensions-columns' ).val( 3 );
 1719+ // Simulate clicks instead of setting values, so the according
 1720+ // actions are performed
 1721+ if ( !$j( '#wikieditor-toolbar-table-dimensions-header' ).is( ':checked' ) )
 1722+ $j( '#wikieditor-toolbar-table-dimensions-header' ).click();
 1723+ if ( !$j( '#wikieditor-toolbar-table-wikitable' ).is( ':checked' ) )
 1724+ $j( '#wikieditor-toolbar-table-wikitable' ).click();
 1725+ if ( $j( '#wikieditor-toolbar-table-sortable' ).is( ':checked' ) )
 1726+ $j( '#wikieditor-toolbar-table-sortable' ).click();
 1727+ },
 1728+ 'wikieditor-toolbar-tool-table-cancel': function() {
 1729+ $j(this).dialog( 'close' );
 1730+ }
 1731+ },
 1732+ open: function() {
 1733+ $j( '#wikieditor-toolbar-table-dimensions-rows' ).focus();
 1734+ if ( !( $j(this).data( 'dialogkeypressset' ) ) ) {
 1735+ $j(this).data( 'dialogkeypressset', true );
 1736+ // Execute the action associated with the first button
 1737+ // when the user presses Enter
 1738+ $j(this).closest( '.ui-dialog' ).keypress( function( e ) {
 1739+ if ( ( e.keyCode || e.which ) == 13 ) {
 1740+ var button = $j(this).data( 'dialogaction' ) || $j(this).find( 'button:first' );
 1741+ button.click();
 1742+ e.preventDefault();
 1743+ }
 1744+ });
 1745+
 1746+ // Make tabbing to a button and pressing
 1747+ // Enter do what people expect
 1748+ $j(this).closest( '.ui-dialog' ).find( 'button' ).focus( function() {
 1749+ $j(this).closest( '.ui-dialog' ).data( 'dialogaction', this );
 1750+ });
 1751+ }
 1752+ }
 1753+ }
 1754+ },
 1755+ 'search-and-replace': {
 1756+ 'browsers': {
 1757+ // Left-to-right languages
 1758+ 'ltr': {
 1759+ 'msie': false,
 1760+ 'firefox': [['>=', 2]],
 1761+ 'opera': false,
 1762+ 'safari': [['>=', 3]],
 1763+ 'chrome': [['>=', 3]]
 1764+ },
 1765+ // Right-to-left languages
 1766+ 'rtl': {
 1767+ 'msie': false,
 1768+ 'firefox': [['>=', 2]],
 1769+ 'opera': false,
 1770+ 'safari': [['>=', 3]],
 1771+ 'chrome': [['>=', 3]]
 1772+ }
 1773+ },
 1774+ filters: [ '#wpTextbox1.toolbar-dialogs' ],
 1775+ titleMsg: 'wikieditor-toolbar-tool-replace-title',
 1776+ id: 'wikieditor-toolbar-replace-dialog',
 1777+ html: '\
 1778+ <div id="wikieditor-toolbar-replace-message">\
 1779+ <div id="wikieditor-toolbar-replace-nomatch" rel="wikieditor-toolbar-tool-replace-nomatch"></div>\
 1780+ <div id="wikieditor-toolbar-replace-success"></div>\
 1781+ <div id="wikieditor-toolbar-replace-emptysearch" rel="wikieditor-toolbar-tool-replace-emptysearch"></div>\
 1782+ <div id="wikieditor-toolbar-replace-invalidregex"></div>\
 1783+ </div>\
 1784+ <fieldset>\
 1785+ <div class="wikieditor-toolbar-field-wrapper">\
 1786+ <label for="wikieditor-toolbar-replace-search" rel="wikieditor-toolbar-tool-replace-search"></label>\
 1787+ <input type="text" id="wikieditor-toolbar-replace-search" style="width: 100%;" />\
 1788+ </div>\
 1789+ <div class="wikieditor-toolbar-field-wrapper">\
 1790+ <label for="wikieditor-toolbar-replace-replace" rel="wikieditor-toolbar-tool-replace-replace"></label>\
 1791+ <input type="text" id="wikieditor-toolbar-replace-replace" style="width: 100%;" />\
 1792+ </div>\
 1793+ <div class="wikieditor-toolbar-field-wrapper">\
 1794+ <input type="checkbox" id="wikieditor-toolbar-replace-case" />\
 1795+ <label for="wikieditor-toolbar-replace-case" rel="wikieditor-toolbar-tool-replace-case"></label>\
 1796+ </div>\
 1797+ <div class="wikieditor-toolbar-field-wrapper">\
 1798+ <input type="checkbox" id="wikieditor-toolbar-replace-regex" />\
 1799+ <label for="wikieditor-toolbar-replace-regex" rel="wikieditor-toolbar-tool-replace-regex"></label>\
 1800+ </div>\
 1801+ </fieldset>',
 1802+ init: function() {
 1803+ var u = mw.usability;
 1804+ $j(this).find( '[rel]' ).each( function() {
 1805+ $j(this).text( u.getMsg( $j(this).attr( 'rel' ) ) );
 1806+ });
 1807+ // Set tabindexes on form fields
 1808+ $j.wikiEditor.modules.dialogs.fn.setTabindexes( $j(this).find( 'input' ).not( '[tabindex]' ) );
 1809+
 1810+ // TODO: Find a cleaner way to share this function
 1811+ $j(this).data( 'replaceCallback', function( mode ) {
 1812+ $j( '#wikieditor-toolbar-replace-nomatch, #wikieditor-toolbar-replace-success, #wikieditor-toolbar-replace-emptysearch, #wikieditor-toolbar-replace-invalidregex' ).hide();
 1813+ var searchStr = $j( '#wikieditor-toolbar-replace-search' ).val();
 1814+ if ( searchStr == '' ) {
 1815+ $j( '#wikieditor-toolbar-replace-emptysearch' ).show();
 1816+ return;
 1817+ }
 1818+ var replaceStr = $j( '#wikieditor-toolbar-replace-replace' ).val();
 1819+ var flags = 'm';
 1820+ var matchCase = $j( '#wikieditor-toolbar-replace-case' ).is( ':checked' );
 1821+ var isRegex = $j( '#wikieditor-toolbar-replace-regex' ).is( ':checked' );
 1822+ if ( !matchCase ) {
 1823+ flags += 'i';
 1824+ }
 1825+ if ( mode == 'replaceAll' ) {
 1826+ flags += 'g';
 1827+ }
 1828+ if ( !isRegex ) {
 1829+ searchStr = RegExp.escape( searchStr );
 1830+ }
 1831+ try {
 1832+ var regex = new RegExp( searchStr, flags );
 1833+ } catch( e ) {
 1834+ $j( '#wikieditor-toolbar-replace-invalidregex' )
 1835+ .text( u.getMsg( 'wikieditor-toolbar-tool-replace-invalidregex',
 1836+ e.message ) )
 1837+ .show();
 1838+ return;
 1839+ }
 1840+ var $textarea = $j(this).data( 'context' ).$textarea;
 1841+ var text = $textarea.textSelection( 'getContents' );
 1842+ var match = false;
 1843+ var offset, s;
 1844+ if ( mode != 'replaceAll' ) {
 1845+ offset = $j(this).data( 'offset' );
 1846+ s = text.substr( offset );
 1847+ match = s.match( regex );
 1848+ }
 1849+ if ( !match ) {
 1850+ // Search hit BOTTOM, continuing at TOP
 1851+ offset = 0;
 1852+ s = text;
 1853+ match = s.match( regex );
 1854+ }
 1855+
 1856+ if ( !match ) {
 1857+ $j( '#wikieditor-toolbar-replace-nomatch' ).show();
 1858+ } else if ( mode == 'replaceAll' ) {
 1859+ // Instead of using repetitive .match() calls, we use one .match() call with /g
 1860+ // and indexOf() followed by substr() to find the offsets. This is actually
 1861+ // faster because our indexOf+substr loop is faster than a match loop, and the
 1862+ // /g match is so ridiculously fast that it's negligible.
 1863+ var index;
 1864+ for ( var i = 0; i < match.length; i++ ) {
 1865+ index = s.indexOf( match[i] );
 1866+ if ( index == -1 ) {
 1867+ // This shouldn't happen
 1868+ break;
 1869+ }
 1870+ s = s.substr( index + match[i].length );
 1871+
 1872+ var start = index + offset;
 1873+ var end = start + match[i].length;
 1874+ var newEnd = start + replaceStr.length;
 1875+ $textarea
 1876+ .textSelection( 'setSelection', { 'start': start, 'end': end } )
 1877+ .textSelection( 'encapsulateSelection', {
 1878+ 'peri': replaceStr,
 1879+ 'replace': true } )
 1880+ .textSelection( 'setSelection', { 'start': start, 'end': newEnd } );
 1881+ offset = newEnd;
 1882+ }
 1883+ $j( '#wikieditor-toolbar-replace-success' )
 1884+ .text( u.getMsg( 'wikieditor-toolbar-tool-replace-success', match.length ) )
 1885+ .show();
 1886+ $j(this).data( 'offset', 0 );
 1887+ } else {
 1888+ var start = match.index + offset;
 1889+ var end = start + match[0].length;
 1890+ var newEnd = start + replaceStr.length;
 1891+ var context = $j( this ).data( 'context' );
 1892+ $textarea.textSelection( 'setSelection', { 'start': start,
 1893+ 'end': end } );
 1894+ if ( mode == 'replace' ) {
 1895+ $textarea
 1896+ .textSelection( 'encapsulateSelection', {
 1897+ 'peri': replaceStr,
 1898+ 'replace': true } )
 1899+ .textSelection( 'setSelection', {
 1900+ 'start': start,
 1901+ 'end': newEnd } );
 1902+ }
 1903+ $textarea.textSelection( 'scrollToCaretPosition' );
 1904+ $textarea.textSelection( 'setSelection', { 'start': start,
 1905+ 'end': mode == 'replace' ? newEnd : end } );
 1906+ $j( this ).data( 'offset', mode == 'replace' ? newEnd : end );
 1907+ var textbox = typeof context.$iframe != 'undefined' ? context.$iframe[0].contentWindow : $textarea[0];
 1908+ textbox.focus();
 1909+ }
 1910+ });
 1911+ },
 1912+ dialog: {
 1913+ width: 500,
 1914+ dialogClass: 'wikiEditor-toolbar-dialog',
 1915+ buttons: {
 1916+ 'wikieditor-toolbar-tool-replace-button-findnext': function( e ) {
 1917+ $j(this).closest( '.ui-dialog' ).data( 'dialogaction', e.target );
 1918+ $j(this).data( 'replaceCallback' ).call( this, 'find' );
 1919+ },
 1920+ 'wikieditor-toolbar-tool-replace-button-replacenext': function( e ) {
 1921+ $j(this).closest( '.ui-dialog' ).data( 'dialogaction', e.target );
 1922+ $j(this).data( 'replaceCallback' ).call( this, 'replace' );
 1923+ },
 1924+ 'wikieditor-toolbar-tool-replace-button-replaceall': function( e ) {
 1925+ $j(this).closest( '.ui-dialog' ).data( 'dialogaction', e.target );
 1926+ $j(this).data( 'replaceCallback' ).call( this, 'replaceAll' );
 1927+ },
 1928+ 'wikieditor-toolbar-tool-replace-close': function() {
 1929+ $j(this).dialog( 'close' );
 1930+ }
 1931+ },
 1932+ open: function() {
 1933+ $j(this).data( 'offset', 0 );
 1934+ $j( '#wikieditor-toolbar-replace-search' ).focus();
 1935+ $j( '#wikieditor-toolbar-replace-nomatch, #wikieditor-toolbar-replace-success, #wikieditor-toolbar-replace-emptysearch, #wikieditor-toolbar-replace-invalidregex' ).hide();
 1936+ if ( !( $j(this).data( 'onetimeonlystuff' ) ) ) {
 1937+ $j(this).data( 'onetimeonlystuff', true );
 1938+ // Execute the action associated with the first button
 1939+ // when the user presses Enter
 1940+ $j(this).closest( '.ui-dialog' ).keypress( function( e ) {
 1941+ if ( ( e.keyCode || e.which ) == 13 ) {
 1942+ var button = $j(this).data( 'dialogaction' ) || $j(this).find( 'button:first' );
 1943+ button.click();
 1944+ e.preventDefault();
 1945+ }
 1946+ });
 1947+ // Make tabbing to a button and pressing
 1948+ // Enter do what people expect
 1949+ $j(this).closest( '.ui-dialog' ).find( 'button' ).focus( function() {
 1950+ $j(this).closest( '.ui-dialog' ).data( 'dialogaction', this );
 1951+ });
 1952+ }
 1953+ var dialog = $j(this).closest( '.ui-dialog' );
 1954+ var that = this;
 1955+ var context = $j(this).data( 'context' );
 1956+ var textbox = typeof context.$iframe != 'undefined' ?
 1957+ context.$iframe[0].contentWindow.document : context.$textarea;
 1958+
 1959+ $j( textbox )
 1960+ .bind( 'keypress.srdialog', function( e ) {
 1961+ if ( ( e.keyCode || e.which ) == 13 ) {
 1962+ // Enter
 1963+ var button = dialog.data( 'dialogaction' ) || dialog.find( 'button:first' );
 1964+ button.click();
 1965+ e.preventDefault();
 1966+ } else if ( ( e.keyCode || e.which ) == 27 ) {
 1967+ // Escape
 1968+ $j(that).dialog( 'close' );
 1969+ }
 1970+ });
 1971+ },
 1972+ close: function() {
 1973+ var context = $j(this).data( 'context' );
 1974+ var textbox = typeof context.$iframe != 'undefined' ?
 1975+ context.$iframe[0].contentWindow.document : context.$textarea;
 1976+ $j( textbox ).unbind( 'keypress.srdialog' );
 1977+ $j(this).closest( '.ui-dialog' ).data( 'dialogaction', false );
 1978+ }
 1979+ }
 1980+ }
 1981+ }
 1982+};
Property changes on: branches/wmf/1.16wmf4/extensions/LiquidThreads_alpha
___________________________________________________________________
Name: svn:mergeinfo
11983 - /branches/wmf-deployment/extensions/LiquidThreads_alpha:60970
/trunk/extensions/LiquidThreads:57390,63727-68694
21984 + /branches/wmf-deployment/extensions/LiquidThreads_alpha:60970
/trunk/extensions/LiquidThreads:57390,63727-68791

Status & tagging log