Jack Phoenix has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/208107

Change subject: Fixed this thing so that it actually works + cleaned up the 
codebase.
......................................................................

Fixed this thing so that it actually works + cleaned up the codebase.

* Functions now live in the brand new LinkSuggest class instead of the main 
setup file
* Updated jquery.mw.linksuggest.js to version 1.3.0 (see 
https://github.com/ciencia/jquery.mw.linksuggest) and fixed a bug in the 
_legacyKeydown function + bumped jquery.mw.linksuggest's version to 1.3.1
* Removed legacy jQuery UI assets
* Removed legacy PHP i18n file

Very lightly tested on MW 1.24.1 + Firefox 37.0.2.

Change-Id: Ied8a36b8546a6b84fae645567fdbb6fec4dd15bb
---
A LinkSuggest.class.php
D LinkSuggest.i18n.php
M LinkSuggest.php
D jquery-ui.css
M jquery.mw.linksuggest.js
D jquery.widget.position.autocomplete-1.8.2.js
6 files changed, 344 insertions(+), 2,096 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/LinkSuggest 
refs/changes/07/208107/1

diff --git a/LinkSuggest.class.php b/LinkSuggest.class.php
new file mode 100644
index 0000000..80718eb
--- /dev/null
+++ b/LinkSuggest.class.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * @file
+ */
+
+class LinkSuggest {
+
+       /**
+        * Adds the new toggle to Special:Preferences for disabling LinkSuggest
+        * extension on a per-user basis
+        *
+        * @param User $user
+        * @param Preferences $preferences
+        * @return bool
+        */
+       public static function onGetPreferences( $user, &$preferences ) {
+               $preferences['disablelinksuggest'] = array(
+                       'type' => 'toggle',
+                       'section' => 'editing/advancedediting',
+                       'label-message' => 'tog-disablelinksuggest',
+               );
+               return true;
+       }
+
+       /**
+        * Add HTML required by LinkSuggest and the appropriate CSS and JS 
files to the
+        * edit form to users who haven't disabled LinkSuggest in their 
preferences.
+        *
+        * @param EditPage $editPage
+        * @param OutputPage $output
+        * @return bool
+        */
+       public static function onEditPage( EditPage $editPage, OutputPage 
$output ) {
+               global $wgUser;
+               if ( $wgUser->getOption( 'disablelinksuggest' ) != true ) {
+                       // Load CSS and JS by using ResourceLoader
+                       $output->addModules( 'ext.LinkSuggest' );
+               }
+               return true;
+       }
+
+       /**
+        * Creates a thumbnail from an image name.
+        *
+        * @return AjaxResponse containing the thumbnail image
+        */
+       public static function getImage() {
+               global $wgRequest;
+
+               $imageName = $wgRequest->getText( 'imageName' );
+
+               $out = 'N/A';
+               try {
+                       $img = wfFindFile( $imageName );
+                       if ( $img ) {
+                               $out = $img->createThumb( 180 );
+                       }
+               } catch ( Exception $e ) {
+                       $out = 'N/A';
+               }
+
+               $ar = new AjaxResponse( $out );
+               $ar->setCacheDuration( 60 * 60 );
+
+               return $ar;
+       }
+
+       /**
+        * AJAX callback function
+        *
+        * @return array $ar Link suggestions
+        */
+       public static function get() {
+               global $wgRequest, $wgContLang, $wgContentNamespaces;
+
+               // trim passed query and replace spaces by underscores
+               // - this is how MediaWiki stores article titles in database
+               $query = urldecode( trim( $wgRequest->getText( 'query' ) ) );
+               $query = str_replace( ' ', '_', $query );
+
+               // explode passed query by ':' to get namespace and article 
title
+               $queryParts = explode( ':', $query, 2 );
+
+               if ( count( $queryParts ) == 2 ) {
+                       $query = $queryParts[1];
+
+                       $namespaceName = $queryParts[0];
+
+                       // try to get the index by canonical name first
+                       $namespace = MWNamespace::getCanonicalIndex( 
strtolower( $namespaceName ) );
+                       if ( $namespace == null ) {
+                               // if we failed, try looking through localized 
namespace names
+                               $namespace = array_search(
+                                       ucfirst( $namespaceName ),
+                                       $wgContLang->getNamespaces()
+                               );
+                               if ( empty( $namespace ) ) {
+                                       // getting here means our "namespace" 
is not real and can only
+                                       // be a part of the title
+                                       $query = $namespaceName . ':' . $query;
+                               }
+                       }
+               }
+
+               // list of namespaces to search in
+               if ( empty( $namespace ) ) {
+                       // search only within content namespaces - default 
behaviour
+                       $namespaces = $wgContentNamespaces;
+               } else {
+                       // search only within a namespace from query
+                       $namespaces = $namespace;
+               }
+
+               $results = array();
+
+               $dbr = wfGetDB( DB_SLAVE );
+               $query = mb_strtolower( $query );
+
+               $res = $dbr->select(
+                       array( 'querycache', 'page' ),
+                       array( 'qc_namespace', 'qc_title' ),
+                       array(
+                               'qc_title = page_title',
+                               'qc_namespace = page_namespace',
+                               'page_is_redirect' => 0,
+                               'qc_type' => 'Mostlinked',
+                               'LOWER(qc_title)' . $dbr->buildLike( $query, 
$dbr->anyString() ),
+                               'qc_namespace' => $namespaces
+                       ),
+                       __METHOD__,
+                       array( 'ORDER BY' => 'qc_value DESC', 'LIMIT' => 10 )
+               );
+
+               foreach ( $res as $row ) {
+                       $results[] = self::formatTitle( $row->qc_namespace, 
$row->qc_title );
+               }
+
+               $res = $dbr->select(
+                       'page',
+                       array( 'page_namespace', 'page_title' ),
+                       array(
+                               'LOWER(page_title)' . $dbr->buildLike( $query, 
$dbr->anyString() ),
+                               'page_is_redirect' => 0,
+                               'page_namespace' => $namespaces
+                       ),
+                       __METHOD__,
+                       array(
+                               'ORDER BY' => 'page_title ASC',
+                               'LIMIT' => ( 15 - count( $results ) )
+                       )
+               );
+
+               foreach ( $res as $row ) {
+                       $results[] = self::formatTitle( $row->page_namespace, 
$row->page_title );
+               }
+
+               $results = array_unique( $results );
+               $format = $wgRequest->getText( 'format' );
+
+               if ( $format == 'json' ) {
+                       $out = json_encode( array(
+                               'query' => $wgRequest->getText( 'query' ),
+                               'suggestions' => array_values( $results )
+                       ) );
+               } else {
+                       $out = implode( "\n", $results );
+               }
+
+               $ar = new AjaxResponse( $out );
+               $ar->setCacheDuration( 60 * 60 ); // cache results for one hour
+
+               // set proper content type to ease development
+               if ( $format == 'json' ) {
+                       $ar->setContentType( 'application/json; charset=utf-8' 
);
+               } else {
+                       $ar->setContentType( 'text/plain; charset=utf-8' );
+               }
+
+               return $ar;
+       }
+
+       /**
+        * Returns formatted title based on given namespace and title
+        *
+        * @param int $namespace Page namespace ID
+        * @param string $title Page title
+        * @return string Formatted title (prefixed with localised namespace)
+        */
+       public static function formatTitle( $namespace, $title ) {
+               global $wgContLang;
+
+               if ( $namespace != NS_MAIN ) {
+                       $title = $wgContLang->getNsText( $namespace ) . ':' . 
$title;
+               }
+
+               return str_replace( '_', ' ', $title );
+       }
+}
\ No newline at end of file
diff --git a/LinkSuggest.i18n.php b/LinkSuggest.i18n.php
deleted file mode 100644
index fc02d97..0000000
--- a/LinkSuggest.i18n.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-/**
- * This is a backwards-compatibility shim, generated by:
- * 
https://git.wikimedia.org/blob/mediawiki%2Fcore.git/HEAD/maintenance%2FgenerateJsonI18n.php
- *
- * Beginning with MediaWiki 1.23, translation strings are stored in json files,
- * and the EXTENSION.i18n.php file only exists to provide compatibility with
- * older releases of MediaWiki. For more information about this migration, see:
- * https://www.mediawiki.org/wiki/Requests_for_comment/Localisation_format
- *
- * This shim maintains compatibility back to MediaWiki 1.17.
- */
-$messages = array();
-if ( !function_exists( 'wfJsonI18nShim8875bbd8f8d24832' ) ) {
-       function wfJsonI18nShim8875bbd8f8d24832( $cache, $code, &$cachedData ) {
-               $codeSequence = array_merge( array( $code ), 
$cachedData['fallbackSequence'] );
-               foreach ( $codeSequence as $csCode ) {
-                       $fileName = dirname( __FILE__ ) . "/i18n/$csCode.json";
-                       if ( is_readable( $fileName ) ) {
-                               $data = FormatJson::decode( file_get_contents( 
$fileName ), true );
-                               foreach ( array_keys( $data ) as $key ) {
-                                       if ( $key === '' || $key[0] === '@' ) {
-                                               unset( $data[$key] );
-                                       }
-                               }
-                               $cachedData['messages'] = array_merge( $data, 
$cachedData['messages'] );
-                       }
-
-                       $cachedData['deps'][] = new FileDependency( $fileName );
-               }
-               return true;
-       }
-
-       $GLOBALS['wgHooks']['LocalisationCacheRecache'][] = 
'wfJsonI18nShim8875bbd8f8d24832';
-}
diff --git a/LinkSuggest.php b/LinkSuggest.php
index ed38769..e11d4f6 100644
--- a/LinkSuggest.php
+++ b/LinkSuggest.php
@@ -15,17 +15,14 @@
  * @copyright Copyright © 2008-2009, Wikia Inc.
  * @copyright Copyright © 2011 Jesús Martínez Novo
  * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 
2.0 or later
- * @link http://www.mediawiki.org/wiki/Extension:LinkSuggest Documentation
+ * @link https://www.mediawiki.org/wiki/Extension:LinkSuggest Documentation
  */
-if( !defined( 'MEDIAWIKI' ) ) {
-       die( 'This is not a valid entry point to MediaWiki.' );
-}
 
 // Extension credits that will show up on Special:Version
 $wgExtensionCredits['other'][] = array(
        'path' => __FILE__,
        'name' => 'LinkSuggest',
-       'version' => '1.8.0',
+       'version' => '1.8.1',
        'author' => array(
                'Inez Korczyński', 'Bartek Łapiński', 'Łukasz Garczewski', 
'Maciej Brencz',
                'Jesús Martínez Novo', 'Jack Phoenix'
@@ -34,220 +31,24 @@
        'url' => 'https://www.mediawiki.org/wiki/Extension:LinkSuggest',
 );
 
-// Internationalization file
+// Internationalization stuff
 $wgMessagesDirs['LinkSuggest'] = __DIR__ . '/i18n';
-$wgExtensionMessagesFiles['LinkSuggest'] = dirname( __FILE__ ) . 
'/LinkSuggest.i18n.php';
 
 // ResourceLoader support (MW 1.17+)
 $wgResourceModules['ext.LinkSuggest'] = array(
        'scripts' => 'jquery.mw.linksuggest.js',
-       'styles' => 'jquery-ui.css', // maybe this isn't needed? I dunno
        'dependencies' => array( 'jquery.ui.autocomplete' ),
-       'localBasePath' => dirname( __FILE__ ),
+       'localBasePath' => __DIR__,
        'remoteExtPath' => 'LinkSuggest'
 );
 
+// Autoload the class file which contains everything (from the PHP side, that 
is)
+$wgAutoloadClasses['LinkSuggest'] = __DIR__ . '/LinkSuggest.class.php';
+
 // Hooked functions
-$wgHooks['EditPage::showEditForm:initial'][] = 'addLinkSuggest';
-$wgHooks['GetPreferences'][] = 'wfLinkSuggestToggle';
+$wgHooks['EditPage::showEditForm:initial'][] = 'LinkSuggest::onEditPage';
+$wgHooks['GetPreferences'][] = 'LinkSuggest::onGetPreferences';
 
-/**
- * Adds the new toggle to Special:Preferences for disabling LinkSuggest
- * extension on a per-user basis
- *
- * @param $user Object: User object
- * @param $preferences Object: Preferences object
- * @return Boolean: true
- */
-function wfLinkSuggestToggle( $user, &$preferences ) {
-       $preferences['disablelinksuggest'] = array(
-               'type' => 'toggle',
-               'section' => 'editing/advancedediting',
-               'label-message' => 'tog-disablelinksuggest',
-       );
-       return true;
-}
-
-/**
- * Add HTML required by LinkSuggest and the appropriate CSS and JS files to the
- * edit form to users who haven't disabled LinkSuggest in their preferences.
- *
- * @param $editPage Object: instance of EditPage
- * @return Boolean: true
- */
-function addLinkSuggest( $editPage ) {
-       global $wgOut, $wgUser, $wgScriptPath;
-       if( $wgUser->getOption( 'disablelinksuggest' ) != true ) {
-               if ( defined( 'MW_SUPPORTS_RESOURCE_MODULES' ) ) {
-                       // Load CSS and JS by using ResourceLoader (only for MW 
1.17+)
-                       $wgOut->addModules( 'ext.LinkSuggest' );
-               } else {
-                       // 1.16 backwards compatibility code...icky
-                       $wgOut->includeJQuery();
-                       $wgOut->addInlineScript( '$ = jQuery;' ); // required 
in 1.16 :-(
-                       $wgOut->addScriptFile( $wgScriptPath . 
'/extensions/LinkSuggest/jquery.widget.position.autocomplete-1.8.2.js' );
-                       $wgOut->addExtensionStyle( $wgScriptPath . 
'/extensions/LinkSuggest/jquery.autocomplete.css' );
-                       $wgOut->addScriptFile( $wgScriptPath . 
'/extensions/LinkSuggest/jquery.mw.linksuggest.js' );
-               }
-       }
-       return true;
-}
-
-global $wgAjaxExportList;
-$wgAjaxExportList[] = 'getLinkSuggest';
-$wgAjaxExportList[] = 'getLinkSuggestImage';
-
-/**
- * Creates a thumbnail from an image name.
- *
- * @return AjaxResponse containing the thumbnail image
- */
-function getLinkSuggestImage() {
-       global $wgRequest;
-       $imageName = $wgRequest->getText( 'imageName' );
-
-       $out = 'N/A';
-       try {
-               $img = wfFindFile( $imageName );
-               if( $img ) {
-                       $out = $img->createThumb( 180 );
-               }
-       } catch( Exception $e ) {
-               $out = 'N/A';
-       }
-
-       $ar = new AjaxResponse( $out );
-       $ar->setCacheDuration( 60 * 60 );
-       return $ar;
-}
-
-/**
- * AJAX callback function
- *
- * @return $ar Array of link suggestions
- */
-function getLinkSuggest() {
-       global $wgRequest, $wgContLang, $wgContentNamespaces;
-
-       // trim passed query and replace spaces by underscores
-       // - this is how MediaWiki stores article titles in database
-       $query = urldecode( trim( $wgRequest->getText( 'query' ) ) );
-       $query = str_replace( ' ', '_', $query );
-
-       // explode passed query by ':' to get namespace and article title
-       $queryParts = explode( ':', $query, 2 );
-
-       if( count( $queryParts ) == 2 ) {
-               $query = $queryParts[1];
-
-               $namespaceName = $queryParts[0];
-
-               // try to get the index by canonical name first
-               $namespace = MWNamespace::getCanonicalIndex( strtolower( 
$namespaceName ) );
-               if ( $namespace == null ) {
-                       // if we failed, try looking through localized 
namespace names
-                       $namespace = array_search(
-                               ucfirst( $namespaceName ),
-                               $wgContLang->getNamespaces()
-                       );
-                       if( empty( $namespace ) ) {
-                               // getting here means our "namespace" is not 
real and can only
-                               // be a part of the title
-                               $query = $namespaceName . ':' . $query;
-                       }
-               }
-       }
-
-       // list of namespaces to search in
-       if ( empty( $namespace ) ) {
-               // search only within content namespaces - default behaviour
-               $namespaces = $wgContentNamespaces;
-       } else {
-               // search only within a namespace from query
-               $namespaces = $namespace;
-       }
-
-       $results = array();
-
-       $dbr = wfGetDB( DB_SLAVE );
-       $query = mb_strtolower( $query );
-
-       $res = $dbr->select(
-               array( 'querycache', 'page' ),
-               array( 'qc_namespace', 'qc_title' ),
-               array(
-                       'qc_title = page_title',
-                       'qc_namespace = page_namespace',
-                       'page_is_redirect = 0',
-                       'qc_type' => 'Mostlinked',
-                       'LOWER(qc_title)' . $dbr->buildLike( $query, 
$dbr->anyString() ),
-                       'qc_namespace' => $namespaces
-               ),
-               __METHOD__,
-               array( 'ORDER BY' => 'qc_value DESC', 'LIMIT' => 10 )
-       );
-
-       foreach( $res as $row ) {
-               $results[] = wfLinkSuggestFormatTitle( $row->qc_namespace, 
$row->qc_title );
-       }
-
-       $res = $dbr->select(
-               'page',
-               array( 'page_namespace', 'page_title' ),
-               array(
-                       'LOWER(page_title)' . $dbr->buildLike( $query, 
$dbr->anyString() ),
-                       'page_is_redirect' => 0,
-                       'page_namespace' => $namespaces
-               ),
-               __METHOD__,
-               array(
-                       'ORDER BY' => 'page_title ASC',
-                       'LIMIT' => ( 15 - count( $results ) )
-               )
-       );
-
-       foreach( $res as $row ) {
-               $results[] = wfLinkSuggestFormatTitle( $row->page_namespace, 
$row->page_title );
-       }
-
-       $results = array_unique( $results );
-       $format = $wgRequest->getText( 'format' );
-
-       if( $format == 'json' ) {
-               $out = json_encode( array(
-                       'query' => $wgRequest->getText( 'query' ),
-                       'suggestions' => array_values( $results )
-               ));
-       } else {
-               $out = implode( "\n", $results );
-       }
-
-       $ar = new AjaxResponse( $out );
-       $ar->setCacheDuration( 60 * 60 ); // cache results for one hour
-
-       // set proper content type to ease development
-       if ( $format == 'json' ) {
-               $ar->setContentType( 'application/json; charset=utf-8' );
-       } else {
-               $ar->setContentType( 'text/plain; charset=utf-8' );
-       }
-
-       return $ar;
-}
-
-/**
- * Returns formatted title based on given namespace and title
- *
- * @param $namespace integer page namespace ID
- * @param $title string page title
- * @return string formatted title (prefixed with localised namespace)
- */
-function wfLinkSuggestFormatTitle( $namespace, $title ) {
-       global $wgContLang;
-
-       if ( $namespace != NS_MAIN ) {
-               $title = $wgContLang->getNsText( $namespace ) . ':' . $title;
-       }
-
-       return str_replace( '_', ' ', $title );
-}
+// AJAX callback functions
+$wgAjaxExportList[] = 'LinkSuggest::get';
+$wgAjaxExportList[] = 'LinkSuggest::getImage';
\ No newline at end of file
diff --git a/jquery-ui.css b/jquery-ui.css
deleted file mode 100644
index 58d35ad..0000000
--- a/jquery-ui.css
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * jQuery UI CSS Framework 1.8.10
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- */
-
-/* Layout helpers
-----------------------------------*/
-.ui-helper-hidden { display: none; }
-.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 
1px 1px 1px); clip: rect(1px,1px,1px,1px); }
-.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 
1.3; text-decoration: none; font-size: 100%; list-style: none; }
-.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: 
both; visibility: hidden; }
-.ui-helper-clearfix { display: inline-block; }
-/* required comment for clearfix to work in Opera \*/
-* html .ui-helper-clearfix { height:1%; }
-.ui-helper-clearfix { display:block; }
-/* end clearfix */
-.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: 
absolute; opacity: 0; filter:Alpha(Opacity=0); }
-
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-disabled { cursor: default !important; }
-
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { display: block; text-indent: -99999px; overflow: hidden; 
background-repeat: no-repeat; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Overlays */
-.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 
100%; }
-/*
- * jQuery UI Accordion 1.8.10
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Accordion#theming
- */
-/* IE/Win - Fix animation bug - #4615 */
-.ui-accordion { width: 100%; }
-.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; 
margin-top: 1px; zoom: 1; }
-.ui-accordion .ui-accordion-li-fix { display: inline; }
-.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
-.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; 
padding: .5em .5em .5em .7em; }
-.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
-.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; 
top: 50%; margin-top: -8px; }
-.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; }
-.ui-accordion .ui-accordion-content-active { display: block; }
-/*
- * jQuery UI Autocomplete 1.8.10
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete#theming
- */
-.ui-autocomplete { position: absolute; cursor: default; }      
-
-/* workarounds */
-* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 
100% in IE6 */
-
-/*
- * jQuery UI Menu 1.8.10
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Menu#theming
- */
-.ui-menu {
-       list-style:none;
-       padding: 2px;
-       margin: 0;
-       display:block;
-       float: left;
-}
-.ui-menu .ui-menu {
-       margin-top: -3px;
-}
-.ui-menu .ui-menu-item {
-       margin:0;
-       padding: 0;
-       zoom: 1;
-       float: left;
-       clear: left;
-       width: 100%;
-}
-.ui-menu .ui-menu-item a {
-       text-decoration:none;
-       display:block;
-       padding:.2em .4em;
-       line-height:1.5;
-       zoom:1;
-}
-.ui-menu .ui-menu-item a.ui-state-hover,
-.ui-menu .ui-menu-item a.ui-state-active {
-       font-weight: normal;
-       margin: -1px;
-}
-/*
- * jQuery UI Button 1.8.10
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Button#theming
- */
-.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 */
-.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width 
needs to be set here */
-button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a 
little more width */
-.ui-button-icons-only { width: 3.4em; } 
-button.ui-button-icons-only { width: 3.7em; } 
-
-/*button text element */
-.ui-button .ui-button-text { display: block; line-height: 1.4;  }
-.ui-button-text-only .ui-button-text { padding: .4em 1em; }
-.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { 
padding: .4em; text-indent: -9999999px; }
-.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons 
.ui-button-text { padding: .4em 1em .4em 2.1em; }
-.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons 
.ui-button-text { padding: .4em 2.1em .4em 1em; }
-.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 
2.1em; }
-/* no icon support for input elements, provide padding by default */
-input.ui-button { padding: .4em 1em; }
-
-/*button icon element(s) */
-.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; }
-.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
-.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; }
-.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; }
-.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only 
.ui-button-icon-secondary { right: .5em; }
-
-/*button sets*/
-.ui-buttonset { margin-right: 7px; }
-.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
-
-/* workarounds */
-button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra 
padding in Firefox */
-/*
- * jQuery UI Datepicker 1.8.10
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker#theming
- */
-.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
-.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
-.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { 
position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
-.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker 
.ui-datepicker-next-hover { top: 1px; }
-.ui-datepicker .ui-datepicker-prev { left:2px; }
-.ui-datepicker .ui-datepicker-next { right:2px; }
-.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
-.ui-datepicker .ui-datepicker-next-hover { right:1px; }
-.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;  }
-.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; 
text-align: center; }
-.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
-.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
-.ui-datepicker select.ui-datepicker-month, 
-.ui-datepicker select.ui-datepicker-year { width: 49%;}
-.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; 
margin:0 0 .4em; }
-.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; 
border: 0;  }
-.ui-datepicker td { border: 0; padding: 1px; }
-.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; 
text-align: right; text-decoration: none; }
-.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; }
-.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em 
.2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; 
overflow:visible; }
-.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { 
float:left; }
-
-/* with multiple calendars */
-.ui-datepicker.ui-datepicker-multi { width:auto; }
-.ui-datepicker-multi .ui-datepicker-group { float:left; }
-.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto 
.4em; }
-.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
-.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
-.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
-.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { 
border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { 
border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
-.ui-datepicker-row-break { clear:both; width:100%; }
-
-/* RTL support */
-.ui-datepicker-rtl { direction: rtl; }
-.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { 
float:right; }
-.ui-datepicker-rtl .ui-datepicker-group { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { 
border-right-width:0; border-left-width:1px; }
-.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { 
border-right-width:0; border-left-width:1px; }
-
-/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
-.ui-datepicker-cover {
-    display: none; /*sorry for IE5*/
-    display/**/: block; /*sorry for IE5*/
-    position: absolute; /*must have*/
-    z-index: -1; /*must have*/
-    filter: mask(); /*must have*/
-    top: -4px; /*must have*/
-    left: -4px; /*must have*/
-    width: 200px; /*must have*/
-    height: 200px; /*must have*/
-}/*
- * jQuery UI Dialog 1.8.10
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Dialog#theming
- */
-.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: 
hidden; }
-.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative;  }
-.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } 
-.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 
50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
-.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
-.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog 
.ui-dialog-titlebar-close:focus { padding: 0; }
-.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 
1em; background: none; overflow: auto; zoom: 1; }
-.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; }
-.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
-.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: 
pointer; }
-.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 
3px; }
-.ui-draggable .ui-dialog-titlebar { cursor: move; }
-/*
- * jQuery UI Progressbar 1.8.10
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Progressbar#theming
- */
-.ui-progressbar { height:2em; text-align: left; }
-.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/*
- * jQuery UI Resizable 1.8.10
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Resizable#theming
- */
-.ui-resizable { position: relative;}
-.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; 
display: block;}
-.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide 
.ui-resizable-handle { display: none; }
-.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 
0; }
-.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; 
left: 0; }
-.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 
100%; }
-.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 
100%; }
-.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; 
bottom: 1px; }
-.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; 
bottom: -5px; }
-.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; 
top: -5px; }
-.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; 
top: -5px;}/*
- * jQuery UI Selectable 1.8.10
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Selectable#theming
- */
-.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted 
black; }
-/*
- * jQuery UI Slider 1.8.10
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Slider#theming
- */
-.ui-slider { position: relative; text-align: left; }
-.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; 
height: 1.2em; cursor: default; }
-.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; 
display: block; border: 0; background-position: 0 0; }
-
-.ui-slider-horizontal { height: .8em; }
-.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
-.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
-.ui-slider-horizontal .ui-slider-range-min { left: 0; }
-.ui-slider-horizontal .ui-slider-range-max { right: 0; }
-
-.ui-slider-vertical { width: .8em; height: 100px; }
-.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; 
margin-bottom: -.6em; }
-.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
-.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
-.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
- * jQuery UI Tabs 1.8.10
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Tabs#theming
- */
-.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") */
-.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
-.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; }
-.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: 
none; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 
1px; }
-.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; }
-.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... */
-.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; 
background: none; }
-.ui-tabs .ui-tabs-hide { display: none !important; }
-/*
- * jQuery UI CSS Framework 1.8.10
- *
- * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/
- */
-
-
-/* Component containers
-----------------------------------*/
-.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 
1.1em/*{fsDefault}*/; }
-.ui-widget .ui-widget { font-size: 1em; }
-.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { 
font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; }
-.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}*/; }
-.ui-widget-content a { color: #222222/*{fcContent}*/; }
-.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; }
-.ui-widget-header a { color: #222222/*{fcHeader}*/; }
-
-/* Interaction states
-----------------------------------*/
-.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}*/; }
-.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { 
color: #555555/*{fcDefault}*/; text-decoration: none; }
-.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}*/; }
-.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; 
text-decoration: none; }
-.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}*/; }
-.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { 
color: #212121/*{fcActive}*/; text-decoration: none; }
-.ui-widget :active { outline: none; }
-
-/* Interaction Cues
-----------------------------------*/
-.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}*/; }
-.ui-state-highlight a, .ui-widget-content .ui-state-highlight 
a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; }
-.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}*/; }
-.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header 
.ui-state-error a { color: #cd0a0a/*{fcError}*/; }
-.ui-state-error-text, .ui-widget-content .ui-state-error-text, 
.ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; }
-.ui-priority-primary, .ui-widget-content .ui-priority-primary, 
.ui-widget-header .ui-priority-primary { font-weight: bold; }
-.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  
.ui-widget-header .ui-priority-secondary { opacity: .7; 
filter:Alpha(Opacity=70); font-weight: normal; }
-.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header 
.ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: 
none; }
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { width: 16px; height: 16px; background-image: 
url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
-.ui-widget-content .ui-icon {background-image: 
url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
-.ui-widget-header .ui-icon {background-image: 
url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; }
-.ui-state-default .ui-icon { background-image: 
url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; }
-.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: 
url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; }
-.ui-state-active .ui-icon {background-image: 
url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; }
-.ui-state-highlight .ui-icon {background-image: 
url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; }
-.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: 
url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; }
-
-/* positioning */
-.ui-icon-carat-1-n { background-position: 0 0; }
-.ui-icon-carat-1-ne { background-position: -16px 0; }
-.ui-icon-carat-1-e { background-position: -32px 0; }
-.ui-icon-carat-1-se { background-position: -48px 0; }
-.ui-icon-carat-1-s { background-position: -64px 0; }
-.ui-icon-carat-1-sw { background-position: -80px 0; }
-.ui-icon-carat-1-w { background-position: -96px 0; }
-.ui-icon-carat-1-nw { background-position: -112px 0; }
-.ui-icon-carat-2-n-s { background-position: -128px 0; }
-.ui-icon-carat-2-e-w { background-position: -144px 0; }
-.ui-icon-triangle-1-n { background-position: 0 -16px; }
-.ui-icon-triangle-1-ne { background-position: -16px -16px; }
-.ui-icon-triangle-1-e { background-position: -32px -16px; }
-.ui-icon-triangle-1-se { background-position: -48px -16px; }
-.ui-icon-triangle-1-s { background-position: -64px -16px; }
-.ui-icon-triangle-1-sw { background-position: -80px -16px; }
-.ui-icon-triangle-1-w { background-position: -96px -16px; }
-.ui-icon-triangle-1-nw { background-position: -112px -16px; }
-.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
-.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
-.ui-icon-arrow-1-n { background-position: 0 -32px; }
-.ui-icon-arrow-1-ne { background-position: -16px -32px; }
-.ui-icon-arrow-1-e { background-position: -32px -32px; }
-.ui-icon-arrow-1-se { background-position: -48px -32px; }
-.ui-icon-arrow-1-s { background-position: -64px -32px; }
-.ui-icon-arrow-1-sw { background-position: -80px -32px; }
-.ui-icon-arrow-1-w { background-position: -96px -32px; }
-.ui-icon-arrow-1-nw { background-position: -112px -32px; }
-.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
-.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
-.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
-.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
-.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
-.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
-.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
-.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
-.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
-.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
-.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
-.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
-.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
-.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
-.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
-.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
-.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
-.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
-.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
-.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
-.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
-.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
-.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
-.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
-.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
-.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
-.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
-.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
-.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
-.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
-.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
-.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
-.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
-.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
-.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
-.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
-.ui-icon-arrow-4 { background-position: 0 -80px; }
-.ui-icon-arrow-4-diag { background-position: -16px -80px; }
-.ui-icon-extlink { background-position: -32px -80px; }
-.ui-icon-newwin { background-position: -48px -80px; }
-.ui-icon-refresh { background-position: -64px -80px; }
-.ui-icon-shuffle { background-position: -80px -80px; }
-.ui-icon-transfer-e-w { background-position: -96px -80px; }
-.ui-icon-transferthick-e-w { background-position: -112px -80px; }
-.ui-icon-folder-collapsed { background-position: 0 -96px; }
-.ui-icon-folder-open { background-position: -16px -96px; }
-.ui-icon-document { background-position: -32px -96px; }
-.ui-icon-document-b { background-position: -48px -96px; }
-.ui-icon-note { background-position: -64px -96px; }
-.ui-icon-mail-closed { background-position: -80px -96px; }
-.ui-icon-mail-open { background-position: -96px -96px; }
-.ui-icon-suitcase { background-position: -112px -96px; }
-.ui-icon-comment { background-position: -128px -96px; }
-.ui-icon-person { background-position: -144px -96px; }
-.ui-icon-print { background-position: -160px -96px; }
-.ui-icon-trash { background-position: -176px -96px; }
-.ui-icon-locked { background-position: -192px -96px; }
-.ui-icon-unlocked { background-position: -208px -96px; }
-.ui-icon-bookmark { background-position: -224px -96px; }
-.ui-icon-tag { background-position: -240px -96px; }
-.ui-icon-home { background-position: 0 -112px; }
-.ui-icon-flag { background-position: -16px -112px; }
-.ui-icon-calendar { background-position: -32px -112px; }
-.ui-icon-cart { background-position: -48px -112px; }
-.ui-icon-pencil { background-position: -64px -112px; }
-.ui-icon-clock { background-position: -80px -112px; }
-.ui-icon-disk { background-position: -96px -112px; }
-.ui-icon-calculator { background-position: -112px -112px; }
-.ui-icon-zoomin { background-position: -128px -112px; }
-.ui-icon-zoomout { background-position: -144px -112px; }
-.ui-icon-search { background-position: -160px -112px; }
-.ui-icon-wrench { background-position: -176px -112px; }
-.ui-icon-gear { background-position: -192px -112px; }
-.ui-icon-heart { background-position: -208px -112px; }
-.ui-icon-star { background-position: -224px -112px; }
-.ui-icon-link { background-position: -240px -112px; }
-.ui-icon-cancel { background-position: 0 -128px; }
-.ui-icon-plus { background-position: -16px -128px; }
-.ui-icon-plusthick { background-position: -32px -128px; }
-.ui-icon-minus { background-position: -48px -128px; }
-.ui-icon-minusthick { background-position: -64px -128px; }
-.ui-icon-close { background-position: -80px -128px; }
-.ui-icon-closethick { background-position: -96px -128px; }
-.ui-icon-key { background-position: -112px -128px; }
-.ui-icon-lightbulb { background-position: -128px -128px; }
-.ui-icon-scissors { background-position: -144px -128px; }
-.ui-icon-clipboard { background-position: -160px -128px; }
-.ui-icon-copy { background-position: -176px -128px; }
-.ui-icon-contact { background-position: -192px -128px; }
-.ui-icon-image { background-position: -208px -128px; }
-.ui-icon-video { background-position: -224px -128px; }
-.ui-icon-script { background-position: -240px -128px; }
-.ui-icon-alert { background-position: 0 -144px; }
-.ui-icon-info { background-position: -16px -144px; }
-.ui-icon-notice { background-position: -32px -144px; }
-.ui-icon-help { background-position: -48px -144px; }
-.ui-icon-check { background-position: -64px -144px; }
-.ui-icon-bullet { background-position: -80px -144px; }
-.ui-icon-radio-off { background-position: -96px -144px; }
-.ui-icon-radio-on { background-position: -112px -144px; }
-.ui-icon-pin-w { background-position: -128px -144px; }
-.ui-icon-pin-s { background-position: -144px -144px; }
-.ui-icon-play { background-position: 0 -160px; }
-.ui-icon-pause { background-position: -16px -160px; }
-.ui-icon-seek-next { background-position: -32px -160px; }
-.ui-icon-seek-prev { background-position: -48px -160px; }
-.ui-icon-seek-end { background-position: -64px -160px; }
-.ui-icon-seek-start { background-position: -80px -160px; }
-/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
-.ui-icon-seek-first { background-position: -80px -160px; }
-.ui-icon-stop { background-position: -96px -160px; }
-.ui-icon-eject { background-position: -112px -160px; }
-.ui-icon-volume-off { background-position: -128px -160px; }
-.ui-icon-volume-on { background-position: -144px -160px; }
-.ui-icon-power { background-position: 0 -176px; }
-.ui-icon-signal-diag { background-position: -16px -176px; }
-.ui-icon-signal { background-position: -32px -176px; }
-.ui-icon-battery-0 { background-position: -48px -176px; }
-.ui-icon-battery-1 { background-position: -64px -176px; }
-.ui-icon-battery-2 { background-position: -80px -176px; }
-.ui-icon-battery-3 { background-position: -96px -176px; }
-.ui-icon-circle-plus { background-position: 0 -192px; }
-.ui-icon-circle-minus { background-position: -16px -192px; }
-.ui-icon-circle-close { background-position: -32px -192px; }
-.ui-icon-circle-triangle-e { background-position: -48px -192px; }
-.ui-icon-circle-triangle-s { background-position: -64px -192px; }
-.ui-icon-circle-triangle-w { background-position: -80px -192px; }
-.ui-icon-circle-triangle-n { background-position: -96px -192px; }
-.ui-icon-circle-arrow-e { background-position: -112px -192px; }
-.ui-icon-circle-arrow-s { background-position: -128px -192px; }
-.ui-icon-circle-arrow-w { background-position: -144px -192px; }
-.ui-icon-circle-arrow-n { background-position: -160px -192px; }
-.ui-icon-circle-zoomin { background-position: -176px -192px; }
-.ui-icon-circle-zoomout { background-position: -192px -192px; }
-.ui-icon-circle-check { background-position: -208px -192px; }
-.ui-icon-circlesmall-plus { background-position: 0 -208px; }
-.ui-icon-circlesmall-minus { background-position: -16px -208px; }
-.ui-icon-circlesmall-close { background-position: -32px -208px; }
-.ui-icon-squaresmall-plus { background-position: -48px -208px; }
-.ui-icon-squaresmall-minus { background-position: -64px -208px; }
-.ui-icon-squaresmall-close { background-position: -80px -208px; }
-.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
-.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
-.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
-.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
-.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
-.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Corner radius */
-.ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; 
-webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 
4px/*{cornerRadius}*/; }
-.ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; 
-webkit-border-top-right-radius: 4px/*{cornerRadius}*/; 
border-top-right-radius: 4px/*{cornerRadius}*/; }
-.ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; 
-webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; 
border-bottom-left-radius: 4px/*{cornerRadius}*/; }
-.ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; 
-webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; 
border-bottom-right-radius: 4px/*{cornerRadius}*/; }
-.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}*/; }
-.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}*/; }
-.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}*/; }
-.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}*/; }
-.ui-corner-all { -moz-border-radius: 4px/*{cornerRadius}*/; 
-webkit-border-radius: 4px/*{cornerRadius}*/; border-radius: 
4px/*{cornerRadius}*/; }
-
-/* Overlays */
-.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}*/; }
-.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
diff --git a/jquery.mw.linksuggest.js b/jquery.mw.linksuggest.js
index 6995c55..5783537 100644
--- a/jquery.mw.linksuggest.js
+++ b/jquery.mw.linksuggest.js
@@ -1,8 +1,8 @@
 /*
- * jQuery MediaWiki LinkSuggest 1.1.0
+ * jQuery MediaWiki LinkSuggest 1.3.1
  * JavaScript for LinkSuggest extension
  *
- * Copyright © 2010
+ * Copyright © 2010-2014
  * Authors: Inez Korczyński (korczynski at gmail dot com)
  *          Jesús Martínez Novo (martineznovo at gmail dot com)
  * Licensed under the GPL (GPL-LICENSE.txt) license.
@@ -12,11 +12,18 @@
  */
 ( function( $ ) {
 
+// Private static variables
+var testerElement = null, // Tester element, global for caching and not 
recreate it everytime
+       cachedElement = null, // Cached element of the autocomplete to compare
+       cachedText = null, // Cached text before the position of the link
+       cachedPosition = null, // Cached position of the drop-down
+       suppressKeyPress;
+
 $.widget( 'mw.linksuggest', {
        options: {
                minLength: 3,
                delay: 300,
-               url: window.wgScript
+               url: mw.config.get( 'wgScript' )
        },
        _create: function() {
                var self = this;
@@ -39,32 +46,91 @@
                };
                // Opera only prevents default behavior on keypress, needed for
                // capturing arrows and enter
-               var eventType = $.browser.opera ? 'keypress' : 'keydown';
                this.options = $.extend( opt, this.options );
                this.element.autocomplete( this.options );
                // Overwrite the keydown event of autocomplete to fix some 
undesired key events
-               if ( typeof( this.element.data( 'events' ).keydown[0] ) !== 
undefined ) {
-                       this._legacyKeydown = this.element.data( 'events' 
).keydown[0].handler;
-               }
-               this.element.unbind( 'keydown.autocomplete' )
-               .bind( eventType + '.linksuggest', function( thisInstance ) {
-                       return function() {
-                               thisInstance._keydown.apply( thisInstance, 
arguments );
-                       };
-               }( this ));
+               this.element.unbind( 'keydown.autocomplete' ).unbind( 
'kepress.autocomplete' )
+                       .bind( 'keydown.linksuggest',
+                               function( thisInstance ) {
+                                       return function() {
+                                               thisInstance._keydown.apply( 
thisInstance, arguments );
+                                       };
+                               }( this ))
+                       .bind( 'keypress.linksuggest', function() {
+                                       if ( suppressKeyPress ) {
+                                               suppressKeyPress = false;
+                                               event.preventDefault();
+                                       }
+                               });
                // deactivate some menu weird behavior
                this.element.data( 'autocomplete' ).menu.options.blur = null;
        },
-       _legacyKeydown: null,
+       // function copied from jQuery UI Autocomplete 1.8.17. Keep in sync 
with the same used in MediaWiki
+       _legacyKeydown: function( event ) {
+               var self = this;
+               if ( self.options.disabled || self.element.prop( 'readOnly' ) ) 
{
+                       return;
+               }
+
+               suppressKeyPress = false;
+               var keyCode = $.ui.keyCode;
+               switch ( event.keyCode ) {
+                       case keyCode.PAGE_UP:
+                               self._move( 'previousPage', event );
+                               break;
+                       case keyCode.PAGE_DOWN:
+                               self._move( 'nextPage', event );
+                               break;
+                       case keyCode.UP:
+                               self._move( 'previous', event );
+                               // prevent moving cursor to beginning of text 
field in some browsers
+                               event.preventDefault();
+                               break;
+                       case keyCode.DOWN:
+                               self._move( 'next', event );
+                               // prevent moving cursor to end of text field 
in some browsers
+                               event.preventDefault();
+                               break;
+                       case keyCode.ENTER:
+                       case keyCode.NUMPAD_ENTER:
+                               // when menu is open and has focus
+                               if ( self.menu.active ) {
+                                       // #6055 - Opera still allows the 
keypress to occur
+                                       // which causes forms to submit
+                                       suppressKeyPress = true;
+                                       event.preventDefault();
+                               }
+                               // passthrough - ENTER and TAB both select the 
current element
+                       case keyCode.TAB:
+                               if ( !self.menu.active ) {
+                                       return;
+                               }
+                               self.menu.select( event );
+                               break;
+                       case keyCode.ESCAPE:
+                               self.element.val( self.term );
+                               self.close( event );
+                               break;
+                       default:
+                               // keypress is triggered before the input value 
is changed
+                               clearTimeout( self.searching );
+                               self.searching = setTimeout( function() {
+                                       // only search if the value has changed
+                                       if ( self.term != self.element.val() ) {
+                                               self.selectedItem = null;
+                                               self.search( null, event );
+                                       }
+                               }, self.options.delay );
+                               break;
+               }
+       },
        _keydown: function( event ) {
                var keyCode = $.ui.keyCode;
-               switch( event.keyCode ) {
+               switch ( event.keyCode ) {
                        case keyCode.UP:
                        case keyCode.DOWN:
                                if ( !this.element.data( 'autocomplete' 
).menu.element.is( ':visible' ) ) {
-                                       // If menu element is not visible, 
ignore.
-                                       // Autocomplete event handler just 
prevents default
-                                       // behavior, which is not what we want
+                                       // If menu element is not visible, 
ignore. Autocomplete event handler just prevents default behavior, which is not 
what we want
                                        return;
                                }
                                break;
@@ -96,10 +162,8 @@
                                return
                                break;
                }
-               // If we not already returned from this function, fire the old 
autocomplete handler
-               if ( $.isFunction( this._legacyKeydown ) ) {
-                       this._legacyKeydown.apply( this.element.data( 
'autocomplete' ), arguments );
-               }
+               // If we've not returned already from this function, fire the 
old autocomplete handler
+               this._legacyKeydown.apply( this.element.data( 'autocomplete' ), 
arguments );
        },
        _sendQuery: function( request, response ) {
                var emptyset = [];
@@ -201,7 +265,7 @@
                                this.options.url,
                                {
                                        action: 'ajax',
-                                       rs: 'getLinkSuggest',
+                                       rs: 'LinkSuggest::get',
                                        query: sQueryReal
                                },
                                this._responseWrapper( this, response, format, 
stripPrefix )
@@ -223,7 +287,7 @@
                return $.map( data.split( '\n' ), function( n ) {
                        if ( stripPrefix ) {
                                var pos = n.indexOf( ':' );
-                               if ( pos >= 0 ) {
+                               if ( pos != -1 ) {
                                        n = n.substr( pos + 1 );
                                }
                        }
@@ -293,73 +357,66 @@
                }
        },
        _getCaretPosition: function() {
+               var result = [0, 0];
                var control = this.element[0];
                var left = 0;
                var top = 0;
-               var tester = $( '<div 
style="position:absolute;top:-1000px;left:-1000px;white-space:pre-wrap;visibility:hidden;"></div>'
 );
                var text = this._getText();
                var caret = this._getCaret();
-               var initialcaret = caret;
+               var initialCaret = caret;
                if ( caret == 0 ) {
                        // This should never happen
-                       return [ 0, 0 ];
+                       return result;
                }
                // Get the position at the start of the link/template
                for ( var i = caret - 1; i >= 0; i-- ) {
-                       var c = text.charAt( i );
+                       var c = text.charAt(i);
                        if ( c == '[' || c == '{' ) {
-                               initialcaret = i + 1;
+                               initialCaret = i + 1;
                                break;
                        }
                }
-               // Create a tester container to get the size of the text before 
the
-               // caret, and thus the position inside the element
-               // WARNING: You MUST apply a font-family CSS attribute to the 
textarea
-               // (to this particular one, or a generic `textarea {font-famly: 
whatever;}´)
-               // so IE could retrieve the correct font-family used, otherwise 
it may
-               // fail to position the drop-down correctly!
-               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(' ');
-               for ( var i = 0; i < props.length; i++ ) {
-                       tester.css( props[i], this.element.css( props[i] ) );
-               }
-               // Using clientWidth because if the textarea has scroll, the 
effective
-               // width for word wrap doesn't include the width used by the 
scrollbar
-               tester.width( control.clientWidth ).appendTo( document.body 
).text( text.substr( 0, caret ) );
-               left = tester.outerWidth();
-               top = tester.outerHeight() - control.scrollTop;
-               var initialheight = tester.height();
-               var paddingText = '';
-               // Insert the text until the initial position of the element we 
want to
-               // suggest, plus a space, to get the characters needed to force 
a word
-               // wrap to a new line
-               tester.text( text.substr( 0, initialcaret ) + ' ' );
-               if ( tester.height() < initialheight ) {
-                       // If the height has been reduced then the element to 
suggest is
-                       // forcing a word wrap to a new line and it's on the 
left side of
-                       // the textarea
-                       left = 0;
-               } else {
-                       // Get how many characters we need to force a word wrap 
to a new
-                       // line, and then transform it in an actual size
-                       // If we go beyond 500, something must be wrong
-                       for ( var i = 1; i < 500; i++ ) {
-                               paddingText += 'A';
-                               // msie appendData doesn't update the height()
-                               if ( $.browser.msie ) {
-                                       tester[0].firstChild.data += 'A';
-                               } else {
-                                       tester[0].firstChild.appendData( 'A' );
-                               }
-                               if ( tester.height() > initialheight ) {
-                                       tester.css( 'width', 'auto' );
-                                       tester.text( paddingText );
-                                       left -= tester.outerWidth();
-                                       break;
-                               }
+               var textBeforePosition = text.substr( 0, initialCaret );
+               // If the control isnot the same, clear the cached tester 
element
+               if ( cachedElement !== control ) {
+                       cachedElement = control;
+                       if ( testerElement !== null ) {
+                               testerElement.remove();
+                               testerElement = null;
                        }
                }
-               tester.remove();
-               return [ left, top ];
+               // Use the cached tester element. Improves speed
+               if ( testerElement === null ) {
+                       testerElement = $( '<div 
style="position:absolute;top:-2000px;left:-2000px;white-space:pre-wrap;visibility:hidden;"></div>'
 );
+                       // Create a tester container to get the size of the 
text before the caret, and thus the position inside the element
+                       // WARNING: You MUST apply a font-family CSS attribute 
to the textarea (to this particular one, or a generic
+                       //      `textarea {font-famly: whatever;}´) so IE could 
retrieve the correct font-family used, otherwise it may
+                       //  fail to position the drop-down correctly!
+                       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( ' ' );
+                       for ( var i = 0; i < props.length; i++ ) {
+                               testerElement.css( props[i], this.element.css( 
props[i] ) );
+                       }
+               } else {
+                       // If the element and the text is the same, return the 
cached results
+                       if ( cachedText === textBeforePosition ) {
+                               return cachedPosition;
+                       }
+               }
+               // An element that will provide the caret position
+               var caretElem = $( '<span></span>' ).text( text.substring( 
initialCaret, caret ) );
+               // Using scrollWidth because if the textarea has scroll, the 
effective
+               // width for word wrap doesn't include the width used by the 
scrollbar
+               testerElement
+                       .width( control.scrollWidth )
+                       .text( textBeforePosition )
+                       .append( caretElem )
+                       .appendTo( document.body );
+               var pos = caretElem.position();
+               result = [ pos.left, pos.top + caretElem.height() - 
control.scrollTop ];
+               // Store in the cache
+               cachedText = textBeforePosition;
+               cachedPosition = result;
+               return result;
        },
        _open: function( event, ui ) {
                var menu = this.element.data( 'autocomplete' ).menu.element;
@@ -382,9 +439,8 @@
 
 }( jQuery ));
 
-// Implementation: This should be done injecting this code into MediaWiki, not
-// in this JS file
+// Implementation: This should be done injecting this code into MediaWiki, not 
in this JS file
 $( function() {
        // Apply font-style for bug in IE. This should be done using a style 
sheet
        $( '#wpTextbox1' ).css( 'font-family', 'monospace' ).linksuggest();
-});
\ No newline at end of file
+} );
\ No newline at end of file
diff --git a/jquery.widget.position.autocomplete-1.8.2.js 
b/jquery.widget.position.autocomplete-1.8.2.js
deleted file mode 100644
index 77c4003..0000000
--- a/jquery.widget.position.autocomplete-1.8.2.js
+++ /dev/null
@@ -1,1201 +0,0 @@
-// https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.js
-
-/*!
- * jQuery UI 1.8.2
- *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI
- */
-
-(function($) {
-
-// prevent duplicate loading
-// this is only a problem because we proxy existing functions
-// and we don't want to double proxy them
-$.ui = $.ui || {};
-if ($.ui.version) {
-       return;
-}
-
-//Helper functions and ui object
-$.extend($.ui, {
-       version: "1.8.2",
-
-       // $.ui.plugin is deprecated.  Use the proxy pattern instead.
-       plugin: {
-               add: function(module, option, set) {
-                       var proto = $.ui[module].prototype;
-                       for(var i in set) {
-                               proto.plugins[i] = proto.plugins[i] || [];
-                               proto.plugins[i].push([option, set[i]]);
-                       }
-               },
-               call: function(instance, name, args) {
-                       var set = instance.plugins[name];
-                       if(!set || !instance.element[0].parentNode) { return; }
-
-                       for (var i = 0; i < set.length; i++) {
-                               if (instance.options[set[i][0]]) {
-                                       set[i][1].apply(instance.element, args);
-                               }
-                       }
-               }
-       },
-
-       contains: function(a, b) {
-               return document.compareDocumentPosition
-                       ? a.compareDocumentPosition(b) & 16
-                       : a !== b && a.contains(b);
-       },
-
-       hasScroll: function(el, a) {
-
-               //If overflow is hidden, the element might have extra content, 
but the user wants to hide it
-               if ($(el).css('overflow') == 'hidden') { return false; }
-
-               var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop',
-                       has = false;
-
-               if (el[scroll] > 0) { return true; }
-
-               // TODO: determine which cases actually cause this to happen
-               // if the element doesn't have the scroll set, see if it's 
possible to
-               // set the scroll
-               el[scroll] = 1;
-               has = (el[scroll] > 0);
-               el[scroll] = 0;
-               return has;
-       },
-
-       isOverAxis: function(x, reference, size) {
-               //Determines when x coordinate is over "b" element axis
-               return (x > reference) && (x < (reference + size));
-       },
-
-       isOver: function(y, x, top, left, height, width) {
-               //Determines when x, y coordinates is over "b" element
-               return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, 
left, width);
-       },
-
-       keyCode: {
-               ALT: 18,
-               BACKSPACE: 8,
-               CAPS_LOCK: 20,
-               COMMA: 188,
-               COMMAND: 91,
-               COMMAND_LEFT: 91, // COMMAND
-               COMMAND_RIGHT: 93,
-               CONTROL: 17,
-               DELETE: 46,
-               DOWN: 40,
-               END: 35,
-               ENTER: 13,
-               ESCAPE: 27,
-               HOME: 36,
-               INSERT: 45,
-               LEFT: 37,
-               MENU: 93, // COMMAND_RIGHT
-               NUMPAD_ADD: 107,
-               NUMPAD_DECIMAL: 110,
-               NUMPAD_DIVIDE: 111,
-               NUMPAD_ENTER: 108,
-               NUMPAD_MULTIPLY: 106,
-               NUMPAD_SUBTRACT: 109,
-               PAGE_DOWN: 34,
-               PAGE_UP: 33,
-               PERIOD: 190,
-               RIGHT: 39,
-               SHIFT: 16,
-               SPACE: 32,
-               TAB: 9,
-               UP: 38,
-               WINDOWS: 91 // COMMAND
-       }
-});
-
-//jQuery plugins
-$.fn.extend({
-       _focus: $.fn.focus,
-       focus: function(delay, fn) {
-               return typeof delay === 'number'
-                       ? this.each(function() {
-                               var elem = this;
-                               setTimeout(function() {
-                                       $(elem).focus();
-                                       (fn && fn.call(elem));
-                               }, delay);
-                       })
-                       : this._focus.apply(this, arguments);
-       },
-       
-       enableSelection: function() {
-               return this
-                       .attr('unselectable', 'off')
-                       .css('MozUserSelect', '');
-       },
-
-       disableSelection: function() {
-               return this
-                       .attr('unselectable', 'on')
-                       .css('MozUserSelect', 'none');
-       },
-
-       scrollParent: function() {
-               var scrollParent;
-               if(($.browser.msie && 
(/(static|relative)/).test(this.css('position'))) || 
(/absolute/).test(this.css('position'))) {
-                       scrollParent = this.parents().filter(function() {
-                               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));
-                       }).eq(0);
-               } else {
-                       scrollParent = this.parents().filter(function() {
-                               return 
(/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
-                       }).eq(0);
-               }
-
-               return (/fixed/).test(this.css('position')) || 
!scrollParent.length ? $(document) : scrollParent;
-       },
-
-       zIndex: function(zIndex) {
-               if (zIndex !== undefined) {
-                       return this.css('zIndex', zIndex);
-               }
-               
-               if (this.length) {
-                       var elem = $(this[0]), position, value;
-                       while (elem.length && elem[0] !== document) {
-                               // Ignore z-index if position is set to a value 
where z-index is ignored by the browser
-                               // This makes behavior of this function 
consistent across browsers
-                               // WebKit always returns auto if the element is 
positioned
-                               position = elem.css('position');
-                               if (position == 'absolute' || position == 
'relative' || position == 'fixed')
-                               {
-                                       // IE returns 0 when zIndex is not 
specified
-                                       // other browsers return a string
-                                       // we ignore the case of nested 
elements with an explicit value of 0
-                                       // <div style="z-index: -10;"><div 
style="z-index: 0;"></div></div>
-                                       value = parseInt(elem.css('zIndex'));
-                                       if (!isNaN(value) && value != 0) {
-                                               return value;
-                                       }
-                               }
-                               elem = elem.parent();
-                       }
-               }
-
-               return 0;
-       }
-});
-
-
-//Additional selectors
-$.extend($.expr[':'], {
-       data: function(elem, i, match) {
-               return !!$.data(elem, match[3]);
-       },
-
-       focusable: function(element) {
-               var nodeName = element.nodeName.toLowerCase(),
-                       tabIndex = $.attr(element, 'tabindex');
-               return (/input|select|textarea|button|object/.test(nodeName)
-                       ? !element.disabled
-                       : 'a' == nodeName || 'area' == nodeName
-                               ? element.href || !isNaN(tabIndex)
-                               : !isNaN(tabIndex))
-                       // the element and all of its ancestors must be visible
-                       // the browser may report that the area is hidden
-                       && !$(element)['area' == nodeName ? 'parents' : 
'closest'](':hidden').length;
-       },
-
-       tabbable: function(element) {
-               var tabIndex = $.attr(element, 'tabindex');
-               return (isNaN(tabIndex) || tabIndex >= 0) && 
$(element).is(':focusable');
-       }
-});
-
-})(jQuery);
-/*!
- * jQuery UI Widget 1.8.2
- *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI/Widget
- */
-(function( $ ) {
-
-var _remove = $.fn.remove;
-
-$.fn.remove = function( selector, keepData ) {
-       return this.each(function() {
-               if ( !keepData ) {
-                       if ( !selector || $.filter( selector, [ this ] ).length 
) {
-                               $( "*", this ).add( this ).each(function() {
-                                       $( this ).triggerHandler( "remove" );
-                               });
-                       }
-               }
-               return _remove.call( $(this), selector, keepData );
-       });
-};
-
-$.widget = function( name, base, prototype ) {
-       var namespace = name.split( "." )[ 0 ],
-               fullName;
-       name = name.split( "." )[ 1 ];
-       fullName = namespace + "-" + name;
-
-       if ( !prototype ) {
-               prototype = base;
-               base = $.Widget;
-       }
-
-       // create selector for plugin
-       $.expr[ ":" ][ fullName ] = function( elem ) {
-               return !!$.data( elem, name );
-       };
-
-       $[ namespace ] = $[ namespace ] || {};
-       $[ namespace ][ name ] = function( options, element ) {
-               // allow instantiation without initializing for simple 
inheritance
-               if ( arguments.length ) {
-                       this._createWidget( options, element );
-               }
-       };
-
-       var basePrototype = new base();
-       // we need to make the options hash a property directly on the new 
instance
-       // otherwise we'll modify the options hash on the prototype that we're
-       // inheriting from
-//     $.each( basePrototype, function( key, val ) {
-//             if ( $.isPlainObject(val) ) {
-//                     basePrototype[ key ] = $.extend( {}, val );
-//             }
-//     });
-       basePrototype.options = $.extend( {}, basePrototype.options );
-       $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
-               namespace: namespace,
-               widgetName: name,
-               widgetEventPrefix: $[ namespace ][ name 
].prototype.widgetEventPrefix || name,
-               widgetBaseClass: fullName
-       }, prototype );
-
-       $.widget.bridge( name, $[ namespace ][ name ] );
-};
-
-$.widget.bridge = function( name, object ) {
-       $.fn[ name ] = function( options ) {
-               var isMethodCall = typeof options === "string",
-                       args = Array.prototype.slice.call( arguments, 1 ),
-                       returnValue = this;
-
-               // allow multiple hashes to be passed on init
-               options = !isMethodCall && args.length ?
-                       $.extend.apply( null, [ true, options ].concat(args) ) :
-                       options;
-
-               // prevent calls to internal methods
-               if ( isMethodCall && options.substring( 0, 1 ) === "_" ) {
-                       return returnValue;
-               }
-
-               if ( isMethodCall ) {
-                       this.each(function() {
-                               var instance = $.data( this, name ),
-                                       methodValue = instance && $.isFunction( 
instance[options] ) ?
-                                               instance[ options ].apply( 
instance, args ) :
-                                               instance;
-                               if ( methodValue !== instance && methodValue 
!== undefined ) {
-                                       returnValue = methodValue;
-                                       return false;
-                               }
-                       });
-               } else {
-                       this.each(function() {
-                               var instance = $.data( this, name );
-                               if ( instance ) {
-                                       if ( options ) {
-                                               instance.option( options );
-                                       }
-                                       instance._init();
-                               } else {
-                                       $.data( this, name, new object( 
options, this ) );
-                               }
-                       });
-               }
-
-               return returnValue;
-       };
-};
-
-$.Widget = function( options, element ) {
-       // allow instantiation without initializing for simple inheritance
-       if ( arguments.length ) {
-               this._createWidget( options, element );
-       }
-};
-
-$.Widget.prototype = {
-       widgetName: "widget",
-       widgetEventPrefix: "",
-       options: {
-               disabled: false
-       },
-       _createWidget: function( options, element ) {
-               // $.widget.bridge stores the plugin instance, but we do it 
anyway
-               // so that it's stored even before the _create function runs
-               this.element = $( element ).data( this.widgetName, this );
-               this.options = $.extend( true, {},
-                       this.options,
-                       $.metadata && $.metadata.get( element )[ 
this.widgetName ],
-                       options );
-
-               var self = this;
-               this.element.bind( "remove." + this.widgetName, function() {
-                       self.destroy();
-               });
-
-               this._create();
-               this._init();
-       },
-       _create: function() {},
-       _init: function() {},
-
-       destroy: function() {
-               this.element
-                       .unbind( "." + this.widgetName )
-                       .removeData( this.widgetName );
-               this.widget()
-                       .unbind( "." + this.widgetName )
-                       .removeAttr( "aria-disabled" )
-                       .removeClass(
-                               this.widgetBaseClass + "-disabled " +
-                               "ui-state-disabled" );
-       },
-
-       widget: function() {
-               return this.element;
-       },
-
-       option: function( key, value ) {
-               var options = key,
-                       self = this;
-
-               if ( arguments.length === 0 ) {
-                       // don't return a reference to the internal hash
-                       return $.extend( {}, self.options );
-               }
-
-               if  (typeof key === "string" ) {
-                       if ( value === undefined ) {
-                               return this.options[ key ];
-                       }
-                       options = {};
-                       options[ key ] = value;
-               }
-
-               $.each( options, function( key, value ) {
-                       self._setOption( key, value );
-               });
-
-               return self;
-       },
-       _setOption: function( key, value ) {
-               this.options[ key ] = value;
-
-               if ( key === "disabled" ) {
-                       this.widget()
-                               [ value ? "addClass" : "removeClass"](
-                                       this.widgetBaseClass + "-disabled" + " 
" +
-                                       "ui-state-disabled" )
-                               .attr( "aria-disabled", value );
-               }
-
-               return this;
-       },
-
-       enable: function() {
-               return this._setOption( "disabled", false );
-       },
-       disable: function() {
-               return this._setOption( "disabled", true );
-       },
-
-       _trigger: function( type, event, data ) {
-               var callback = this.options[ type ];
-
-               event = $.Event( event );
-               event.type = ( type === this.widgetEventPrefix ?
-                       type :
-                       this.widgetEventPrefix + type ).toLowerCase();
-               data = data || {};
-
-               // copy original event properties over to the new event
-               // this would happen if we could call $.event.fix instead of 
$.Event
-               // but we don't have a way to force an event to be fixed 
multiple times
-               if ( event.originalEvent ) {
-                       for ( var i = $.event.props.length, prop; i; ) {
-                               prop = $.event.props[ --i ];
-                               event[ prop ] = event.originalEvent[ prop ];
-                       }
-               }
-
-               this.element.trigger( event, data );
-
-               return !( $.isFunction(callback) &&
-                       callback.call( this.element[0], event, data ) === false 
||
-                       event.isDefaultPrevented() );
-       }
-};
-
-})( jQuery );
-
-/*
- * jQuery UI Menu (not officially released)
- * 
- * This widget isn't yet finished and the API is subject to change. We plan to 
finish
- * it for the next release. You're welcome to give it a try anyway and give us 
feedback,
- * as long as you're okay with migrating your code later on. We can help with 
that, too.
- *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI/Menu
- *
- * Depends:
- *     jquery.ui.core.js
- *  jquery.ui.widget.js
- */
-(function($) {
-
-$.widget("ui.menu", {
-       _create: function() {
-               var self = this;
-               this.element
-                       .addClass("ui-menu ui-widget ui-widget-content 
ui-corner-all")
-                       .attr({
-                               role: "listbox",
-                               "aria-activedescendant": "ui-active-menuitem"
-                       })
-                       .click(function( event ) {
-                               if ( !$( event.target ).closest( ".ui-menu-item 
a" ).length ) {
-                                       return;
-                               }
-                               // temporary
-                               event.preventDefault();
-                               self.select( event );
-                       });
-               this.refresh();
-       },
-       
-       refresh: function() {
-               var self = this;
-
-               // don't refresh list items that are already adapted
-               var items = 
this.element.children("li:not(.ui-menu-item):has(a)")
-                       .addClass("ui-menu-item")
-                       .attr("role", "menuitem");
-               
-               items.children("a")
-                       .addClass("ui-corner-all")
-                       .attr("tabindex", -1)
-                       // mouseenter doesn't work with event delegation
-                       .mouseenter(function( event ) {
-                               self.activate( event, $(this).parent() );
-                       })
-                       .mouseleave(function() {
-                               self.deactivate();
-                       });
-       },
-
-       activate: function( event, item ) {
-               this.deactivate();
-               if (this.hasScroll()) {
-                       var offset = item.offset().top - 
this.element.offset().top,
-                               scroll = this.element.attr("scrollTop"),
-                               elementHeight = this.element.height();
-                       if (offset < 0) {
-                               this.element.attr("scrollTop", scroll + offset);
-                       } else if (offset > elementHeight) {
-                               this.element.attr("scrollTop", scroll + offset 
- elementHeight + item.height());
-                       }
-               }
-               this.active = item.eq(0)
-                       .children("a")
-                               .addClass("ui-state-hover")
-                               .attr("id", "ui-active-menuitem")
-                       .end();
-               this._trigger("focus", event, { item: item });
-       },
-
-       deactivate: function() {
-               if (!this.active) { return; }
-
-               this.active.children("a")
-                       .removeClass("ui-state-hover")
-                       .removeAttr("id");
-               this._trigger("blur");
-               this.active = null;
-       },
-
-       next: function(event) {
-               this.move("next", ".ui-menu-item:first", event);
-       },
-
-       previous: function(event) {
-               this.move("prev", ".ui-menu-item:last", event);
-       },
-
-       first: function() {
-               return this.active && !this.active.prev().length;
-       },
-
-       last: function() {
-               return this.active && !this.active.next().length;
-       },
-
-       move: function(direction, edge, event) {
-               if (!this.active) {
-                       this.activate(event, this.element.children(edge));
-                       return;
-               }
-               var next = this.active[direction + 
"All"](".ui-menu-item").eq(0);
-               if (next.length) {
-                       this.activate(event, next);
-               } else {
-                       this.activate(event, this.element.children(edge));
-               }
-       },
-
-       // TODO merge with previousPage
-       nextPage: function(event) {
-               if (this.hasScroll()) {
-                       // TODO merge with no-scroll-else
-                       if (!this.active || this.last()) {
-                               this.activate(event, 
this.element.children(":first"));
-                               return;
-                       }
-                       var base = this.active.offset().top,
-                               height = this.element.height(),
-                               result = 
this.element.children("li").filter(function() {
-                                       var close = $(this).offset().top - base 
- height + $(this).height();
-                                       // TODO improve approximation
-                                       return close < 10 && close > -10;
-                               });
-
-                       // TODO try to catch this earlier when scrollTop 
indicates the last page anyway
-                       if (!result.length) {
-                               result = this.element.children(":last");
-                       }
-                       this.activate(event, result);
-               } else {
-                       this.activate(event, this.element.children(!this.active 
|| this.last() ? ":first" : ":last"));
-               }
-       },
-
-       // TODO merge with nextPage
-       previousPage: function(event) {
-               if (this.hasScroll()) {
-                       // TODO merge with no-scroll-else
-                       if (!this.active || this.first()) {
-                               this.activate(event, 
this.element.children(":last"));
-                               return;
-                       }
-
-                       var base = this.active.offset().top,
-                               height = this.element.height();
-                               result = 
this.element.children("li").filter(function() {
-                                       var close = $(this).offset().top - base 
+ height - $(this).height();
-                                       // TODO improve approximation
-                                       return close < 10 && close > -10;
-                               });
-
-                       // TODO try to catch this earlier when scrollTop 
indicates the last page anyway
-                       if (!result.length) {
-                               result = this.element.children(":first");
-                       }
-                       this.activate(event, result);
-               } else {
-                       this.activate(event, this.element.children(!this.active 
|| this.first() ? ":last" : ":first"));
-               }
-       },
-
-       hasScroll: function() {
-               return this.element.height() < 
this.element.attr("scrollHeight");
-       },
-
-       select: function( event ) {
-               this._trigger("selected", event, { item: this.active });
-       }
-});
-
-}(jQuery));
-
-/*
- * jQuery UI Position 1.8.2
- *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI/Position
- */
-(function( $ ) {
-
-$.ui = $.ui || {};
-
-var horizontalPositions = /left|center|right/,
-       horizontalDefault = "center",
-       verticalPositions = /top|center|bottom/,
-       verticalDefault = "center",
-       _position = $.fn.position,
-       _offset = $.fn.offset;
-
-$.fn.position = function( options ) {
-       if ( !options || !options.of ) {
-               return _position.apply( this, arguments );
-       }
-
-       // make a copy, we don't want to modify arguments
-       options = $.extend( {}, options );
-
-       var target = $( options.of ),
-               collision = ( options.collision || "flip" ).split( " " ),
-               offset = options.offset ? options.offset.split( " " ) : [ 0, 0 
],
-               targetWidth,
-               targetHeight,
-               basePosition;
-
-       if ( options.of.nodeType === 9 ) {
-               targetWidth = target.width();
-               targetHeight = target.height();
-               basePosition = { top: 0, left: 0 };
-       } else if ( options.of.scrollTo && options.of.document ) {
-               targetWidth = target.width();
-               targetHeight = target.height();
-               basePosition = { top: target.scrollTop(), left: 
target.scrollLeft() };
-       } else if ( options.of.preventDefault ) {
-               // force left top to allow flipping
-               options.at = "left top";
-               targetWidth = targetHeight = 0;
-               basePosition = { top: options.of.pageY, left: options.of.pageX 
};
-       } else {
-               targetWidth = target.outerWidth();
-               targetHeight = target.outerHeight();
-               basePosition = target.offset();
-       }
-
-       // force my and at to have valid horizontal and veritcal positions
-       // if a value is missing or invalid, it will be converted to center 
-       $.each( [ "my", "at" ], function() {
-               var pos = ( options[this] || "" ).split( " " );
-               if ( pos.length === 1) {
-                       pos = horizontalPositions.test( pos[0] ) ?
-                               pos.concat( [verticalDefault] ) :
-                               verticalPositions.test( pos[0] ) ?
-                                       [ horizontalDefault ].concat( pos ) :
-                                       [ horizontalDefault, verticalDefault ];
-               }
-               pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : 
horizontalDefault;
-               pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : 
verticalDefault;
-               options[ this ] = pos;
-       });
-
-       // normalize collision option
-       if ( collision.length === 1 ) {
-               collision[ 1 ] = collision[ 0 ];
-       }
-
-       // normalize offset option
-       offset[ 0 ] = parseInt( offset[0], 10 ) || 0;
-       if ( offset.length === 1 ) {
-               offset[ 1 ] = offset[ 0 ];
-       }
-       offset[ 1 ] = parseInt( offset[1], 10 ) || 0;
-
-       if ( options.at[0] === "right" ) {
-               basePosition.left += targetWidth;
-       } else if (options.at[0] === horizontalDefault ) {
-               basePosition.left += targetWidth / 2;
-       }
-
-       if ( options.at[1] === "bottom" ) {
-               basePosition.top += targetHeight;
-       } else if ( options.at[1] === verticalDefault ) {
-               basePosition.top += targetHeight / 2;
-       }
-
-       basePosition.left += offset[ 0 ];
-       basePosition.top += offset[ 1 ];
-
-       return this.each(function() {
-               var elem = $( this ),
-                       elemWidth = elem.outerWidth(),
-                       elemHeight = elem.outerHeight(),
-                       position = $.extend( {}, basePosition );
-
-               if ( options.my[0] === "right" ) {
-                       position.left -= elemWidth;
-               } else if ( options.my[0] === horizontalDefault ) {
-                       position.left -= elemWidth / 2;
-               }
-
-               if ( options.my[1] === "bottom" ) {
-                       position.top -= elemHeight;
-               } else if ( options.my[1] === verticalDefault ) {
-                       position.top -= elemHeight / 2;
-               }
-
-               // prevent fractions (see #5280)
-               position.left = parseInt( position.left );
-               position.top = parseInt( position.top );
-
-               $.each( [ "left", "top" ], function( i, dir ) {
-                       if ( $.ui.position[ collision[i] ] ) {
-                               $.ui.position[ collision[i] ][ dir ]( position, 
{
-                                       targetWidth: targetWidth,
-                                       targetHeight: targetHeight,
-                                       elemWidth: elemWidth,
-                                       elemHeight: elemHeight,
-                                       offset: offset,
-                                       my: options.my,
-                                       at: options.at
-                               });
-                       }
-               });
-
-               if ( $.fn.bgiframe ) {
-                       elem.bgiframe();
-               }
-               elem.offset( $.extend( position, { using: options.using } ) );
-       });
-};
-
-$.ui.position = {
-       fit: {
-               left: function( position, data ) {
-                       var win = $( window ),
-                               over = position.left + data.elemWidth - 
win.width() - win.scrollLeft();
-                       position.left = over > 0 ? position.left - over : 
Math.max( 0, position.left );
-               },
-               top: function( position, data ) {
-                       var win = $( window ),
-                               over = position.top + data.elemHeight - 
win.height() - win.scrollTop();
-                       position.top = over > 0 ? position.top - over : 
Math.max( 0, position.top );
-               }
-       },
-
-       flip: {
-               left: function( position, data ) {
-                       if ( data.at[0] === "center" ) {
-                               return;
-                       }
-                       var win = $( window ),
-                               over = position.left + data.elemWidth - 
win.width() - win.scrollLeft(),
-                               myOffset = data.my[ 0 ] === "left" ?
-                                       -data.elemWidth :
-                                       data.my[ 0 ] === "right" ?
-                                               data.elemWidth :
-                                               0,
-                               offset = -2 * data.offset[ 0 ];
-                       position.left += position.left < 0 ?
-                               myOffset + data.targetWidth + offset :
-                               over > 0 ?
-                                       myOffset - data.targetWidth + offset :
-                                       0;
-               },
-               top: function( position, data ) {
-                       if ( data.at[1] === "center" ) {
-                               return;
-                       }
-                       var win = $( window ),
-                               over = position.top + data.elemHeight - 
win.height() - win.scrollTop(),
-                               myOffset = data.my[ 1 ] === "top" ?
-                                       -data.elemHeight :
-                                       data.my[ 1 ] === "bottom" ?
-                                               data.elemHeight :
-                                               0,
-                               atOffset = data.at[ 1 ] === "top" ?
-                                       data.targetHeight :
-                                       -data.targetHeight,
-                               offset = -2 * data.offset[ 1 ];
-                       position.top += position.top < 0 ?
-                               myOffset + data.targetHeight + offset :
-                               over > 0 ?
-                                       myOffset + atOffset + offset :
-                                       0;
-               }
-       }
-};
-
-// offset setter from jQuery 1.4
-if ( !$.offset.setOffset ) {
-       $.offset.setOffset = function( elem, options ) {
-               // set position first, in-case top/left are set even on static 
elem
-               if ( /static/.test( $.curCSS( elem, "position" ) ) ) {
-                       elem.style.position = "relative";
-               }
-               var curElem   = $( elem ),
-                       curOffset = curElem.offset(),
-                       curTop    = parseInt( $.curCSS( elem, "top",  true ), 
10 ) || 0,
-                       curLeft   = parseInt( $.curCSS( elem, "left", true ), 
10)  || 0,
-                       props     = {
-                               top:  (options.top  - curOffset.top)  + curTop,
-                               left: (options.left - curOffset.left) + curLeft
-                       };
-               
-               if ( 'using' in options ) {
-                       options.using.call( elem, props );
-               } else {
-                       curElem.css( props );
-               }
-       };
-
-       $.fn.offset = function( options ) {
-               var elem = this[ 0 ];
-               if ( !elem || !elem.ownerDocument ) { return null; }
-               if ( options ) { 
-                       return this.each(function() {
-                               $.offset.setOffset( this, options );
-                       });
-               }
-               return _offset.call( this );
-       };
-}
-
-}( jQuery ));
-
-
-/*
- * jQuery UI Autocomplete 1.8.2
- *
- * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * http://docs.jquery.com/UI/Autocomplete
- *
- * Depends:
- *     jquery.ui.core.js
- *     jquery.ui.widget.js
- *     jquery.ui.position.js
- */
-(function( $ ) {
-
-$.widget( "ui.autocomplete", {
-       options: {
-               minLength: 1,
-               delay: 300
-       },
-       _create: function() {
-               var self = this,
-                       doc = this.element[ 0 ].ownerDocument;
-               this.element
-                       .addClass( "ui-autocomplete-input" )
-                       .attr( "autocomplete", "off" )
-                       // TODO verify these actually work as intended
-                       .attr({
-                               role: "textbox",
-                               "aria-autocomplete": "list",
-                               "aria-haspopup": "true"
-                       })
-                       .bind( "keydown.autocomplete", function( event ) {
-                               var keyCode = $.ui.keyCode;
-                               switch( event.keyCode ) {
-                               case keyCode.PAGE_UP:
-                                       self._move( "previousPage", event );
-                                       break;
-                               case keyCode.PAGE_DOWN:
-                                       self._move( "nextPage", event );
-                                       break;
-                               case keyCode.UP:
-                                       self._move( "previous", event );
-                                       // prevent moving cursor to beginning 
of text field in some browsers
-                                       event.preventDefault();
-                                       break;
-                               case keyCode.DOWN:
-                                       self._move( "next", event );
-                                       // prevent moving cursor to end of text 
field in some browsers
-                                       event.preventDefault();
-                                       break;
-                               case keyCode.ENTER:
-                               case keyCode.NUMPAD_ENTER:
-                                       // when menu is open or has focus
-                                       if ( self.menu.active ) {
-                                               event.preventDefault();
-                                       }
-                                       //passthrough - ENTER and TAB both 
select the current element
-                               case keyCode.TAB:
-                                       if ( !self.menu.active ) {
-                                               return;
-                                       }
-                                       self.menu.select( event );
-                                       break;
-                               case keyCode.ESCAPE:
-                                       self.element.val( self.term );
-                                       self.close( event );
-                                       break;
-                               case keyCode.LEFT:
-                               case keyCode.RIGHT:
-                               case keyCode.SHIFT:
-                               case keyCode.CONTROL:
-                               case keyCode.ALT:
-                               case keyCode.COMMAND:
-                               case keyCode.COMMAND_RIGHT:
-                               case keyCode.INSERT:
-                               case keyCode.CAPS_LOCK:
-                               case keyCode.END:
-                               case keyCode.HOME:
-                                       // ignore metakeys (shift, ctrl, alt)
-                                       break;
-                               default:
-                                       // keypress is triggered before the 
input value is changed
-                                       clearTimeout( self.searching );
-                                       self.searching = setTimeout(function() {
-                                               self.search( null, event );
-                                       }, self.options.delay );
-                                       break;
-                               }
-                       })
-                       .bind( "focus.autocomplete", function() {
-                               self.selectedItem = null;
-                               self.previous = self.element.val();
-                       })
-                       .bind( "blur.autocomplete", function( event ) {
-                               clearTimeout( self.searching );
-                               // clicks on the menu (or a button to trigger a 
search) will cause a blur event
-                               self.closing = setTimeout(function() {
-                                       self.close( event );
-                                       self._change( event );
-                               }, 150 );
-                       });
-               this._initSource();
-               this.response = function() {
-                       return self._response.apply( self, arguments );
-               };
-               this.menu = $( "<ul></ul>" )
-                       .addClass( "ui-autocomplete" )
-                       .appendTo( "body", doc )
-                       // prevent the close-on-blur in case of a "slow" click 
on the menu (long mousedown)
-                       .mousedown(function() {
-                               // use another timeout to make sure the 
blur-event-handler on the input was already triggered
-                               setTimeout(function() {
-                                       clearTimeout( self.closing );
-                               }, 13);
-                       })
-                       .menu({
-                               focus: function( event, ui ) {
-                                       var item = ui.item.data( 
"item.autocomplete" );
-                                       if ( false !== self._trigger( "focus", 
null, { item: item } ) ) {
-                                               // use value to match what will 
end up in the input, if it was a key event
-                                               if ( 
/^key/.test(event.originalEvent.type) ) {
-                                                       self.element.val( 
item.value );
-                                               }
-                                       }
-                               },
-                               selected: function( event, ui ) {
-                                       var item = ui.item.data( 
"item.autocomplete" );
-                                       if ( false !== self._trigger( "select", 
event, { item: item } ) ) {
-                                               self.element.val( item.value );
-                                       }
-                                       self.close( event );
-                                       // only trigger when focus was lost 
(click on menu)
-                                       var previous = self.previous;
-                                       if ( self.element[0] !== 
doc.activeElement ) {
-                                               self.element.focus();
-                                               self.previous = previous;
-                                       }
-                                       self.selectedItem = item;
-                               },
-                               blur: function( event, ui ) {
-                                       if ( self.menu.element.is(":visible") ) 
{
-                                               self.element.val( self.term );
-                                       }
-                               }
-                       })
-                       .zIndex( this.element.zIndex() + 1 )
-                       // workaround for jQuery bug #5781 
http://dev.jquery.com/ticket/5781
-                       .css({ top: 0, left: 0 })
-                       .hide()
-                       .data( "menu" );
-               if ( $.fn.bgiframe ) {
-                        this.menu.element.bgiframe();
-               }
-       },
-
-       destroy: function() {
-               this.element
-                       .removeClass( "ui-autocomplete-input" )
-                       .removeAttr( "autocomplete" )
-                       .removeAttr( "role" )
-                       .removeAttr( "aria-autocomplete" )
-                       .removeAttr( "aria-haspopup" );
-               this.menu.element.remove();
-               $.Widget.prototype.destroy.call( this );
-       },
-
-       _setOption: function( key ) {
-               $.Widget.prototype._setOption.apply( this, arguments );
-               if ( key === "source" ) {
-                       this._initSource();
-               }
-       },
-
-       _initSource: function() {
-               var array,
-                       url;
-               if ( $.isArray(this.options.source) ) {
-                       array = this.options.source;
-                       this.source = function( request, response ) {
-                               response( $.ui.autocomplete.filter(array, 
request.term) );
-                       };
-               } else if ( typeof this.options.source === "string" ) {
-                       url = this.options.source;
-                       this.source = function( request, response ) {
-                               $.getJSON( url, request, response );
-                       };
-               } else {
-                       this.source = this.options.source;
-               }
-       },
-
-       search: function( value, event ) {
-               value = value != null ? value : this.element.val();
-               if ( value.length < this.options.minLength ) {
-                       return this.close( event );
-               }
-
-               clearTimeout( this.closing );
-               if ( this._trigger("search") === false ) {
-                       return;
-               }
-
-               return this._search( value );
-       },
-
-       _search: function( value ) {
-               this.term = this.element
-                       .addClass( "ui-autocomplete-loading" )
-                       // always save the actual value, not the one passed as 
an argument
-                       .val();
-
-               this.source( { term: value }, this.response );
-       },
-
-       _response: function( content ) {
-               if ( content.length ) {
-                       content = this._normalize( content );
-                       this._suggest( content );
-                       this._trigger( "open" );
-               } else {
-                       this.close();
-               }
-               this.element.removeClass( "ui-autocomplete-loading" );
-       },
-
-       close: function( event ) {
-               clearTimeout( this.closing );
-               if ( this.menu.element.is(":visible") ) {
-                       this._trigger( "close", event );
-                       this.menu.element.hide();
-                       this.menu.deactivate();
-               }
-       },
-       
-       _change: function( event ) {
-               if ( this.previous !== this.element.val() ) {
-                       this._trigger( "change", event, { item: 
this.selectedItem } );
-               }
-       },
-
-       _normalize: function( items ) {
-               // assume all items have the right format when the first item 
is complete
-               if ( items.length && items[0].label && items[0].value ) {
-                       return items;
-               }
-               return $.map( items, function(item) {
-                       if ( typeof item === "string" ) {
-                               return {
-                                       label: item,
-                                       value: item
-                               };
-                       }
-                       return $.extend({
-                               label: item.label || item.value,
-                               value: item.value || item.label
-                       }, item );
-               });
-       },
-
-       _suggest: function( items ) {
-               var ul = this.menu.element
-                               .empty()
-                               .zIndex( this.element.zIndex() + 1 ),
-                       menuWidth,
-                       textWidth;
-               this._renderMenu( ul, items );
-               // TODO refresh should check if the active item is still in the 
dom, removing the need for a manual deactivate
-               this.menu.deactivate();
-               this.menu.refresh();
-               this.menu.element.show().position({
-                       my: "left top",
-                       at: "left bottom",
-                       of: this.element,
-                       collision: "none"
-               });
-
-               menuWidth = ul.width( "" ).width();
-               textWidth = this.element.width();
-               ul.width( Math.max( menuWidth, textWidth ) );
-       },
-       
-       _renderMenu: function( ul, items ) {
-               var self = this;
-               $.each( items, function( index, item ) {
-                       self._renderItem( ul, item );
-               });
-       },
-
-       _renderItem: function( ul, item) {
-               return $( "<li></li>" )
-                       .data( "item.autocomplete", item )
-                       .append( "<a>" + item.label + "</a>" )
-                       .appendTo( ul );
-       },
-
-       _move: function( direction, event ) {
-               if ( !this.menu.element.is(":visible") ) {
-                       this.search( null, event );
-                       return;
-               }
-               if ( this.menu.first() && /^previous/.test(direction) ||
-                               this.menu.last() && /^next/.test(direction) ) {
-                       this.element.val( this.term );
-                       this.menu.deactivate();
-                       return;
-               }
-               this.menu[ direction ]( event );
-       },
-
-       widget: function() {
-               return this.menu.element;
-       }
-});
-
-$.extend( $.ui.autocomplete, {
-       escapeRegex: function( value ) {
-               return value.replace( /([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, 
"\\$1" );
-       },
-       filter: function(array, term) {
-               var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), 
"i" );
-               return $.grep( array, function(value) {
-                       return matcher.test( value.label || value.value || 
value );
-               });
-       }
-});
-
-}( jQuery ));

-- 
To view, visit https://gerrit.wikimedia.org/r/208107
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ied8a36b8546a6b84fae645567fdbb6fec4dd15bb
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/LinkSuggest
Gerrit-Branch: master
Gerrit-Owner: Jack Phoenix <j...@countervandalism.net>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to