r85036 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r85035‎ | r85036 | r85037 >
Date:19:19, 30 March 2011
Author:ashley
Status:deferred (Comments)
Tags:
Comment:
add LinkSuggest extension; tested with FF 3.6.13/15 and IE7 + 8 (IIRC), has some known issues on IE9. Huge thanks to Jesús Martínez Novo for rewriting the main JS file!
Modified paths:
  • /trunk/extensions/LinkSuggest (added) (history)
  • /trunk/extensions/LinkSuggest/LinkSuggest.i18n.php (added) (history)
  • /trunk/extensions/LinkSuggest/LinkSuggest.php (added) (history)
  • /trunk/extensions/LinkSuggest/jquery-ui.css (added) (history)
  • /trunk/extensions/LinkSuggest/jquery.mw.linksuggest.js (added) (history)
  • /trunk/extensions/LinkSuggest/jquery.widget.position.autocomplete-1.8.2.js (added) (history)

Diff [purge]

Index: trunk/extensions/LinkSuggest/jquery-ui.css
@@ -0,0 +1,571 @@
 2+/*
 3+ * jQuery UI CSS Framework 1.8.10
 4+ *
 5+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 6+ * Dual licensed under the MIT or GPL Version 2 licenses.
 7+ * http://jquery.org/license
 8+ *
 9+ * http://docs.jquery.com/UI/Theming/API
 10+ */
 11+
 12+/* Layout helpers
 13+----------------------------------*/
 14+.ui-helper-hidden { display: none; }
 15+.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
 16+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
 17+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
 18+.ui-helper-clearfix { display: inline-block; }
 19+/* required comment for clearfix to work in Opera \*/
 20+* html .ui-helper-clearfix { height:1%; }
 21+.ui-helper-clearfix { display:block; }
 22+/* end clearfix */
 23+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
 24+
 25+
 26+/* Interaction Cues
 27+----------------------------------*/
 28+.ui-state-disabled { cursor: default !important; }
 29+
 30+
 31+/* Icons
 32+----------------------------------*/
 33+
 34+/* states and images */
 35+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
 36+
 37+
 38+/* Misc visuals
 39+----------------------------------*/
 40+
 41+/* Overlays */
 42+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
 43+/*
 44+ * jQuery UI Accordion 1.8.10
 45+ *
 46+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 47+ * Dual licensed under the MIT or GPL Version 2 licenses.
 48+ * http://jquery.org/license
 49+ *
 50+ * http://docs.jquery.com/UI/Accordion#theming
 51+ */
 52+/* IE/Win - Fix animation bug - #4615 */
 53+.ui-accordion { width: 100%; }
 54+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
 55+.ui-accordion .ui-accordion-li-fix { display: inline; }
 56+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
 57+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
 58+.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
 59+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
 60+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
 61+.ui-accordion .ui-accordion-content-active { display: block; }
 62+/*
 63+ * jQuery UI Autocomplete 1.8.10
 64+ *
 65+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 66+ * Dual licensed under the MIT or GPL Version 2 licenses.
 67+ * http://jquery.org/license
 68+ *
 69+ * http://docs.jquery.com/UI/Autocomplete#theming
 70+ */
 71+.ui-autocomplete { position: absolute; cursor: default; }
 72+
 73+/* workarounds */
 74+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
 75+
 76+/*
 77+ * jQuery UI Menu 1.8.10
 78+ *
 79+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
 80+ * Dual licensed under the MIT or GPL Version 2 licenses.
 81+ * http://jquery.org/license
 82+ *
 83+ * http://docs.jquery.com/UI/Menu#theming
 84+ */
 85+.ui-menu {
 86+ list-style:none;
 87+ padding: 2px;
 88+ margin: 0;
 89+ display:block;
 90+ float: left;
 91+}
 92+.ui-menu .ui-menu {
 93+ margin-top: -3px;
 94+}
 95+.ui-menu .ui-menu-item {
 96+ margin:0;
 97+ padding: 0;
 98+ zoom: 1;
 99+ float: left;
 100+ clear: left;
 101+ width: 100%;
 102+}
 103+.ui-menu .ui-menu-item a {
 104+ text-decoration:none;
 105+ display:block;
 106+ padding:.2em .4em;
 107+ line-height:1.5;
 108+ zoom:1;
 109+}
 110+.ui-menu .ui-menu-item a.ui-state-hover,
 111+.ui-menu .ui-menu-item a.ui-state-active {
 112+ font-weight: normal;
 113+ margin: -1px;
 114+}
 115+/*
 116+ * jQuery UI Button 1.8.10
 117+ *
 118+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 119+ * Dual licensed under the MIT or GPL Version 2 licenses.
 120+ * http://jquery.org/license
 121+ *
 122+ * http://docs.jquery.com/UI/Button#theming
 123+ */
 124+.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
 125+.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
 126+button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
 127+.ui-button-icons-only { width: 3.4em; }
 128+button.ui-button-icons-only { width: 3.7em; }
 129+
 130+/*button text element */
 131+.ui-button .ui-button-text { display: block; line-height: 1.4; }
 132+.ui-button-text-only .ui-button-text { padding: .4em 1em; }
 133+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
 134+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
 135+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
 136+.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
 137+/* no icon support for input elements, provide padding by default */
 138+input.ui-button { padding: .4em 1em; }
 139+
 140+/*button icon element(s) */
 141+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
 142+.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
 143+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
 144+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
 145+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
 146+
 147+/*button sets*/
 148+.ui-buttonset { margin-right: 7px; }
 149+.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
 150+
 151+/* workarounds */
 152+button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
 153+/*
 154+ * jQuery UI Datepicker 1.8.10
 155+ *
 156+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 157+ * Dual licensed under the MIT or GPL Version 2 licenses.
 158+ * http://jquery.org/license
 159+ *
 160+ * http://docs.jquery.com/UI/Datepicker#theming
 161+ */
 162+.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
 163+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
 164+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
 165+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
 166+.ui-datepicker .ui-datepicker-prev { left:2px; }
 167+.ui-datepicker .ui-datepicker-next { right:2px; }
 168+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
 169+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
 170+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
 171+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
 172+.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
 173+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
 174+.ui-datepicker select.ui-datepicker-month,
 175+.ui-datepicker select.ui-datepicker-year { width: 49%;}
 176+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
 177+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
 178+.ui-datepicker td { border: 0; padding: 1px; }
 179+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
 180+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
 181+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
 182+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
 183+
 184+/* with multiple calendars */
 185+.ui-datepicker.ui-datepicker-multi { width:auto; }
 186+.ui-datepicker-multi .ui-datepicker-group { float:left; }
 187+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
 188+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
 189+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
 190+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
 191+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
 192+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
 193+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
 194+.ui-datepicker-row-break { clear:both; width:100%; }
 195+
 196+/* RTL support */
 197+.ui-datepicker-rtl { direction: rtl; }
 198+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
 199+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
 200+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
 201+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
 202+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
 203+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
 204+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
 205+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
 206+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
 207+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
 208+
 209+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
 210+.ui-datepicker-cover {
 211+ display: none; /*sorry for IE5*/
 212+ display/**/: block; /*sorry for IE5*/
 213+ position: absolute; /*must have*/
 214+ z-index: -1; /*must have*/
 215+ filter: mask(); /*must have*/
 216+ top: -4px; /*must have*/
 217+ left: -4px; /*must have*/
 218+ width: 200px; /*must have*/
 219+ height: 200px; /*must have*/
 220+}/*
 221+ * jQuery UI Dialog 1.8.10
 222+ *
 223+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 224+ * Dual licensed under the MIT or GPL Version 2 licenses.
 225+ * http://jquery.org/license
 226+ *
 227+ * http://docs.jquery.com/UI/Dialog#theming
 228+ */
 229+.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
 230+.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
 231+.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
 232+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
 233+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
 234+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
 235+.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
 236+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
 237+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
 238+.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
 239+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
 240+.ui-draggable .ui-dialog-titlebar { cursor: move; }
 241+/*
 242+ * jQuery UI Progressbar 1.8.10
 243+ *
 244+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 245+ * Dual licensed under the MIT or GPL Version 2 licenses.
 246+ * http://jquery.org/license
 247+ *
 248+ * http://docs.jquery.com/UI/Progressbar#theming
 249+ */
 250+.ui-progressbar { height:2em; text-align: left; }
 251+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/*
 252+ * jQuery UI Resizable 1.8.10
 253+ *
 254+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 255+ * Dual licensed under the MIT or GPL Version 2 licenses.
 256+ * http://jquery.org/license
 257+ *
 258+ * http://docs.jquery.com/UI/Resizable#theming
 259+ */
 260+.ui-resizable { position: relative;}
 261+.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
 262+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
 263+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
 264+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
 265+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
 266+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
 267+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
 268+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
 269+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
 270+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
 271+ * jQuery UI Selectable 1.8.10
 272+ *
 273+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 274+ * Dual licensed under the MIT or GPL Version 2 licenses.
 275+ * http://jquery.org/license
 276+ *
 277+ * http://docs.jquery.com/UI/Selectable#theming
 278+ */
 279+.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
 280+/*
 281+ * jQuery UI Slider 1.8.10
 282+ *
 283+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 284+ * Dual licensed under the MIT or GPL Version 2 licenses.
 285+ * http://jquery.org/license
 286+ *
 287+ * http://docs.jquery.com/UI/Slider#theming
 288+ */
 289+.ui-slider { position: relative; text-align: left; }
 290+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
 291+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
 292+
 293+.ui-slider-horizontal { height: .8em; }
 294+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
 295+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
 296+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
 297+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
 298+
 299+.ui-slider-vertical { width: .8em; height: 100px; }
 300+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
 301+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
 302+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
 303+.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
 304+ * jQuery UI Tabs 1.8.10
 305+ *
 306+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 307+ * Dual licensed under the MIT or GPL Version 2 licenses.
 308+ * http://jquery.org/license
 309+ *
 310+ * http://docs.jquery.com/UI/Tabs#theming
 311+ */
 312+.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
 313+.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
 314+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
 315+.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
 316+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
 317+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
 318+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
 319+.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
 320+.ui-tabs .ui-tabs-hide { display: none !important; }
 321+/*
 322+ * jQuery UI CSS Framework 1.8.10
 323+ *
 324+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 325+ * Dual licensed under the MIT or GPL Version 2 licenses.
 326+ * http://jquery.org/license
 327+ *
 328+ * http://docs.jquery.com/UI/Theming/API
 329+ *
 330+ * To view and modify this theme, visit http://jqueryui.com/themeroller/
 331+ */
 332+
 333+
 334+/* Component containers
 335+----------------------------------*/
 336+.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; }
 337+.ui-widget .ui-widget { font-size: 1em; }
 338+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; }
 339+.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; }
 340+.ui-widget-content a { color: #222222/*{fcContent}*/; }
 341+.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; }
 342+.ui-widget-header a { color: #222222/*{fcHeader}*/; }
 343+
 344+/* Interaction states
 345+----------------------------------*/
 346+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }
 347+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; }
 348+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; }
 349+.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; }
 350+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; }
 351+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; }
 352+.ui-widget :active { outline: none; }
 353+
 354+/* Interaction Cues
 355+----------------------------------*/
 356+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; }
 357+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; }
 358+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; }
 359+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; }
 360+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; }
 361+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
 362+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
 363+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
 364+
 365+/* Icons
 366+----------------------------------*/
 367+
 368+/* states and images */
 369+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
 370+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
 371+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; }
 372+.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; }
 373+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; }
 374+.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; }
 375+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; }
 376+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; }
 377+
 378+/* positioning */
 379+.ui-icon-carat-1-n { background-position: 0 0; }
 380+.ui-icon-carat-1-ne { background-position: -16px 0; }
 381+.ui-icon-carat-1-e { background-position: -32px 0; }
 382+.ui-icon-carat-1-se { background-position: -48px 0; }
 383+.ui-icon-carat-1-s { background-position: -64px 0; }
 384+.ui-icon-carat-1-sw { background-position: -80px 0; }
 385+.ui-icon-carat-1-w { background-position: -96px 0; }
 386+.ui-icon-carat-1-nw { background-position: -112px 0; }
 387+.ui-icon-carat-2-n-s { background-position: -128px 0; }
 388+.ui-icon-carat-2-e-w { background-position: -144px 0; }
 389+.ui-icon-triangle-1-n { background-position: 0 -16px; }
 390+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
 391+.ui-icon-triangle-1-e { background-position: -32px -16px; }
 392+.ui-icon-triangle-1-se { background-position: -48px -16px; }
 393+.ui-icon-triangle-1-s { background-position: -64px -16px; }
 394+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
 395+.ui-icon-triangle-1-w { background-position: -96px -16px; }
 396+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
 397+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
 398+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
 399+.ui-icon-arrow-1-n { background-position: 0 -32px; }
 400+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
 401+.ui-icon-arrow-1-e { background-position: -32px -32px; }
 402+.ui-icon-arrow-1-se { background-position: -48px -32px; }
 403+.ui-icon-arrow-1-s { background-position: -64px -32px; }
 404+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
 405+.ui-icon-arrow-1-w { background-position: -96px -32px; }
 406+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
 407+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
 408+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
 409+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
 410+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
 411+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
 412+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
 413+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
 414+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
 415+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
 416+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
 417+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
 418+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
 419+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
 420+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
 421+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
 422+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
 423+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
 424+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
 425+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
 426+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
 427+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
 428+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
 429+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
 430+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
 431+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
 432+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
 433+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
 434+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
 435+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
 436+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
 437+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
 438+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
 439+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
 440+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
 441+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
 442+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
 443+.ui-icon-arrow-4 { background-position: 0 -80px; }
 444+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
 445+.ui-icon-extlink { background-position: -32px -80px; }
 446+.ui-icon-newwin { background-position: -48px -80px; }
 447+.ui-icon-refresh { background-position: -64px -80px; }
 448+.ui-icon-shuffle { background-position: -80px -80px; }
 449+.ui-icon-transfer-e-w { background-position: -96px -80px; }
 450+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
 451+.ui-icon-folder-collapsed { background-position: 0 -96px; }
 452+.ui-icon-folder-open { background-position: -16px -96px; }
 453+.ui-icon-document { background-position: -32px -96px; }
 454+.ui-icon-document-b { background-position: -48px -96px; }
 455+.ui-icon-note { background-position: -64px -96px; }
 456+.ui-icon-mail-closed { background-position: -80px -96px; }
 457+.ui-icon-mail-open { background-position: -96px -96px; }
 458+.ui-icon-suitcase { background-position: -112px -96px; }
 459+.ui-icon-comment { background-position: -128px -96px; }
 460+.ui-icon-person { background-position: -144px -96px; }
 461+.ui-icon-print { background-position: -160px -96px; }
 462+.ui-icon-trash { background-position: -176px -96px; }
 463+.ui-icon-locked { background-position: -192px -96px; }
 464+.ui-icon-unlocked { background-position: -208px -96px; }
 465+.ui-icon-bookmark { background-position: -224px -96px; }
 466+.ui-icon-tag { background-position: -240px -96px; }
 467+.ui-icon-home { background-position: 0 -112px; }
 468+.ui-icon-flag { background-position: -16px -112px; }
 469+.ui-icon-calendar { background-position: -32px -112px; }
 470+.ui-icon-cart { background-position: -48px -112px; }
 471+.ui-icon-pencil { background-position: -64px -112px; }
 472+.ui-icon-clock { background-position: -80px -112px; }
 473+.ui-icon-disk { background-position: -96px -112px; }
 474+.ui-icon-calculator { background-position: -112px -112px; }
 475+.ui-icon-zoomin { background-position: -128px -112px; }
 476+.ui-icon-zoomout { background-position: -144px -112px; }
 477+.ui-icon-search { background-position: -160px -112px; }
 478+.ui-icon-wrench { background-position: -176px -112px; }
 479+.ui-icon-gear { background-position: -192px -112px; }
 480+.ui-icon-heart { background-position: -208px -112px; }
 481+.ui-icon-star { background-position: -224px -112px; }
 482+.ui-icon-link { background-position: -240px -112px; }
 483+.ui-icon-cancel { background-position: 0 -128px; }
 484+.ui-icon-plus { background-position: -16px -128px; }
 485+.ui-icon-plusthick { background-position: -32px -128px; }
 486+.ui-icon-minus { background-position: -48px -128px; }
 487+.ui-icon-minusthick { background-position: -64px -128px; }
 488+.ui-icon-close { background-position: -80px -128px; }
 489+.ui-icon-closethick { background-position: -96px -128px; }
 490+.ui-icon-key { background-position: -112px -128px; }
 491+.ui-icon-lightbulb { background-position: -128px -128px; }
 492+.ui-icon-scissors { background-position: -144px -128px; }
 493+.ui-icon-clipboard { background-position: -160px -128px; }
 494+.ui-icon-copy { background-position: -176px -128px; }
 495+.ui-icon-contact { background-position: -192px -128px; }
 496+.ui-icon-image { background-position: -208px -128px; }
 497+.ui-icon-video { background-position: -224px -128px; }
 498+.ui-icon-script { background-position: -240px -128px; }
 499+.ui-icon-alert { background-position: 0 -144px; }
 500+.ui-icon-info { background-position: -16px -144px; }
 501+.ui-icon-notice { background-position: -32px -144px; }
 502+.ui-icon-help { background-position: -48px -144px; }
 503+.ui-icon-check { background-position: -64px -144px; }
 504+.ui-icon-bullet { background-position: -80px -144px; }
 505+.ui-icon-radio-off { background-position: -96px -144px; }
 506+.ui-icon-radio-on { background-position: -112px -144px; }
 507+.ui-icon-pin-w { background-position: -128px -144px; }
 508+.ui-icon-pin-s { background-position: -144px -144px; }
 509+.ui-icon-play { background-position: 0 -160px; }
 510+.ui-icon-pause { background-position: -16px -160px; }
 511+.ui-icon-seek-next { background-position: -32px -160px; }
 512+.ui-icon-seek-prev { background-position: -48px -160px; }
 513+.ui-icon-seek-end { background-position: -64px -160px; }
 514+.ui-icon-seek-start { background-position: -80px -160px; }
 515+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
 516+.ui-icon-seek-first { background-position: -80px -160px; }
 517+.ui-icon-stop { background-position: -96px -160px; }
 518+.ui-icon-eject { background-position: -112px -160px; }
 519+.ui-icon-volume-off { background-position: -128px -160px; }
 520+.ui-icon-volume-on { background-position: -144px -160px; }
 521+.ui-icon-power { background-position: 0 -176px; }
 522+.ui-icon-signal-diag { background-position: -16px -176px; }
 523+.ui-icon-signal { background-position: -32px -176px; }
 524+.ui-icon-battery-0 { background-position: -48px -176px; }
 525+.ui-icon-battery-1 { background-position: -64px -176px; }
 526+.ui-icon-battery-2 { background-position: -80px -176px; }
 527+.ui-icon-battery-3 { background-position: -96px -176px; }
 528+.ui-icon-circle-plus { background-position: 0 -192px; }
 529+.ui-icon-circle-minus { background-position: -16px -192px; }
 530+.ui-icon-circle-close { background-position: -32px -192px; }
 531+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
 532+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
 533+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
 534+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
 535+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
 536+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
 537+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
 538+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
 539+.ui-icon-circle-zoomin { background-position: -176px -192px; }
 540+.ui-icon-circle-zoomout { background-position: -192px -192px; }
 541+.ui-icon-circle-check { background-position: -208px -192px; }
 542+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
 543+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
 544+.ui-icon-circlesmall-close { background-position: -32px -208px; }
 545+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
 546+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
 547+.ui-icon-squaresmall-close { background-position: -80px -208px; }
 548+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
 549+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
 550+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
 551+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
 552+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
 553+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
 554+
 555+
 556+/* Misc visuals
 557+----------------------------------*/
 558+
 559+/* Corner radius */
 560+.ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; }
 561+.ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; }
 562+.ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; }
 563+.ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
 564+.ui-corner-top { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; }
 565+.ui-corner-bottom { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
 566+.ui-corner-right { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
 567+.ui-corner-left { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; }
 568+.ui-corner-all { -moz-border-radius: 4px/*{cornerRadius}*/; -webkit-border-radius: 4px/*{cornerRadius}*/; border-radius: 4px/*{cornerRadius}*/; }
 569+
 570+/* Overlays */
 571+.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; }
 572+.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; }
\ No newline at end of file
Index: trunk/extensions/LinkSuggest/LinkSuggest.i18n.php
@@ -0,0 +1,305 @@
 2+<?php
 3+/**
 4+ * Internationalization file for the LinkSuggest extension.
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ */
 9+
 10+$messages = array();
 11+
 12+/** English */
 13+$messages['en'] = array(
 14+ 'tog-disablelinksuggest' => 'Do not show link suggest'
 15+);
 16+
 17+/** Afrikaans (Afrikaans)
 18+ * @author Naudefj
 19+ */
 20+$messages['af'] = array(
 21+ 'tog-disablelinksuggest' => 'Moet nie skakel-voorstelle wys nie',
 22+);
 23+
 24+/** Azerbaijani (Azərbaycanca)
 25+ * @author PPerviz
 26+ */
 27+$messages['az'] = array(
 28+ 'tog-disablelinksuggest' => 'Keçid təklifini göstərmə',
 29+);
 30+
 31+/** Belarusian (Taraškievica orthography) (‪Беларуская (тарашкевіца)‬)
 32+ * @author EugeneZelenko
 33+ */
 34+$messages['be-tarask'] = array(
 35+ 'tog-disablelinksuggest' => 'Не паказваць прапановы спасылак',
 36+);
 37+
 38+/** Breton (Brezhoneg)
 39+ * @author Gwenn-Ael
 40+ */
 41+$messages['br'] = array(
 42+ 'tog-disablelinksuggest' => 'Chomp hep diskouez al liammoù kinniget',
 43+);
 44+
 45+/** Catalan (Català)
 46+ * @author Paucabot
 47+ */
 48+$messages['ca'] = array(
 49+ 'tog-disablelinksuggest' => "No mostris suggeriments d'enllaços",
 50+);
 51+
 52+/** Czech (Česky)
 53+ * @author Mormegil
 54+ */
 55+$messages['cs'] = array(
 56+ 'tog-disablelinksuggest' => 'Nezobrazovat návrhy odkazů',
 57+);
 58+
 59+/** German (Deutsch) */
 60+$messages['de'] = array(
 61+ 'tog-disablelinksuggest' => 'Keine Link-Vorschläge anzeigen',
 62+);
 63+
 64+/** Spanish (Español) */
 65+$messages['es'] = array(
 66+ 'tog-disablelinksuggest' => 'No mostrar sugerencias de vínculos',
 67+);
 68+
 69+/** Finnish (Suomi)
 70+ * @author Centerlink
 71+ */
 72+$messages['fi'] = array(
 73+ 'tog-disablelinksuggest' => 'Älä näytä linkkiehdotuksia',
 74+);
 75+
 76+/** French (Français) */
 77+$messages['fr'] = array(
 78+ 'tog-disablelinksuggest' => 'Ne pas montrer les liens suggérés',
 79+);
 80+
 81+/** Galician (Galego)
 82+ * @author Toliño
 83+ */
 84+$messages['gl'] = array(
 85+ 'tog-disablelinksuggest' => 'Non mostrar as ligazón suxeridas',
 86+);
 87+
 88+/** Manx (Gaelg)
 89+ * @author MacTire02
 90+ */
 91+$messages['gv'] = array(
 92+ 'tog-disablelinksuggest' => 'Ny taishbyney kiangley-choyrlaghey',
 93+);
 94+
 95+/** Hebrew (עברית)
 96+ * @author Rotemliss
 97+ */
 98+$messages['he'] = array(
 99+ 'tog-disablelinksuggest' => 'ביטול הצגת הצעות לקישורים',
 100+);
 101+
 102+/** Upper Sorbian (Hornjoserbsce)
 103+ * @author Michawiki
 104+ */
 105+$messages['hsb'] = array(
 106+ 'tog-disablelinksuggest' => 'Žadyn wotkazowy namjet pokazać',
 107+);
 108+
 109+/** Hungarian (Magyar)
 110+ * @author Glanthor Reviol
 111+ */
 112+$messages['hu'] = array(
 113+ 'tog-disablelinksuggest' => 'Ne jelenítse meg a hivatkozás-javaslatot',
 114+);
 115+
 116+/** Interlingua (Interlingua)
 117+ * @author McDutchie
 118+ */
 119+$messages['ia'] = array(
 120+ 'tog-disablelinksuggest' => 'Non monstrar suggestiones de ligamines',
 121+);
 122+
 123+/** Indonesian (Bahasa Indonesia)
 124+ * @author Bennylin
 125+ */
 126+$messages['id'] = array(
 127+ 'tog-disablelinksuggest' => 'Jangan menampilkan saran pranala',
 128+);
 129+
 130+/** Italian (Italiano)
 131+ * @author Civvì
 132+ */
 133+$messages['it'] = array(
 134+ 'tog-disablelinksuggest' => 'Non mostrare link suggeriti',
 135+);
 136+
 137+/** Japanese (日本語) */
 138+$messages['ja'] = array(
 139+ 'tog-disablelinksuggest' => '編集時のリンク補完を使わない',
 140+);
 141+
 142+/** Colognian (Ripoarisch)
 143+ * @author Purodha
 144+ */
 145+$messages['ksh'] = array(
 146+ 'tog-disablelinksuggest' => 'Donn kein Vörschlääsch för Lenks aanzeije',
 147+);
 148+
 149+/** Luxembourgish (Lëtzebuergesch)
 150+ * @author Robby
 151+ */
 152+$messages['lb'] = array(
 153+ 'tog-disablelinksuggest' => 'Déi proposéiert Linken net weisen',
 154+);
 155+
 156+/** Latvian (Latviešu)
 157+ * @author Xil
 158+ */
 159+$messages['lv'] = array(
 160+ 'tog-disablelinksuggest' => 'Neradīt saišu ieteikumus',
 161+);
 162+
 163+/** Macedonian (Македонски)
 164+ * @author Bjankuloski06
 165+ */
 166+$messages['mk'] = array(
 167+ 'tog-disablelinksuggest' => 'Не прикажувај предложени врски',
 168+);
 169+
 170+/** Dutch (Nederlands)
 171+ * @author Siebrand
 172+ */
 173+$messages['nl'] = array(
 174+ 'tog-disablelinksuggest' => 'Geen verwijzigssuggesties weergeven',
 175+);
 176+
 177+/** Norwegian Nynorsk (‪Norsk (nynorsk)‬)
 178+ * @author Harald Khan
 179+ */
 180+$messages['nn'] = array(
 181+ 'tog-disablelinksuggest' => 'Ikkje vis lenkjeframlegg',
 182+);
 183+
 184+/** Norwegian (bokmål)‬ (‪Norsk (bokmål)‬)
 185+ * @author Jon Harald Søby
 186+ */
 187+$messages['no'] = array(
 188+ 'tog-disablelinksuggest' => 'Ikke vis lenkeforslag',
 189+);
 190+
 191+/** Occitan (Occitan)
 192+ * @author Cedric31
 193+ */
 194+$messages['oc'] = array(
 195+ 'tog-disablelinksuggest' => 'Far pas veire los ligams suggerits',
 196+);
 197+
 198+/** Polish (Polski)
 199+ * @author Sp5uhe
 200+ */
 201+$messages['pl'] = array(
 202+ 'tog-disablelinksuggest' => 'Nie pokazuj sugerowanych linków',
 203+);
 204+
 205+/** Piedmontese (Piemontèis)
 206+ * @author Borichèt
 207+ */
 208+$messages['pms'] = array(
 209+ 'tog-disablelinksuggest' => "Mostra pa ij sugeriment ëd j'anliure",
 210+);
 211+
 212+/** Pashto (پښتو)
 213+ * @author Ahmed-Najib-Biabani-Ibrahimkhel
 214+ */
 215+$messages['ps'] = array(
 216+ 'tog-disablelinksuggest' => 'د تړنې وړانديز مه ښکاره کوه',
 217+);
 218+
 219+/** Portuguese (Português)
 220+ * @author Hamilton Abreu
 221+ */
 222+$messages['pt'] = array(
 223+ 'tog-disablelinksuggest' => 'Não apresentar sugestões de links',
 224+);
 225+
 226+/** Brazilian Portuguese (Português do Brasil)
 227+ * @author Daemorris
 228+ */
 229+$messages['pt-br'] = array(
 230+ 'tog-disablelinksuggest' => 'Não mostrar sugestões de ligação',
 231+);
 232+
 233+/** Tarandíne (Tarandíne)
 234+ * @author Joetaras
 235+ */
 236+$messages['roa-tara'] = array(
 237+ 'tog-disablelinksuggest' => "No fà vedè 'u collegamende suggerite",
 238+);
 239+
 240+/** Russian (Русский) */
 241+$messages['ru'] = array(
 242+ 'tog-disablelinksuggest' => 'Не показывать предложения ссылок',
 243+);
 244+
 245+/** Serbian Cyrillic ekavian (‪Српски (ћирилица)‬)
 246+ * @author Rancher
 247+ * @author Verlor
 248+ */
 249+$messages['sr-ec'] = array(
 250+ 'tog-disablelinksuggest' => 'Не приказуј предложену везу',
 251+);
 252+
 253+/** Sundanese (Basa Sunda)
 254+ * @author Kandar
 255+ */
 256+$messages['su'] = array(
 257+ 'tog-disablelinksuggest' => 'Sumputkeun usulan tutumbu',
 258+);
 259+
 260+/** Swedish (Svenska)
 261+ * @author Sertion
 262+ */
 263+$messages['sv'] = array(
 264+ 'tog-disablelinksuggest' => 'Visa inte länkförslag',
 265+);
 266+
 267+/** Tagalog (Tagalog)
 268+ * @author AnakngAraw
 269+ */
 270+$messages['tl'] = array(
 271+ 'tog-disablelinksuggest' => 'Huwag ipakita ang mungkahing kawing',
 272+);
 273+
 274+/** Turkish (Türkçe)
 275+ * @author Manco Capac
 276+ */
 277+$messages['tr'] = array(
 278+ 'tog-disablelinksuggest' => 'Bağlantı önermesini gösterme',
 279+);
 280+
 281+/** Tatar (Cyrillic) (Татарча/Tatarça (Cyrillic))
 282+ * @author Ильнар
 283+ */
 284+$messages['tt-cyrl'] = array(
 285+ 'tog-disablelinksuggest' => 'Сылтамаларны күрсәтмәскә',
 286+);
 287+
 288+/** Ukrainian (Українська) */
 289+$messages['uk'] = array(
 290+ 'tog-disablelinksuggest' => 'Не показувати пропозиції посилань',
 291+);
 292+
 293+/** Simplified Chinese (‪中文(简体)‬)
 294+ * @author Hydra
 295+ */
 296+$messages['zh-hans'] = array(
 297+ 'tog-disablelinksuggest' => '不会显示链接建议',
 298+);
 299+
 300+/** Traditional Chinese (‪中文(繁體)‬)
 301+ * @author Frankou
 302+ */
 303+$messages['zh-hant'] = array(
 304+ 'tog-disablelinksuggest' => '不顯示鏈接建議',
 305+);
 306+
Index: trunk/extensions/LinkSuggest/jquery.widget.position.autocomplete-1.8.2.js
@@ -0,0 +1,1201 @@
 2+// https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.js
 3+
 4+/*!
 5+ * jQuery UI 1.8.2
 6+ *
 7+ * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
 8+ * Dual licensed under the MIT (MIT-LICENSE.txt)
 9+ * and GPL (GPL-LICENSE.txt) licenses.
 10+ *
 11+ * http://docs.jquery.com/UI
 12+ */
 13+
 14+(function($) {
 15+
 16+// prevent duplicate loading
 17+// this is only a problem because we proxy existing functions
 18+// and we don't want to double proxy them
 19+$.ui = $.ui || {};
 20+if ($.ui.version) {
 21+ return;
 22+}
 23+
 24+//Helper functions and ui object
 25+$.extend($.ui, {
 26+ version: "1.8.2",
 27+
 28+ // $.ui.plugin is deprecated. Use the proxy pattern instead.
 29+ plugin: {
 30+ add: function(module, option, set) {
 31+ var proto = $.ui[module].prototype;
 32+ for(var i in set) {
 33+ proto.plugins[i] = proto.plugins[i] || [];
 34+ proto.plugins[i].push([option, set[i]]);
 35+ }
 36+ },
 37+ call: function(instance, name, args) {
 38+ var set = instance.plugins[name];
 39+ if(!set || !instance.element[0].parentNode) { return; }
 40+
 41+ for (var i = 0; i < set.length; i++) {
 42+ if (instance.options[set[i][0]]) {
 43+ set[i][1].apply(instance.element, args);
 44+ }
 45+ }
 46+ }
 47+ },
 48+
 49+ contains: function(a, b) {
 50+ return document.compareDocumentPosition
 51+ ? a.compareDocumentPosition(b) & 16
 52+ : a !== b && a.contains(b);
 53+ },
 54+
 55+ hasScroll: function(el, a) {
 56+
 57+ //If overflow is hidden, the element might have extra content, but the user wants to hide it
 58+ if ($(el).css('overflow') == 'hidden') { return false; }
 59+
 60+ var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop',
 61+ has = false;
 62+
 63+ if (el[scroll] > 0) { return true; }
 64+
 65+ // TODO: determine which cases actually cause this to happen
 66+ // if the element doesn't have the scroll set, see if it's possible to
 67+ // set the scroll
 68+ el[scroll] = 1;
 69+ has = (el[scroll] > 0);
 70+ el[scroll] = 0;
 71+ return has;
 72+ },
 73+
 74+ isOverAxis: function(x, reference, size) {
 75+ //Determines when x coordinate is over "b" element axis
 76+ return (x > reference) && (x < (reference + size));
 77+ },
 78+
 79+ isOver: function(y, x, top, left, height, width) {
 80+ //Determines when x, y coordinates is over "b" element
 81+ return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width);
 82+ },
 83+
 84+ keyCode: {
 85+ ALT: 18,
 86+ BACKSPACE: 8,
 87+ CAPS_LOCK: 20,
 88+ COMMA: 188,
 89+ COMMAND: 91,
 90+ COMMAND_LEFT: 91, // COMMAND
 91+ COMMAND_RIGHT: 93,
 92+ CONTROL: 17,
 93+ DELETE: 46,
 94+ DOWN: 40,
 95+ END: 35,
 96+ ENTER: 13,
 97+ ESCAPE: 27,
 98+ HOME: 36,
 99+ INSERT: 45,
 100+ LEFT: 37,
 101+ MENU: 93, // COMMAND_RIGHT
 102+ NUMPAD_ADD: 107,
 103+ NUMPAD_DECIMAL: 110,
 104+ NUMPAD_DIVIDE: 111,
 105+ NUMPAD_ENTER: 108,
 106+ NUMPAD_MULTIPLY: 106,
 107+ NUMPAD_SUBTRACT: 109,
 108+ PAGE_DOWN: 34,
 109+ PAGE_UP: 33,
 110+ PERIOD: 190,
 111+ RIGHT: 39,
 112+ SHIFT: 16,
 113+ SPACE: 32,
 114+ TAB: 9,
 115+ UP: 38,
 116+ WINDOWS: 91 // COMMAND
 117+ }
 118+});
 119+
 120+//jQuery plugins
 121+$.fn.extend({
 122+ _focus: $.fn.focus,
 123+ focus: function(delay, fn) {
 124+ return typeof delay === 'number'
 125+ ? this.each(function() {
 126+ var elem = this;
 127+ setTimeout(function() {
 128+ $(elem).focus();
 129+ (fn && fn.call(elem));
 130+ }, delay);
 131+ })
 132+ : this._focus.apply(this, arguments);
 133+ },
 134+
 135+ enableSelection: function() {
 136+ return this
 137+ .attr('unselectable', 'off')
 138+ .css('MozUserSelect', '');
 139+ },
 140+
 141+ disableSelection: function() {
 142+ return this
 143+ .attr('unselectable', 'on')
 144+ .css('MozUserSelect', 'none');
 145+ },
 146+
 147+ scrollParent: function() {
 148+ var scrollParent;
 149+ if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
 150+ scrollParent = this.parents().filter(function() {
 151+ return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
 152+ }).eq(0);
 153+ } else {
 154+ scrollParent = this.parents().filter(function() {
 155+ return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
 156+ }).eq(0);
 157+ }
 158+
 159+ return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
 160+ },
 161+
 162+ zIndex: function(zIndex) {
 163+ if (zIndex !== undefined) {
 164+ return this.css('zIndex', zIndex);
 165+ }
 166+
 167+ if (this.length) {
 168+ var elem = $(this[0]), position, value;
 169+ while (elem.length && elem[0] !== document) {
 170+ // Ignore z-index if position is set to a value where z-index is ignored by the browser
 171+ // This makes behavior of this function consistent across browsers
 172+ // WebKit always returns auto if the element is positioned
 173+ position = elem.css('position');
 174+ if (position == 'absolute' || position == 'relative' || position == 'fixed')
 175+ {
 176+ // IE returns 0 when zIndex is not specified
 177+ // other browsers return a string
 178+ // we ignore the case of nested elements with an explicit value of 0
 179+ // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
 180+ value = parseInt(elem.css('zIndex'));
 181+ if (!isNaN(value) && value != 0) {
 182+ return value;
 183+ }
 184+ }
 185+ elem = elem.parent();
 186+ }
 187+ }
 188+
 189+ return 0;
 190+ }
 191+});
 192+
 193+
 194+//Additional selectors
 195+$.extend($.expr[':'], {
 196+ data: function(elem, i, match) {
 197+ return !!$.data(elem, match[3]);
 198+ },
 199+
 200+ focusable: function(element) {
 201+ var nodeName = element.nodeName.toLowerCase(),
 202+ tabIndex = $.attr(element, 'tabindex');
 203+ return (/input|select|textarea|button|object/.test(nodeName)
 204+ ? !element.disabled
 205+ : 'a' == nodeName || 'area' == nodeName
 206+ ? element.href || !isNaN(tabIndex)
 207+ : !isNaN(tabIndex))
 208+ // the element and all of its ancestors must be visible
 209+ // the browser may report that the area is hidden
 210+ && !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length;
 211+ },
 212+
 213+ tabbable: function(element) {
 214+ var tabIndex = $.attr(element, 'tabindex');
 215+ return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable');
 216+ }
 217+});
 218+
 219+})(jQuery);
 220+/*!
 221+ * jQuery UI Widget 1.8.2
 222+ *
 223+ * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
 224+ * Dual licensed under the MIT (MIT-LICENSE.txt)
 225+ * and GPL (GPL-LICENSE.txt) licenses.
 226+ *
 227+ * http://docs.jquery.com/UI/Widget
 228+ */
 229+(function( $ ) {
 230+
 231+var _remove = $.fn.remove;
 232+
 233+$.fn.remove = function( selector, keepData ) {
 234+ return this.each(function() {
 235+ if ( !keepData ) {
 236+ if ( !selector || $.filter( selector, [ this ] ).length ) {
 237+ $( "*", this ).add( this ).each(function() {
 238+ $( this ).triggerHandler( "remove" );
 239+ });
 240+ }
 241+ }
 242+ return _remove.call( $(this), selector, keepData );
 243+ });
 244+};
 245+
 246+$.widget = function( name, base, prototype ) {
 247+ var namespace = name.split( "." )[ 0 ],
 248+ fullName;
 249+ name = name.split( "." )[ 1 ];
 250+ fullName = namespace + "-" + name;
 251+
 252+ if ( !prototype ) {
 253+ prototype = base;
 254+ base = $.Widget;
 255+ }
 256+
 257+ // create selector for plugin
 258+ $.expr[ ":" ][ fullName ] = function( elem ) {
 259+ return !!$.data( elem, name );
 260+ };
 261+
 262+ $[ namespace ] = $[ namespace ] || {};
 263+ $[ namespace ][ name ] = function( options, element ) {
 264+ // allow instantiation without initializing for simple inheritance
 265+ if ( arguments.length ) {
 266+ this._createWidget( options, element );
 267+ }
 268+ };
 269+
 270+ var basePrototype = new base();
 271+ // we need to make the options hash a property directly on the new instance
 272+ // otherwise we'll modify the options hash on the prototype that we're
 273+ // inheriting from
 274+// $.each( basePrototype, function( key, val ) {
 275+// if ( $.isPlainObject(val) ) {
 276+// basePrototype[ key ] = $.extend( {}, val );
 277+// }
 278+// });
 279+ basePrototype.options = $.extend( {}, basePrototype.options );
 280+ $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
 281+ namespace: namespace,
 282+ widgetName: name,
 283+ widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
 284+ widgetBaseClass: fullName
 285+ }, prototype );
 286+
 287+ $.widget.bridge( name, $[ namespace ][ name ] );
 288+};
 289+
 290+$.widget.bridge = function( name, object ) {
 291+ $.fn[ name ] = function( options ) {
 292+ var isMethodCall = typeof options === "string",
 293+ args = Array.prototype.slice.call( arguments, 1 ),
 294+ returnValue = this;
 295+
 296+ // allow multiple hashes to be passed on init
 297+ options = !isMethodCall && args.length ?
 298+ $.extend.apply( null, [ true, options ].concat(args) ) :
 299+ options;
 300+
 301+ // prevent calls to internal methods
 302+ if ( isMethodCall && options.substring( 0, 1 ) === "_" ) {
 303+ return returnValue;
 304+ }
 305+
 306+ if ( isMethodCall ) {
 307+ this.each(function() {
 308+ var instance = $.data( this, name ),
 309+ methodValue = instance && $.isFunction( instance[options] ) ?
 310+ instance[ options ].apply( instance, args ) :
 311+ instance;
 312+ if ( methodValue !== instance && methodValue !== undefined ) {
 313+ returnValue = methodValue;
 314+ return false;
 315+ }
 316+ });
 317+ } else {
 318+ this.each(function() {
 319+ var instance = $.data( this, name );
 320+ if ( instance ) {
 321+ if ( options ) {
 322+ instance.option( options );
 323+ }
 324+ instance._init();
 325+ } else {
 326+ $.data( this, name, new object( options, this ) );
 327+ }
 328+ });
 329+ }
 330+
 331+ return returnValue;
 332+ };
 333+};
 334+
 335+$.Widget = function( options, element ) {
 336+ // allow instantiation without initializing for simple inheritance
 337+ if ( arguments.length ) {
 338+ this._createWidget( options, element );
 339+ }
 340+};
 341+
 342+$.Widget.prototype = {
 343+ widgetName: "widget",
 344+ widgetEventPrefix: "",
 345+ options: {
 346+ disabled: false
 347+ },
 348+ _createWidget: function( options, element ) {
 349+ // $.widget.bridge stores the plugin instance, but we do it anyway
 350+ // so that it's stored even before the _create function runs
 351+ this.element = $( element ).data( this.widgetName, this );
 352+ this.options = $.extend( true, {},
 353+ this.options,
 354+ $.metadata && $.metadata.get( element )[ this.widgetName ],
 355+ options );
 356+
 357+ var self = this;
 358+ this.element.bind( "remove." + this.widgetName, function() {
 359+ self.destroy();
 360+ });
 361+
 362+ this._create();
 363+ this._init();
 364+ },
 365+ _create: function() {},
 366+ _init: function() {},
 367+
 368+ destroy: function() {
 369+ this.element
 370+ .unbind( "." + this.widgetName )
 371+ .removeData( this.widgetName );
 372+ this.widget()
 373+ .unbind( "." + this.widgetName )
 374+ .removeAttr( "aria-disabled" )
 375+ .removeClass(
 376+ this.widgetBaseClass + "-disabled " +
 377+ "ui-state-disabled" );
 378+ },
 379+
 380+ widget: function() {
 381+ return this.element;
 382+ },
 383+
 384+ option: function( key, value ) {
 385+ var options = key,
 386+ self = this;
 387+
 388+ if ( arguments.length === 0 ) {
 389+ // don't return a reference to the internal hash
 390+ return $.extend( {}, self.options );
 391+ }
 392+
 393+ if (typeof key === "string" ) {
 394+ if ( value === undefined ) {
 395+ return this.options[ key ];
 396+ }
 397+ options = {};
 398+ options[ key ] = value;
 399+ }
 400+
 401+ $.each( options, function( key, value ) {
 402+ self._setOption( key, value );
 403+ });
 404+
 405+ return self;
 406+ },
 407+ _setOption: function( key, value ) {
 408+ this.options[ key ] = value;
 409+
 410+ if ( key === "disabled" ) {
 411+ this.widget()
 412+ [ value ? "addClass" : "removeClass"](
 413+ this.widgetBaseClass + "-disabled" + " " +
 414+ "ui-state-disabled" )
 415+ .attr( "aria-disabled", value );
 416+ }
 417+
 418+ return this;
 419+ },
 420+
 421+ enable: function() {
 422+ return this._setOption( "disabled", false );
 423+ },
 424+ disable: function() {
 425+ return this._setOption( "disabled", true );
 426+ },
 427+
 428+ _trigger: function( type, event, data ) {
 429+ var callback = this.options[ type ];
 430+
 431+ event = $.Event( event );
 432+ event.type = ( type === this.widgetEventPrefix ?
 433+ type :
 434+ this.widgetEventPrefix + type ).toLowerCase();
 435+ data = data || {};
 436+
 437+ // copy original event properties over to the new event
 438+ // this would happen if we could call $.event.fix instead of $.Event
 439+ // but we don't have a way to force an event to be fixed multiple times
 440+ if ( event.originalEvent ) {
 441+ for ( var i = $.event.props.length, prop; i; ) {
 442+ prop = $.event.props[ --i ];
 443+ event[ prop ] = event.originalEvent[ prop ];
 444+ }
 445+ }
 446+
 447+ this.element.trigger( event, data );
 448+
 449+ return !( $.isFunction(callback) &&
 450+ callback.call( this.element[0], event, data ) === false ||
 451+ event.isDefaultPrevented() );
 452+ }
 453+};
 454+
 455+})( jQuery );
 456+
 457+/*
 458+ * jQuery UI Menu (not officially released)
 459+ *
 460+ * This widget isn't yet finished and the API is subject to change. We plan to finish
 461+ * it for the next release. You're welcome to give it a try anyway and give us feedback,
 462+ * as long as you're okay with migrating your code later on. We can help with that, too.
 463+ *
 464+ * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
 465+ * Dual licensed under the MIT (MIT-LICENSE.txt)
 466+ * and GPL (GPL-LICENSE.txt) licenses.
 467+ *
 468+ * http://docs.jquery.com/UI/Menu
 469+ *
 470+ * Depends:
 471+ * jquery.ui.core.js
 472+ * jquery.ui.widget.js
 473+ */
 474+(function($) {
 475+
 476+$.widget("ui.menu", {
 477+ _create: function() {
 478+ var self = this;
 479+ this.element
 480+ .addClass("ui-menu ui-widget ui-widget-content ui-corner-all")
 481+ .attr({
 482+ role: "listbox",
 483+ "aria-activedescendant": "ui-active-menuitem"
 484+ })
 485+ .click(function( event ) {
 486+ if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) {
 487+ return;
 488+ }
 489+ // temporary
 490+ event.preventDefault();
 491+ self.select( event );
 492+ });
 493+ this.refresh();
 494+ },
 495+
 496+ refresh: function() {
 497+ var self = this;
 498+
 499+ // don't refresh list items that are already adapted
 500+ var items = this.element.children("li:not(.ui-menu-item):has(a)")
 501+ .addClass("ui-menu-item")
 502+ .attr("role", "menuitem");
 503+
 504+ items.children("a")
 505+ .addClass("ui-corner-all")
 506+ .attr("tabindex", -1)
 507+ // mouseenter doesn't work with event delegation
 508+ .mouseenter(function( event ) {
 509+ self.activate( event, $(this).parent() );
 510+ })
 511+ .mouseleave(function() {
 512+ self.deactivate();
 513+ });
 514+ },
 515+
 516+ activate: function( event, item ) {
 517+ this.deactivate();
 518+ if (this.hasScroll()) {
 519+ var offset = item.offset().top - this.element.offset().top,
 520+ scroll = this.element.attr("scrollTop"),
 521+ elementHeight = this.element.height();
 522+ if (offset < 0) {
 523+ this.element.attr("scrollTop", scroll + offset);
 524+ } else if (offset > elementHeight) {
 525+ this.element.attr("scrollTop", scroll + offset - elementHeight + item.height());
 526+ }
 527+ }
 528+ this.active = item.eq(0)
 529+ .children("a")
 530+ .addClass("ui-state-hover")
 531+ .attr("id", "ui-active-menuitem")
 532+ .end();
 533+ this._trigger("focus", event, { item: item });
 534+ },
 535+
 536+ deactivate: function() {
 537+ if (!this.active) { return; }
 538+
 539+ this.active.children("a")
 540+ .removeClass("ui-state-hover")
 541+ .removeAttr("id");
 542+ this._trigger("blur");
 543+ this.active = null;
 544+ },
 545+
 546+ next: function(event) {
 547+ this.move("next", ".ui-menu-item:first", event);
 548+ },
 549+
 550+ previous: function(event) {
 551+ this.move("prev", ".ui-menu-item:last", event);
 552+ },
 553+
 554+ first: function() {
 555+ return this.active && !this.active.prev().length;
 556+ },
 557+
 558+ last: function() {
 559+ return this.active && !this.active.next().length;
 560+ },
 561+
 562+ move: function(direction, edge, event) {
 563+ if (!this.active) {
 564+ this.activate(event, this.element.children(edge));
 565+ return;
 566+ }
 567+ var next = this.active[direction + "All"](".ui-menu-item").eq(0);
 568+ if (next.length) {
 569+ this.activate(event, next);
 570+ } else {
 571+ this.activate(event, this.element.children(edge));
 572+ }
 573+ },
 574+
 575+ // TODO merge with previousPage
 576+ nextPage: function(event) {
 577+ if (this.hasScroll()) {
 578+ // TODO merge with no-scroll-else
 579+ if (!this.active || this.last()) {
 580+ this.activate(event, this.element.children(":first"));
 581+ return;
 582+ }
 583+ var base = this.active.offset().top,
 584+ height = this.element.height(),
 585+ result = this.element.children("li").filter(function() {
 586+ var close = $(this).offset().top - base - height + $(this).height();
 587+ // TODO improve approximation
 588+ return close < 10 && close > -10;
 589+ });
 590+
 591+ // TODO try to catch this earlier when scrollTop indicates the last page anyway
 592+ if (!result.length) {
 593+ result = this.element.children(":last");
 594+ }
 595+ this.activate(event, result);
 596+ } else {
 597+ this.activate(event, this.element.children(!this.active || this.last() ? ":first" : ":last"));
 598+ }
 599+ },
 600+
 601+ // TODO merge with nextPage
 602+ previousPage: function(event) {
 603+ if (this.hasScroll()) {
 604+ // TODO merge with no-scroll-else
 605+ if (!this.active || this.first()) {
 606+ this.activate(event, this.element.children(":last"));
 607+ return;
 608+ }
 609+
 610+ var base = this.active.offset().top,
 611+ height = this.element.height();
 612+ result = this.element.children("li").filter(function() {
 613+ var close = $(this).offset().top - base + height - $(this).height();
 614+ // TODO improve approximation
 615+ return close < 10 && close > -10;
 616+ });
 617+
 618+ // TODO try to catch this earlier when scrollTop indicates the last page anyway
 619+ if (!result.length) {
 620+ result = this.element.children(":first");
 621+ }
 622+ this.activate(event, result);
 623+ } else {
 624+ this.activate(event, this.element.children(!this.active || this.first() ? ":last" : ":first"));
 625+ }
 626+ },
 627+
 628+ hasScroll: function() {
 629+ return this.element.height() < this.element.attr("scrollHeight");
 630+ },
 631+
 632+ select: function( event ) {
 633+ this._trigger("selected", event, { item: this.active });
 634+ }
 635+});
 636+
 637+}(jQuery));
 638+
 639+/*
 640+ * jQuery UI Position 1.8.2
 641+ *
 642+ * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
 643+ * Dual licensed under the MIT (MIT-LICENSE.txt)
 644+ * and GPL (GPL-LICENSE.txt) licenses.
 645+ *
 646+ * http://docs.jquery.com/UI/Position
 647+ */
 648+(function( $ ) {
 649+
 650+$.ui = $.ui || {};
 651+
 652+var horizontalPositions = /left|center|right/,
 653+ horizontalDefault = "center",
 654+ verticalPositions = /top|center|bottom/,
 655+ verticalDefault = "center",
 656+ _position = $.fn.position,
 657+ _offset = $.fn.offset;
 658+
 659+$.fn.position = function( options ) {
 660+ if ( !options || !options.of ) {
 661+ return _position.apply( this, arguments );
 662+ }
 663+
 664+ // make a copy, we don't want to modify arguments
 665+ options = $.extend( {}, options );
 666+
 667+ var target = $( options.of ),
 668+ collision = ( options.collision || "flip" ).split( " " ),
 669+ offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ],
 670+ targetWidth,
 671+ targetHeight,
 672+ basePosition;
 673+
 674+ if ( options.of.nodeType === 9 ) {
 675+ targetWidth = target.width();
 676+ targetHeight = target.height();
 677+ basePosition = { top: 0, left: 0 };
 678+ } else if ( options.of.scrollTo && options.of.document ) {
 679+ targetWidth = target.width();
 680+ targetHeight = target.height();
 681+ basePosition = { top: target.scrollTop(), left: target.scrollLeft() };
 682+ } else if ( options.of.preventDefault ) {
 683+ // force left top to allow flipping
 684+ options.at = "left top";
 685+ targetWidth = targetHeight = 0;
 686+ basePosition = { top: options.of.pageY, left: options.of.pageX };
 687+ } else {
 688+ targetWidth = target.outerWidth();
 689+ targetHeight = target.outerHeight();
 690+ basePosition = target.offset();
 691+ }
 692+
 693+ // force my and at to have valid horizontal and veritcal positions
 694+ // if a value is missing or invalid, it will be converted to center
 695+ $.each( [ "my", "at" ], function() {
 696+ var pos = ( options[this] || "" ).split( " " );
 697+ if ( pos.length === 1) {
 698+ pos = horizontalPositions.test( pos[0] ) ?
 699+ pos.concat( [verticalDefault] ) :
 700+ verticalPositions.test( pos[0] ) ?
 701+ [ horizontalDefault ].concat( pos ) :
 702+ [ horizontalDefault, verticalDefault ];
 703+ }
 704+ pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : horizontalDefault;
 705+ pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : verticalDefault;
 706+ options[ this ] = pos;
 707+ });
 708+
 709+ // normalize collision option
 710+ if ( collision.length === 1 ) {
 711+ collision[ 1 ] = collision[ 0 ];
 712+ }
 713+
 714+ // normalize offset option
 715+ offset[ 0 ] = parseInt( offset[0], 10 ) || 0;
 716+ if ( offset.length === 1 ) {
 717+ offset[ 1 ] = offset[ 0 ];
 718+ }
 719+ offset[ 1 ] = parseInt( offset[1], 10 ) || 0;
 720+
 721+ if ( options.at[0] === "right" ) {
 722+ basePosition.left += targetWidth;
 723+ } else if (options.at[0] === horizontalDefault ) {
 724+ basePosition.left += targetWidth / 2;
 725+ }
 726+
 727+ if ( options.at[1] === "bottom" ) {
 728+ basePosition.top += targetHeight;
 729+ } else if ( options.at[1] === verticalDefault ) {
 730+ basePosition.top += targetHeight / 2;
 731+ }
 732+
 733+ basePosition.left += offset[ 0 ];
 734+ basePosition.top += offset[ 1 ];
 735+
 736+ return this.each(function() {
 737+ var elem = $( this ),
 738+ elemWidth = elem.outerWidth(),
 739+ elemHeight = elem.outerHeight(),
 740+ position = $.extend( {}, basePosition );
 741+
 742+ if ( options.my[0] === "right" ) {
 743+ position.left -= elemWidth;
 744+ } else if ( options.my[0] === horizontalDefault ) {
 745+ position.left -= elemWidth / 2;
 746+ }
 747+
 748+ if ( options.my[1] === "bottom" ) {
 749+ position.top -= elemHeight;
 750+ } else if ( options.my[1] === verticalDefault ) {
 751+ position.top -= elemHeight / 2;
 752+ }
 753+
 754+ // prevent fractions (see #5280)
 755+ position.left = parseInt( position.left );
 756+ position.top = parseInt( position.top );
 757+
 758+ $.each( [ "left", "top" ], function( i, dir ) {
 759+ if ( $.ui.position[ collision[i] ] ) {
 760+ $.ui.position[ collision[i] ][ dir ]( position, {
 761+ targetWidth: targetWidth,
 762+ targetHeight: targetHeight,
 763+ elemWidth: elemWidth,
 764+ elemHeight: elemHeight,
 765+ offset: offset,
 766+ my: options.my,
 767+ at: options.at
 768+ });
 769+ }
 770+ });
 771+
 772+ if ( $.fn.bgiframe ) {
 773+ elem.bgiframe();
 774+ }
 775+ elem.offset( $.extend( position, { using: options.using } ) );
 776+ });
 777+};
 778+
 779+$.ui.position = {
 780+ fit: {
 781+ left: function( position, data ) {
 782+ var win = $( window ),
 783+ over = position.left + data.elemWidth - win.width() - win.scrollLeft();
 784+ position.left = over > 0 ? position.left - over : Math.max( 0, position.left );
 785+ },
 786+ top: function( position, data ) {
 787+ var win = $( window ),
 788+ over = position.top + data.elemHeight - win.height() - win.scrollTop();
 789+ position.top = over > 0 ? position.top - over : Math.max( 0, position.top );
 790+ }
 791+ },
 792+
 793+ flip: {
 794+ left: function( position, data ) {
 795+ if ( data.at[0] === "center" ) {
 796+ return;
 797+ }
 798+ var win = $( window ),
 799+ over = position.left + data.elemWidth - win.width() - win.scrollLeft(),
 800+ myOffset = data.my[ 0 ] === "left" ?
 801+ -data.elemWidth :
 802+ data.my[ 0 ] === "right" ?
 803+ data.elemWidth :
 804+ 0,
 805+ offset = -2 * data.offset[ 0 ];
 806+ position.left += position.left < 0 ?
 807+ myOffset + data.targetWidth + offset :
 808+ over > 0 ?
 809+ myOffset - data.targetWidth + offset :
 810+ 0;
 811+ },
 812+ top: function( position, data ) {
 813+ if ( data.at[1] === "center" ) {
 814+ return;
 815+ }
 816+ var win = $( window ),
 817+ over = position.top + data.elemHeight - win.height() - win.scrollTop(),
 818+ myOffset = data.my[ 1 ] === "top" ?
 819+ -data.elemHeight :
 820+ data.my[ 1 ] === "bottom" ?
 821+ data.elemHeight :
 822+ 0,
 823+ atOffset = data.at[ 1 ] === "top" ?
 824+ data.targetHeight :
 825+ -data.targetHeight,
 826+ offset = -2 * data.offset[ 1 ];
 827+ position.top += position.top < 0 ?
 828+ myOffset + data.targetHeight + offset :
 829+ over > 0 ?
 830+ myOffset + atOffset + offset :
 831+ 0;
 832+ }
 833+ }
 834+};
 835+
 836+// offset setter from jQuery 1.4
 837+if ( !$.offset.setOffset ) {
 838+ $.offset.setOffset = function( elem, options ) {
 839+ // set position first, in-case top/left are set even on static elem
 840+ if ( /static/.test( $.curCSS( elem, "position" ) ) ) {
 841+ elem.style.position = "relative";
 842+ }
 843+ var curElem = $( elem ),
 844+ curOffset = curElem.offset(),
 845+ curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0,
 846+ curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0,
 847+ props = {
 848+ top: (options.top - curOffset.top) + curTop,
 849+ left: (options.left - curOffset.left) + curLeft
 850+ };
 851+
 852+ if ( 'using' in options ) {
 853+ options.using.call( elem, props );
 854+ } else {
 855+ curElem.css( props );
 856+ }
 857+ };
 858+
 859+ $.fn.offset = function( options ) {
 860+ var elem = this[ 0 ];
 861+ if ( !elem || !elem.ownerDocument ) { return null; }
 862+ if ( options ) {
 863+ return this.each(function() {
 864+ $.offset.setOffset( this, options );
 865+ });
 866+ }
 867+ return _offset.call( this );
 868+ };
 869+}
 870+
 871+}( jQuery ));
 872+
 873+
 874+/*
 875+ * jQuery UI Autocomplete 1.8.2
 876+ *
 877+ * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
 878+ * Dual licensed under the MIT (MIT-LICENSE.txt)
 879+ * and GPL (GPL-LICENSE.txt) licenses.
 880+ *
 881+ * http://docs.jquery.com/UI/Autocomplete
 882+ *
 883+ * Depends:
 884+ * jquery.ui.core.js
 885+ * jquery.ui.widget.js
 886+ * jquery.ui.position.js
 887+ */
 888+(function( $ ) {
 889+
 890+$.widget( "ui.autocomplete", {
 891+ options: {
 892+ minLength: 1,
 893+ delay: 300
 894+ },
 895+ _create: function() {
 896+ var self = this,
 897+ doc = this.element[ 0 ].ownerDocument;
 898+ this.element
 899+ .addClass( "ui-autocomplete-input" )
 900+ .attr( "autocomplete", "off" )
 901+ // TODO verify these actually work as intended
 902+ .attr({
 903+ role: "textbox",
 904+ "aria-autocomplete": "list",
 905+ "aria-haspopup": "true"
 906+ })
 907+ .bind( "keydown.autocomplete", function( event ) {
 908+ var keyCode = $.ui.keyCode;
 909+ switch( event.keyCode ) {
 910+ case keyCode.PAGE_UP:
 911+ self._move( "previousPage", event );
 912+ break;
 913+ case keyCode.PAGE_DOWN:
 914+ self._move( "nextPage", event );
 915+ break;
 916+ case keyCode.UP:
 917+ self._move( "previous", event );
 918+ // prevent moving cursor to beginning of text field in some browsers
 919+ event.preventDefault();
 920+ break;
 921+ case keyCode.DOWN:
 922+ self._move( "next", event );
 923+ // prevent moving cursor to end of text field in some browsers
 924+ event.preventDefault();
 925+ break;
 926+ case keyCode.ENTER:
 927+ case keyCode.NUMPAD_ENTER:
 928+ // when menu is open or has focus
 929+ if ( self.menu.active ) {
 930+ event.preventDefault();
 931+ }
 932+ //passthrough - ENTER and TAB both select the current element
 933+ case keyCode.TAB:
 934+ if ( !self.menu.active ) {
 935+ return;
 936+ }
 937+ self.menu.select( event );
 938+ break;
 939+ case keyCode.ESCAPE:
 940+ self.element.val( self.term );
 941+ self.close( event );
 942+ break;
 943+ case keyCode.LEFT:
 944+ case keyCode.RIGHT:
 945+ case keyCode.SHIFT:
 946+ case keyCode.CONTROL:
 947+ case keyCode.ALT:
 948+ case keyCode.COMMAND:
 949+ case keyCode.COMMAND_RIGHT:
 950+ case keyCode.INSERT:
 951+ case keyCode.CAPS_LOCK:
 952+ case keyCode.END:
 953+ case keyCode.HOME:
 954+ // ignore metakeys (shift, ctrl, alt)
 955+ break;
 956+ default:
 957+ // keypress is triggered before the input value is changed
 958+ clearTimeout( self.searching );
 959+ self.searching = setTimeout(function() {
 960+ self.search( null, event );
 961+ }, self.options.delay );
 962+ break;
 963+ }
 964+ })
 965+ .bind( "focus.autocomplete", function() {
 966+ self.selectedItem = null;
 967+ self.previous = self.element.val();
 968+ })
 969+ .bind( "blur.autocomplete", function( event ) {
 970+ clearTimeout( self.searching );
 971+ // clicks on the menu (or a button to trigger a search) will cause a blur event
 972+ self.closing = setTimeout(function() {
 973+ self.close( event );
 974+ self._change( event );
 975+ }, 150 );
 976+ });
 977+ this._initSource();
 978+ this.response = function() {
 979+ return self._response.apply( self, arguments );
 980+ };
 981+ this.menu = $( "<ul></ul>" )
 982+ .addClass( "ui-autocomplete" )
 983+ .appendTo( "body", doc )
 984+ // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown)
 985+ .mousedown(function() {
 986+ // use another timeout to make sure the blur-event-handler on the input was already triggered
 987+ setTimeout(function() {
 988+ clearTimeout( self.closing );
 989+ }, 13);
 990+ })
 991+ .menu({
 992+ focus: function( event, ui ) {
 993+ var item = ui.item.data( "item.autocomplete" );
 994+ if ( false !== self._trigger( "focus", null, { item: item } ) ) {
 995+ // use value to match what will end up in the input, if it was a key event
 996+ if ( /^key/.test(event.originalEvent.type) ) {
 997+ self.element.val( item.value );
 998+ }
 999+ }
 1000+ },
 1001+ selected: function( event, ui ) {
 1002+ var item = ui.item.data( "item.autocomplete" );
 1003+ if ( false !== self._trigger( "select", event, { item: item } ) ) {
 1004+ self.element.val( item.value );
 1005+ }
 1006+ self.close( event );
 1007+ // only trigger when focus was lost (click on menu)
 1008+ var previous = self.previous;
 1009+ if ( self.element[0] !== doc.activeElement ) {
 1010+ self.element.focus();
 1011+ self.previous = previous;
 1012+ }
 1013+ self.selectedItem = item;
 1014+ },
 1015+ blur: function( event, ui ) {
 1016+ if ( self.menu.element.is(":visible") ) {
 1017+ self.element.val( self.term );
 1018+ }
 1019+ }
 1020+ })
 1021+ .zIndex( this.element.zIndex() + 1 )
 1022+ // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
 1023+ .css({ top: 0, left: 0 })
 1024+ .hide()
 1025+ .data( "menu" );
 1026+ if ( $.fn.bgiframe ) {
 1027+ this.menu.element.bgiframe();
 1028+ }
 1029+ },
 1030+
 1031+ destroy: function() {
 1032+ this.element
 1033+ .removeClass( "ui-autocomplete-input" )
 1034+ .removeAttr( "autocomplete" )
 1035+ .removeAttr( "role" )
 1036+ .removeAttr( "aria-autocomplete" )
 1037+ .removeAttr( "aria-haspopup" );
 1038+ this.menu.element.remove();
 1039+ $.Widget.prototype.destroy.call( this );
 1040+ },
 1041+
 1042+ _setOption: function( key ) {
 1043+ $.Widget.prototype._setOption.apply( this, arguments );
 1044+ if ( key === "source" ) {
 1045+ this._initSource();
 1046+ }
 1047+ },
 1048+
 1049+ _initSource: function() {
 1050+ var array,
 1051+ url;
 1052+ if ( $.isArray(this.options.source) ) {
 1053+ array = this.options.source;
 1054+ this.source = function( request, response ) {
 1055+ response( $.ui.autocomplete.filter(array, request.term) );
 1056+ };
 1057+ } else if ( typeof this.options.source === "string" ) {
 1058+ url = this.options.source;
 1059+ this.source = function( request, response ) {
 1060+ $.getJSON( url, request, response );
 1061+ };
 1062+ } else {
 1063+ this.source = this.options.source;
 1064+ }
 1065+ },
 1066+
 1067+ search: function( value, event ) {
 1068+ value = value != null ? value : this.element.val();
 1069+ if ( value.length < this.options.minLength ) {
 1070+ return this.close( event );
 1071+ }
 1072+
 1073+ clearTimeout( this.closing );
 1074+ if ( this._trigger("search") === false ) {
 1075+ return;
 1076+ }
 1077+
 1078+ return this._search( value );
 1079+ },
 1080+
 1081+ _search: function( value ) {
 1082+ this.term = this.element
 1083+ .addClass( "ui-autocomplete-loading" )
 1084+ // always save the actual value, not the one passed as an argument
 1085+ .val();
 1086+
 1087+ this.source( { term: value }, this.response );
 1088+ },
 1089+
 1090+ _response: function( content ) {
 1091+ if ( content.length ) {
 1092+ content = this._normalize( content );
 1093+ this._suggest( content );
 1094+ this._trigger( "open" );
 1095+ } else {
 1096+ this.close();
 1097+ }
 1098+ this.element.removeClass( "ui-autocomplete-loading" );
 1099+ },
 1100+
 1101+ close: function( event ) {
 1102+ clearTimeout( this.closing );
 1103+ if ( this.menu.element.is(":visible") ) {
 1104+ this._trigger( "close", event );
 1105+ this.menu.element.hide();
 1106+ this.menu.deactivate();
 1107+ }
 1108+ },
 1109+
 1110+ _change: function( event ) {
 1111+ if ( this.previous !== this.element.val() ) {
 1112+ this._trigger( "change", event, { item: this.selectedItem } );
 1113+ }
 1114+ },
 1115+
 1116+ _normalize: function( items ) {
 1117+ // assume all items have the right format when the first item is complete
 1118+ if ( items.length && items[0].label && items[0].value ) {
 1119+ return items;
 1120+ }
 1121+ return $.map( items, function(item) {
 1122+ if ( typeof item === "string" ) {
 1123+ return {
 1124+ label: item,
 1125+ value: item
 1126+ };
 1127+ }
 1128+ return $.extend({
 1129+ label: item.label || item.value,
 1130+ value: item.value || item.label
 1131+ }, item );
 1132+ });
 1133+ },
 1134+
 1135+ _suggest: function( items ) {
 1136+ var ul = this.menu.element
 1137+ .empty()
 1138+ .zIndex( this.element.zIndex() + 1 ),
 1139+ menuWidth,
 1140+ textWidth;
 1141+ this._renderMenu( ul, items );
 1142+ // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
 1143+ this.menu.deactivate();
 1144+ this.menu.refresh();
 1145+ this.menu.element.show().position({
 1146+ my: "left top",
 1147+ at: "left bottom",
 1148+ of: this.element,
 1149+ collision: "none"
 1150+ });
 1151+
 1152+ menuWidth = ul.width( "" ).width();
 1153+ textWidth = this.element.width();
 1154+ ul.width( Math.max( menuWidth, textWidth ) );
 1155+ },
 1156+
 1157+ _renderMenu: function( ul, items ) {
 1158+ var self = this;
 1159+ $.each( items, function( index, item ) {
 1160+ self._renderItem( ul, item );
 1161+ });
 1162+ },
 1163+
 1164+ _renderItem: function( ul, item) {
 1165+ return $( "<li></li>" )
 1166+ .data( "item.autocomplete", item )
 1167+ .append( "<a>" + item.label + "</a>" )
 1168+ .appendTo( ul );
 1169+ },
 1170+
 1171+ _move: function( direction, event ) {
 1172+ if ( !this.menu.element.is(":visible") ) {
 1173+ this.search( null, event );
 1174+ return;
 1175+ }
 1176+ if ( this.menu.first() && /^previous/.test(direction) ||
 1177+ this.menu.last() && /^next/.test(direction) ) {
 1178+ this.element.val( this.term );
 1179+ this.menu.deactivate();
 1180+ return;
 1181+ }
 1182+ this.menu[ direction ]( event );
 1183+ },
 1184+
 1185+ widget: function() {
 1186+ return this.menu.element;
 1187+ }
 1188+});
 1189+
 1190+$.extend( $.ui.autocomplete, {
 1191+ escapeRegex: function( value ) {
 1192+ return value.replace( /([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1" );
 1193+ },
 1194+ filter: function(array, term) {
 1195+ var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
 1196+ return $.grep( array, function(value) {
 1197+ return matcher.test( value.label || value.value || value );
 1198+ });
 1199+ }
 1200+});
 1201+
 1202+}( jQuery ));
Index: trunk/extensions/LinkSuggest/LinkSuggest.php
@@ -0,0 +1,235 @@
 2+<?php
 3+/**
 4+ * LinkSuggest
 5+ * This extension provides the user with article title suggestions as he types
 6+ * a link in wikitext.
 7+ *
 8+ * @file
 9+ * @ingroup Extensions
 10+ * @version 1.6 (r32133)
 11+ * @author Inez Korczyński <korczynski at gmail dot com>
 12+ * @author Bartek Łapiński <bartek at wikia-inc dot com>
 13+ * @author Łukasz Garczewski (TOR) <tor at wikia-inc dot com>
 14+ * @author Jesús Martínez Novo <martineznovo at gmail dot com>
 15+ * @author Jack Phoenix <jack@countervandalism.net>
 16+ * @copyright Copyright © 2008-2009, Wikia Inc.
 17+ * @copyright Copyright © 2011 Jesús Martínez Novo
 18+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
 19+ * @link http://www.mediawiki.org/wiki/Extension:LinkSuggest Documentation
 20+ */
 21+if( !defined( 'MEDIAWIKI' ) ) {
 22+ die( 'This is not a valid entry point to MediaWiki.' );
 23+}
 24+
 25+// Extension credits that will show up on Special:Version
 26+$wgExtensionCredits['other'][] = array(
 27+ 'name' => 'LinkSuggest',
 28+ 'version' => '1.6',
 29+ 'author' => array(
 30+ 'Inez Korczyński', 'Bartek Łapiński', 'Łukasz Garczewski',
 31+ 'Jesús Martínez Novo', 'Jack Phoenix'
 32+ ),
 33+ 'description' => 'Suggests links to editors on edit view',
 34+ 'url' => 'http://www.mediawiki.org/wiki/Extension:LinkSuggest',
 35+);
 36+
 37+// Internationalization file
 38+$wgExtensionMessagesFiles['LinkSuggest'] = dirname( __FILE__ ) . '/LinkSuggest.i18n.php';
 39+
 40+// ResourceLoader support (MW 1.17+)
 41+$wgResourceModules['ext.LinkSuggest'] = array(
 42+ 'scripts' => 'jquery.mw.linksuggest.js',
 43+ 'styles' => 'jquery-ui.css', // maybe this isn't needed? I dunno
 44+ 'dependencies' => array( 'jquery.ui.autocomplete' ),
 45+ 'localBasePath' => dirname( __FILE__ ),
 46+ 'remoteExtPath' => 'LinkSuggest'
 47+);
 48+
 49+// Hooked functions
 50+$wgHooks['EditPage::showEditForm:initial'][] = 'addLinkSuggest';
 51+$wgHooks['GetPreferences'][] = 'wfLinkSuggestToggle';
 52+
 53+/**
 54+ * Adds the new toggle to Special:Preferences for disabling LinkSuggest
 55+ * extension on a per-user basis
 56+ *
 57+ * @param $user Object: User object
 58+ * @param $preferences Object: Preferences object
 59+ * @return Boolean: true
 60+ */
 61+function wfLinkSuggestToggle( $user, &$preferences ) {
 62+ $preferences['disablelinksuggest'] = array(
 63+ 'type' => 'toggle',
 64+ 'section' => 'editing/advancedediting',
 65+ 'label-message' => 'tog-disablelinksuggest',
 66+ );
 67+ return true;
 68+}
 69+
 70+/**
 71+ * Add HTML required by LinkSuggest and the appropriate CSS and JS files to the
 72+ * edit form to users who haven't disabled LinkSuggest in their preferences.
 73+ *
 74+ * @param $editPage Object: instance of EditPage
 75+ * @return Boolean: true
 76+ */
 77+function addLinkSuggest( $editPage ) {
 78+ global $wgOut, $wgUser, $wgScriptPath;
 79+ if( $wgUser->getOption( 'disablelinksuggest' ) != true ) {
 80+ if ( defined( 'MW_SUPPORTS_RESOURCE_MODULES' ) ) {
 81+ // Load CSS and JS by using ResourceLoader (only for MW 1.17+)
 82+ $wgOut->addModules( 'ext.LinkSuggest' );
 83+ } else {
 84+ // 1.16 backwards compatibility code...icky
 85+ $wgOut->includeJQuery();
 86+ $wgOut->addInlineScript( '$ = jQuery;' ); // required in 1.16 :-(
 87+ $wgOut->addScriptFile( $wgScriptPath . '/extensions/LinkSuggest/jquery.widget.position.autocomplete-1.8.2.js' );
 88+ $wgOut->addExtensionStyle( $wgScriptPath . '/extensions/LinkSuggest/jquery.autocomplete.css' );
 89+ $wgOut->addScriptFile( $wgScriptPath . '/extensions/LinkSuggest/jquery.mw.linksuggest.js' );
 90+ }
 91+ }
 92+ return true;
 93+}
 94+
 95+global $wgAjaxExportList;
 96+$wgAjaxExportList[] = 'getLinkSuggest';
 97+$wgAjaxExportList[] = 'getLinkSuggestImage';
 98+
 99+/**
 100+ * Creates a thumbnail from an image name.
 101+ *
 102+ * @return AjaxResponse containing the thumbnail image
 103+ */
 104+function getLinkSuggestImage() {
 105+ global $wgRequest;
 106+ $imageName = $wgRequest->getText( 'imageName' );
 107+
 108+ $out = 'N/A';
 109+ try {
 110+ $img = wfFindFile( $imageName );
 111+ if( $img ) {
 112+ $out = $img->createThumb( 180 );
 113+ }
 114+ } catch( Exception $e ) {
 115+ $out = 'N/A';
 116+ }
 117+
 118+ $ar = new AjaxResponse( $out );
 119+ $ar->setCacheDuration( 60 * 60 );
 120+ return $ar;
 121+}
 122+
 123+/**
 124+ * AJAX callback function
 125+ *
 126+ * @return $ar Array of link suggestions
 127+ */
 128+function getLinkSuggest() {
 129+ global $wgRequest, $wgContLang;
 130+
 131+ // trim passed query and replace spaces by underscores
 132+ // - this is how MediaWiki stores article titles in database
 133+ $query = urldecode( trim( $wgRequest->getText( 'query' ) ) );
 134+ $query = str_replace( ' ', '_', $query );
 135+
 136+ // explode passed query by ':' to get namespace and article title
 137+ $queryParts = explode( ':', $query, 2 );
 138+
 139+ if( count( $queryParts ) == 2 ) {
 140+ $query = $queryParts[1];
 141+
 142+ $namespaceName = $queryParts[0];
 143+
 144+ // try to get the index by canonical name first
 145+ $namespace = MWNamespace::getCanonicalIndex( strtolower( $namespaceName ) );
 146+ if ( $namespace == null ) {
 147+ // if we failed, try looking through localized namespace names
 148+ $namespace = array_search(
 149+ ucfirst( $namespaceName ),
 150+ $wgContLang->getNamespaces()
 151+ );
 152+ if( empty( $namespace ) ) {
 153+ // getting here means our "namespace" is not real and can only
 154+ // be a part of the title
 155+ $query = $namespaceName . ':' . $query;
 156+ }
 157+ }
 158+ }
 159+
 160+ $results = array();
 161+
 162+ if( empty( $namespace ) ) {
 163+ // default namespace to search in
 164+ $namespace = NS_MAIN;
 165+ }
 166+
 167+ // get localized namespace name
 168+ $namespaceName = $wgContLang->getNsText( $namespace );
 169+ // and prepare it for later use...
 170+ $namespacePrefix = ( !empty( $namespaceName ) ) ? $namespaceName . ':' : '';
 171+
 172+ $dbr = wfGetDB( DB_SLAVE );
 173+ $query = $dbr->strencode( mb_strtolower( $query ) );
 174+
 175+ $res = $dbr->select(
 176+ array( 'querycache', 'page' ),
 177+ 'qc_title',
 178+ array(
 179+ 'qc_title = page_title',
 180+ 'qc_namespace = page_namespace',
 181+ 'page_is_redirect = 0',
 182+ 'qc_type' => 'Mostlinked',
 183+ "LOWER(qc_title) LIKE LOWER('{$query}%')",
 184+ 'qc_namespace' => $namespace
 185+ ),
 186+ __METHOD__,
 187+ array( 'ORDER BY' => 'qc_value DESC', 'LIMIT' => 10 )
 188+ );
 189+
 190+ foreach( $res as $row ) {
 191+ $results[] = str_replace( '_', ' ', $namespacePrefix . $row->qc_title );
 192+ }
 193+
 194+ $res = $dbr->select(
 195+ 'page',
 196+ 'page_title',
 197+ array(
 198+ "LOWER(page_title) LIKE '{$query}%'",
 199+ 'page_is_redirect' => 0,
 200+ 'page_namespace' => $namespace
 201+ ),
 202+ __METHOD__,
 203+ array(
 204+ 'ORDER BY' => 'page_title ASC',
 205+ 'LIMIT' => ( 15 - count( $results ) )
 206+ )
 207+ );
 208+
 209+ foreach( $res as $row ) {
 210+ $results[] = str_replace( '_', ' ', $namespacePrefix . $row->page_title );
 211+ }
 212+
 213+ $results = array_unique( $results );
 214+ $format = $wgRequest->getText( 'format' );
 215+
 216+ if( $format == 'json' ) {
 217+ $out = json_encode( array(
 218+ 'query' => $wgRequest->getText( 'query' ),
 219+ 'suggestions' => array_values( $results )
 220+ ));
 221+ } else {
 222+ $out = implode( "\n", $results );
 223+ }
 224+
 225+ $ar = new AjaxResponse( $out );
 226+ $ar->setCacheDuration( 60 * 60 ); // cache results for one hour
 227+
 228+ // set proper content type to ease development
 229+ if ( $format == 'json' ) {
 230+ $ar->setContentType( 'application/json; charset=utf-8' );
 231+ } else {
 232+ $ar->setContentType( 'text/plain; charset=utf-8' );
 233+ }
 234+
 235+ return $ar;
 236+}
\ No newline at end of file
Index: trunk/extensions/LinkSuggest/jquery.mw.linksuggest.js
@@ -0,0 +1,390 @@
 2+/*
 3+ * jQuery MediaWiki LinkSuggest 1.1.0
 4+ * JavaScript for LinkSuggest extension
 5+ *
 6+ * Copyright © 2010
 7+ * Authors: Inez Korczyński (korczynski at gmail dot com)
 8+ * Jesús Martínez Novo (martineznovo at gmail dot com)
 9+ * Licensed under the GPL (GPL-LICENSE.txt) license.
 10+ *
 11+ * Depends:
 12+ * jquery.ui.autocomplete.js
 13+ */
 14+( function( $ ) {
 15+
 16+$.widget( 'mw.linksuggest', {
 17+ options: {
 18+ minLength: 3,
 19+ delay: 300,
 20+ url: window.wgScript
 21+ },
 22+ _create: function() {
 23+ var self = this;
 24+ var opt = {
 25+ source: function() {
 26+ self._sendQuery.apply( self, arguments );
 27+ },
 28+ focus: function() {
 29+ // prevent value inserted on focus
 30+ return false;
 31+ },
 32+ select: function( event, ui ) {
 33+ self._updateValue( ui.item );
 34+ // prevent value inserted on select
 35+ return false;
 36+ },
 37+ open: function() {
 38+ self._open.apply( self, arguments );
 39+ }
 40+ };
 41+ // Opera only prevents default behavior on keypress, needed for
 42+ // capturing arrows and enter
 43+ var eventType = $.browser.opera ? 'keypress' : 'keydown';
 44+ this.options = $.extend( opt, this.options );
 45+ this.element.autocomplete( this.options );
 46+ // Overwrite the keydown event of autocomplete to fix some undesired key events
 47+ if ( typeof( this.element.data( 'events' ).keydown[0] ) !== undefined ) {
 48+ this._legacyKeydown = this.element.data( 'events' ).keydown[0].handler;
 49+ }
 50+ this.element.unbind( 'keydown.autocomplete' )
 51+ .bind( eventType + '.linksuggest', function( thisInstance ) {
 52+ return function() {
 53+ thisInstance._keydown.apply( thisInstance, arguments );
 54+ };
 55+ }( this ));
 56+ // deactivate some menu weird behavior
 57+ this.element.data( 'autocomplete' ).menu.options.blur = null;
 58+ },
 59+ _legacyKeydown: null,
 60+ _keydown: function( event ) {
 61+ var keyCode = $.ui.keyCode;
 62+ switch( event.keyCode ) {
 63+ case keyCode.UP:
 64+ case keyCode.DOWN:
 65+ if ( !this.element.data( 'autocomplete' ).menu.element.is( ':visible' ) ) {
 66+ // If menu element is not visible, ignore.
 67+ // Autocomplete event handler just prevents default
 68+ // behavior, which is not what we want
 69+ return;
 70+ }
 71+ break;
 72+ case keyCode.TAB:
 73+ // don't navigate away from the field on tab when selecting an item
 74+ if ( this.element.data( 'autocomplete' ).menu.active ) {
 75+ event.preventDefault();
 76+ }
 77+ break;
 78+ case keyCode.ESCAPE:
 79+ // return without setting any value
 80+ this.element.data( 'autocomplete' ).close( event );
 81+ return;
 82+ break;
 83+ case keyCode.PAGE_UP:
 84+ case keyCode.PAGE_DOWN:
 85+ case keyCode.LEFT:
 86+ case keyCode.RIGHT:
 87+ case keyCode.SHIFT:
 88+ case keyCode.CONTROL:
 89+ case keyCode.ALT:
 90+ case keyCode.COMMAND:
 91+ case keyCode.COMMAND_RIGHT:
 92+ case keyCode.INSERT:
 93+ case keyCode.CAPS_LOCK:
 94+ case keyCode.END:
 95+ case keyCode.HOME:
 96+ // ignore metakeys (shift, ctrl, alt)
 97+ return
 98+ break;
 99+ }
 100+ // If we not already returned from this function, fire the old autocomplete handler
 101+ if ( $.isFunction( this._legacyKeydown ) ) {
 102+ this._legacyKeydown.apply( this.element.data( 'autocomplete' ), arguments );
 103+ }
 104+ },
 105+ _sendQuery: function( request, response ) {
 106+ var emptyset = [];
 107+ var text = this._getText();
 108+ var caret = this._getCaret();
 109+ var sQueryStartAt = -1;
 110+ var sQueryReal = '';
 111+ var format = '';
 112+ var stripPrefix = false;
 113+
 114+ // Look forward, to see if we closed this one
 115+ for ( var i = caret; i < text.length; i++ ) {
 116+ var c = text.charAt( i );
 117+ var c1 = ( i > 0 ? text.charAt( i - 1 ) : '' );
 118+ // A line break, it isn't closed
 119+ if ( c == '\n' ) {
 120+ break;
 121+ }
 122+ // A start of a link, so this link isn't closed
 123+ if ( c == '[' && c1 == '[' ) {
 124+ break;
 125+ }
 126+ // A closing link and this was a link, exit
 127+ if ( c == ']' && c1 == ']' ) {
 128+ response( emptyset );
 129+ return false;
 130+ }
 131+ // A start of a template, so this template isn't closed
 132+ if ( c == '{' && c1 == '{' ) {
 133+ break;
 134+ }
 135+ // A closing template and this was a template, exit
 136+ if ( c == '}' && c1 == '}' ) {
 137+ response( emptyset );
 138+ return false;
 139+ }
 140+ }
 141+
 142+ // Get the start of the link/template
 143+ for ( var i = caret - 1; i >= 0; i-- ) {
 144+ var c = text.charAt( i );
 145+ // If nothing found after a line break, nothing to match
 146+ if ( c == '\n' ) {
 147+ break;
 148+ }
 149+ // Closed link/template, a pipe or a hash.
 150+ // There's no link/template to complete, or we're on a parser
 151+ // function or link hash
 152+ if ( c == ']' || c == '}' || c == '|' || c == '#' ) {
 153+ response( emptyset );
 154+ return false;
 155+ }
 156+
 157+ // It's an open link
 158+ if ( c == '[' && i > 0 && text.charAt( i - 1 ) == '[' ) {
 159+ sQueryReal = text.substr( i + 1, ( caret - i - 1 ) );
 160+ if ( sQueryReal.charAt( 0 ) == ':' ) {
 161+ sQueryReal = sQueryReal.substr( 1 );
 162+ format = '[[:$1]]';
 163+ } else {
 164+ format = '[[$1]]';
 165+ }
 166+ sQueryStartAt = i;
 167+ break;
 168+ }
 169+
 170+ // It's an open template
 171+ if ( c == '{' && i > 0 && text.charAt( i - 1 ) == '{' ) {
 172+ // Exclude template parameters
 173+ if ( i > 1 && text.charAt( i - 2 ) == '{' ) {
 174+ response( emptyset );
 175+ return false;
 176+ }
 177+ sQueryReal = text.substr( i + 1, ( caret - i - 1 ) );
 178+ if ( sQueryReal.length >= 6 && sQueryReal.toLowerCase().substr( 0, 6 ) == 'subst:' ) {
 179+ if ( sQueryReal.length >= 7 && sQueryReal.charAt( 6 ) == ':' ) {
 180+ sQueryReal = sQueryReal.substr( 7 );
 181+ format = '{{subst::$1}}';
 182+ } else {
 183+ sQueryReal = 'Template:' + sQueryReal.substr( 6 );
 184+ stripPrefix = true;
 185+ format = '{{subst:$1}}';
 186+ }
 187+ } else if ( sQueryReal.charAt( 0 ) == ':' ) {
 188+ sQueryReal = sQueryReal.substr( 1 );
 189+ format = '{{:$1}}';
 190+ } else {
 191+ sQueryReal = 'Template:' + sQueryReal;
 192+ stripPrefix = true;
 193+ format = '{{$1}}';
 194+ }
 195+ sQueryStartAt = i;
 196+ break;
 197+ }
 198+ }
 199+
 200+ if ( sQueryStartAt >= 0 && sQueryReal.length > this.options.minLength ) {
 201+ $.get(
 202+ this.options.url,
 203+ {
 204+ action: 'ajax',
 205+ rs: 'getLinkSuggest',
 206+ query: sQueryReal
 207+ },
 208+ this._responseWrapper( this, response, format, stripPrefix )
 209+ );
 210+ return true;
 211+ }
 212+ response( emptyset );
 213+ return false
 214+ },
 215+ _responseWrapper: function( thisArg, callback, format, stripPrefix ) {
 216+ return function( data ) {
 217+ if ( data.length == 0 ) {
 218+ return callback( [] );
 219+ }
 220+ callback( thisArg._formatResponse( data, format, stripPrefix ) );
 221+ };
 222+ },
 223+ _formatResponse: function( data, format, stripPrefix ) {
 224+ return $.map( data.split( '\n' ), function( n ) {
 225+ if ( stripPrefix ) {
 226+ var pos = n.indexOf( ':' );
 227+ if ( pos >= 0 ) {
 228+ n = n.substr( pos + 1 );
 229+ }
 230+ }
 231+ return { label: n, value: format.replace( '$1', n ) };
 232+ } );
 233+ },
 234+ _updateValue: function( oItem ) {
 235+ this.element[0].focus();
 236+
 237+ var scrollTop = this.element[0].scrollTop;
 238+ var text = this._getText();
 239+ var caret = this._getCaret();
 240+ var prefix = oItem.value.substr( 0, 2 );
 241+
 242+ for ( var i = caret - 2; i >= 0; i-- ) { // break for templates and normal links
 243+ if ( text.substr( i, 2 ) == prefix ) {
 244+ break;
 245+ }
 246+ }
 247+
 248+ var textBefore = text.substr( 0, i );
 249+ var newVal = textBefore + oItem.value + text.substr( caret );
 250+ this.element.val( newVal );
 251+
 252+ this._setCaret( textBefore.length + oItem.value.length );
 253+ this.element[0].scrollTop = scrollTop;
 254+ },
 255+ _getCaret: function() {
 256+ var caretPos = 0;
 257+ var control = this.element[0];
 258+ // IE Support
 259+ if ( document.selection && document.selection.createRange ) {
 260+ control.focus();
 261+ var sel = document.selection.createRange();
 262+ var sel2 = sel.duplicate();
 263+ sel2.moveToElementText( control );
 264+ var caretPos = -1;
 265+ while ( sel2.inRange( sel ) ) {
 266+ sel2.moveStart( 'character' );
 267+ caretPos++;
 268+ }
 269+ // Firefox support
 270+ } else if ( control.selectionStart || control.selectionStart == '0' ) {
 271+ caretPos = control.selectionStart;
 272+ }
 273+ return caretPos;
 274+ },
 275+ _getText: function() {
 276+ if ( document.selection && document.selection.createRange ) {
 277+ return this.element.val();
 278+ }
 279+ // jQuery.val() removes \n, we need them so we get the caret position
 280+ // correctly. That does not apply to document.selection
 281+ return this.element[0].value;
 282+ },
 283+ _setCaret: function( pos ) {
 284+ var control = this.element[0];
 285+ if ( control.setSelectionRange ) {
 286+ control.focus();
 287+ control.setSelectionRange( pos, pos );
 288+ } else if ( control.createTextRange ) {
 289+ var range = control.createTextRange();
 290+ range.collapse( true );
 291+ range.moveEnd( 'character', pos );
 292+ range.moveStart( 'character', pos );
 293+ range.select();
 294+ }
 295+ },
 296+ _getCaretPosition: function() {
 297+ var control = this.element[0];
 298+ var left = 0;
 299+ var top = 0;
 300+ var tester = $( '<div style="position:absolute;top:-1000px;left:-1000px;white-space:pre-wrap;visibility:hidden;"></div>' );
 301+ var text = this._getText();
 302+ var caret = this._getCaret();
 303+ var initialcaret = caret;
 304+ if ( caret == 0 ) {
 305+ // This should never happen
 306+ return [ 0, 0 ];
 307+ }
 308+ // Get the position at the start of the link/template
 309+ for ( var i = caret - 1; i >= 0; i-- ) {
 310+ var c = text.charAt( i );
 311+ if ( c == '[' || c == '{' ) {
 312+ initialcaret = i + 1;
 313+ break;
 314+ }
 315+ }
 316+ // Create a tester container to get the size of the text before the
 317+ // caret, and thus the position inside the element
 318+ // WARNING: You MUST apply a font-family CSS attribute to the textarea
 319+ // (to this particular one, or a generic `textarea {font-famly: whatever;}´)
 320+ // so IE could retrieve the correct font-family used, otherwise it may
 321+ // fail to position the drop-down correctly!
 322+ var props = 'padding-top padding-right padding-bottom padding-left border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width border-bottom-width border-left-width font-size font-family font-weight line-height'.split(' ');
 323+ for ( var i = 0; i < props.length; i++ ) {
 324+ tester.css( props[i], this.element.css( props[i] ) );
 325+ }
 326+ // Using clientWidth because if the textarea has scroll, the effective
 327+ // width for word wrap doesn't include the width used by the scrollbar
 328+ tester.width( control.clientWidth ).appendTo( document.body ).text( text.substr( 0, caret ) );
 329+ left = tester.outerWidth();
 330+ top = tester.outerHeight() - control.scrollTop;
 331+ var initialheight = tester.height();
 332+ var paddingText = '';
 333+ // Insert the text until the initial position of the element we want to
 334+ // suggest, plus a space, to get the characters needed to force a word
 335+ // wrap to a new line
 336+ tester.text( text.substr( 0, initialcaret ) + ' ' );
 337+ if ( tester.height() < initialheight ) {
 338+ // If the height has been reduced then the element to suggest is
 339+ // forcing a word wrap to a new line and it's on the left side of
 340+ // the textarea
 341+ left = 0;
 342+ } else {
 343+ // Get how many characters we need to force a word wrap to a new
 344+ // line, and then transform it in an actual size
 345+ // If we go beyond 500, something must be wrong
 346+ for ( var i = 1; i < 500; i++ ) {
 347+ paddingText += 'A';
 348+ // msie appendData doesn't update the height()
 349+ if ( $.browser.msie ) {
 350+ tester[0].firstChild.data += 'A';
 351+ } else {
 352+ tester[0].firstChild.appendData( 'A' );
 353+ }
 354+ if ( tester.height() > initialheight ) {
 355+ tester.css( 'width', 'auto' );
 356+ tester.text( paddingText );
 357+ left -= tester.outerWidth();
 358+ break;
 359+ }
 360+ }
 361+ }
 362+ tester.remove();
 363+ return [ left, top ];
 364+ },
 365+ _open: function( event, ui ) {
 366+ var menu = this.element.data( 'autocomplete' ).menu.element;
 367+ var offset = this._getCaretPosition();
 368+ var width = menu.outerWidth();
 369+ var props = {
 370+ my: 'left top',
 371+ at: 'left top',
 372+ of: this.element,
 373+ offset: offset.join( ' ' ),
 374+ collision: 'fit none'
 375+ };
 376+ if ( offset.left + width > this.element.outerWidth() ) {
 377+ props.my = 'right top';
 378+ }
 379+ menu.width( '' ).position( props );
 380+ }
 381+
 382+});
 383+
 384+}( jQuery ));
 385+
 386+// Implementation: This should be done injecting this code into MediaWiki, not
 387+// in this JS file
 388+$( function() {
 389+ // Apply font-style for bug in IE. This should be done using a style sheet
 390+ $( '#wpTextbox1' ).css( 'font-family', 'monospace' ).linksuggest();
 391+});
\ No newline at end of file

Follow-up revisions

RevisionCommit summaryAuthorDate
r85038svn:eol-style native for r85036reedy19:35, 30 March 2011

Comments

#Comment by Macbre (talk | contribs)   13:14, 4 August 2011

jquery-ui.css stylesheet contains lots of unnecessary rules (including requests to not existing PNGs from images subdirectory). This file should be cleaned up.

Status & tagging log