[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/extensions/WikiEditor/modules/ -> jquery.wikiEditor.dialogs.config.js (source)

   1  /**
   2   * Configuration of Dialog module for wikiEditor
   3   */
   4  /*jshint curly:false, noarg:false, quotmark:false, onevar:false */
   5  /*global alert */
   6  ( function ( $, mw ) {
   7  
   8  var hasOwn = Object.prototype.hasOwnProperty;
   9  
  10  $.wikiEditor.modules.dialogs.config = {
  11  
  12      replaceIcons: function ( $textarea ) {
  13          $textarea
  14              .wikiEditor( 'removeFromToolbar', { section: 'main', group: 'insert', tool: 'xlink' } )
  15              .wikiEditor( 'removeFromToolbar', { section: 'main', group: 'insert', tool: 'ilink' } )
  16              .wikiEditor( 'removeFromToolbar', { section: 'main', group: 'insert', tool: 'file' } )
  17              .wikiEditor( 'removeFromToolbar', { section: 'main', group: 'insert', tool: 'reference' } )
  18              .wikiEditor( 'removeFromToolbar', { section: 'advanced', group: 'insert', tool: 'table' } )
  19              .wikiEditor( 'addToToolbar', {
  20                  section: 'main',
  21                  group: 'insert',
  22                  tools: {
  23                      'link': {
  24                          labelMsg: 'wikieditor-toolbar-tool-link',
  25                          type: 'button',
  26                          icon: 'insert-link.png',
  27                          offset: [2, -1654],
  28                          action: {
  29                              type: 'dialog',
  30                              module: 'insert-link'
  31                          }
  32                      },
  33                      'file': {
  34                          labelMsg: 'wikieditor-toolbar-tool-file',
  35                          type: 'button',
  36                          icon: 'insert-file.png',
  37                          offset: [2, -1438],
  38                          action: {
  39                              type: 'dialog',
  40                              module: 'insert-file'
  41                          }
  42                      },
  43                      'reference': {
  44                          labelMsg: 'wikieditor-toolbar-tool-reference',
  45                          filters: [ 'body.ns-subject' ],
  46                          type: 'button',
  47                          icon: 'insert-reference.png',
  48                          offset: [2, -1798],
  49                          action: {
  50                              type: 'dialog',
  51                              module: 'insert-reference'
  52                          }
  53                      }
  54                  }
  55              } )
  56              .wikiEditor( 'addToToolbar', {
  57                  section: 'advanced',
  58                  group: 'insert',
  59                  tools: {
  60                      'table': {
  61                          labelMsg: 'wikieditor-toolbar-tool-table',
  62                          type: 'button',
  63                          icon: 'insert-table.png',
  64                          offset: [2, -1942],
  65                          action: {
  66                              type: 'dialog',
  67                              module: 'insert-table'
  68                          }
  69                      }
  70                  }
  71              } )
  72              .wikiEditor( 'addToToolbar', {
  73                  section: 'advanced',
  74                  groups: {
  75                      'search': {
  76                          tools: {
  77                              'replace': {
  78                                  labelMsg: 'wikieditor-toolbar-tool-replace',
  79                                  type: 'button',
  80                                  icon: 'search-replace.png',
  81                                  offset: [-70, -214],
  82                                  action: {
  83                                      type: 'dialog',
  84                                      module: 'search-and-replace'
  85                                  }
  86                              }
  87                          }
  88                      }
  89                  }
  90              } );
  91      },
  92  
  93      getDefaultConfig: function () {
  94          return { 'dialogs': {
  95              'insert-link': {
  96                  titleMsg: 'wikieditor-toolbar-tool-link-title',
  97                  id: 'wikieditor-toolbar-link-dialog',
  98                  html: '\
  99                      <fieldset>\
 100                          <div class="wikieditor-toolbar-field-wrapper">\
 101                              <label for="wikieditor-toolbar-link-int-target" rel="wikieditor-toolbar-tool-link-int-target" id="wikieditor-toolbar-tool-link-int-target-label"></label>\
 102                              <div id="wikieditor-toolbar-link-int-target-status"></div>\
 103                              <input type="text" id="wikieditor-toolbar-link-int-target"/>\
 104                          </div>\
 105                          <div class="wikieditor-toolbar-field-wrapper">\
 106                              <label for="wikieditor-toolbar-link-int-text" rel="wikieditor-toolbar-tool-link-int-text"></label>\
 107                              <input type="text" id="wikieditor-toolbar-link-int-text"/>\
 108                          </div>\
 109                          <div class="wikieditor-toolbar-field-wrapper">\
 110                              <div class="wikieditor-toolbar-floated-field-wrapper">\
 111                                  <input type="radio" id="wikieditor-toolbar-link-type-int" name="wikieditor-toolbar-link-type" selected/>\
 112                                  <label for="wikieditor-toolbar-link-type-int" rel="wikieditor-toolbar-tool-link-int"></label>\
 113                              </div>\
 114                              <div class="wikieditor-toolbar-floated-field-wrapper">\
 115                                  <input type="radio" id="wikieditor-toolbar-link-type-ext" name="wikieditor-toolbar-link-type"/>\
 116                                  <label for="wikieditor-toolbar-link-type-ext" rel="wikieditor-toolbar-tool-link-ext"></label>\
 117                              </div>\
 118                          </div>\
 119                      </fieldset>',
 120  
 121                  init: function () {
 122  					function isExternalLink( s ) {
 123                          // The following things are considered to be external links:
 124                          // * Starts a URL protocol
 125                          // * Starts with www.
 126                          // All of these are potentially valid titles, and the latter two categories match about 6300
 127                          // titles in enwiki's ns0. Out of 6.9M titles, that's 0.09%
 128                          if ( typeof arguments.callee.regex === 'undefined' ) {
 129                              // Cache the regex
 130                              arguments.callee.regex =
 131                                  new RegExp( "^(" + mw.config.get( 'wgUrlProtocols' ) + "|www\\.)", 'i' );
 132                          }
 133                          return s.match( arguments.callee.regex );
 134                      }
 135  
 136                      // Updates the status indicator above the target link
 137  					function updateWidget( status ) {
 138                          $( '#wikieditor-toolbar-link-int-target-status' ).children().hide();
 139                          $( '#wikieditor-toolbar-link-int-target' ).parent()
 140                              .removeClass(
 141                                  'status-invalid status-external status-notexists status-exists status-loading'
 142                              );
 143                          if ( status ) {
 144                              $( '#wikieditor-toolbar-link-int-target-status-' + status ).show();
 145                              $( '#wikieditor-toolbar-link-int-target' ).parent().addClass( 'status-' + status );
 146                          }
 147                          if ( status === 'invalid' ) {
 148                              $( '.ui-dialog:visible .ui-dialog-buttonpane button:first' )
 149                                  .attr( 'disabled', true )
 150                                  .addClass( 'disabled' );
 151                          } else {
 152                              $( '.ui-dialog:visible .ui-dialog-buttonpane button:first' )
 153                                  .removeAttr( 'disabled' )
 154                                  .removeClass( 'disabled' );
 155                          }
 156                      }
 157  
 158                      // Updates the UI to show if the page title being inputed by the user exists or not
 159                      // accepts parameter internal for bypassing external link detection
 160  					function updateExistence( internal ) {
 161                          // ensure the internal parameter is a boolean
 162                          if ( internal !== true ) {
 163                              internal = false;
 164                          }
 165                          // Abort previous request
 166                          var request = $( '#wikieditor-toolbar-link-int-target-status' ).data( 'request' );
 167                          if ( request ) {
 168                              request.abort();
 169                          }
 170                          var target = $( '#wikieditor-toolbar-link-int-target' ).val();
 171                          var cache = $( '#wikieditor-toolbar-link-int-target-status' ).data( 'existencecache' );
 172                          if ( hasOwn.call( cache, target ) ) {
 173                              updateWidget( cache[target] );
 174                              return;
 175                          }
 176                          if ( target.replace( /^\s+$/,'' ) === '' ) {
 177                              // Hide the widget when the textbox is empty
 178                              updateWidget( false );
 179                              return;
 180                          }
 181                          // If the forced internal paremter was not true, check if the target is an external link
 182                          if ( !internal && isExternalLink( target ) ) {
 183                              updateWidget( 'external' );
 184                              return;
 185                          }
 186                          if ( target.indexOf( '|' ) !== -1 ) {
 187                              // Title contains | , which means it's invalid
 188                              // but confuses the API. Show invalid and bypass API
 189                              updateWidget( 'invalid' );
 190                              return;
 191                          }
 192                          // Show loading spinner while waiting for the API to respond
 193                          updateWidget( 'loading' );
 194                          // Call the API to check page status, saving the request object so it can be aborted if
 195                          // necessary.
 196                          // This used to request a page that would show whether or not the target exists, but we can
 197                          // also check whether it has the disambiguation property and still get existence information.
 198                          // If the Disambiguator extension is not installed then such a property won't be set.
 199                          $( '#wikieditor-toolbar-link-int-target-status' ).data(
 200                              'request',
 201                              ( new mw.Api() ).get( {
 202                                  action: 'query',
 203                                  prop: 'pageprops',
 204                                  titles: target,
 205                                  ppprop: 'disambiguation',
 206                                  indexpageids: true
 207                              } ).done( function ( data ) {
 208                                  var status;
 209                                  if ( !data.query || !data.query.pages ) {
 210                                      // This happens in some weird cases like interwiki links
 211                                      status = false;
 212                                  } else {
 213                                      var page = data.query.pages[data.query.pageids[0]];
 214                                      status = 'exists';
 215                                      if ( page.missing !== undefined ) {
 216                                          status = 'notexists';
 217                                      } else if ( page.invalid !== undefined ) {
 218                                          status = 'invalid';
 219                                      } else if ( page.pageprops !== undefined ) {
 220                                          status = 'disambig';
 221                                      }
 222                                  }
 223                                  // Cache the status of the link target if the force internal
 224                                  // parameter was not passed
 225                                  if ( !internal ) {
 226                                      cache[target] = status;
 227                                  }
 228                                  updateWidget( status );
 229                              } )
 230                          );
 231                      }
 232                      $( '#wikieditor-toolbar-link-type-int, #wikieditor-toolbar-link-type-ext' ).click( function () {
 233                          if ( $( '#wikieditor-toolbar-link-type-ext' ).prop( 'checked' ) ) {
 234                              // Abort previous request
 235                              var request = $( '#wikieditor-toolbar-link-int-target-status' ).data( 'request' );
 236                              if ( request ) {
 237                                  request.abort();
 238                              }
 239                              updateWidget( 'external' );
 240                          }
 241                          if ( $( '#wikieditor-toolbar-link-type-int' ).prop( 'checked' ) ) {
 242                              updateExistence( true );
 243                          }
 244                      } );
 245                      // Set labels of tabs based on rel values
 246                      $( this ).find( '[rel]' ).each( function () {
 247                          $( this ).text( mw.msg( $( this ).attr( 'rel' ) ) );
 248                      } );
 249                      // Set tabindexes on form fields
 250                      $.wikiEditor.modules.dialogs.fn.setTabindexes( $( this ).find( 'input' ).not( '[tabindex]' ) );
 251                      // Setup the tooltips in the textboxes
 252                      $( '#wikieditor-toolbar-link-int-target' )
 253                          .data( 'tooltip', mw.msg( 'wikieditor-toolbar-tool-link-int-target-tooltip' ) );
 254                      $( '#wikieditor-toolbar-link-int-text' )
 255                          .data( 'tooltip', mw.msg( 'wikieditor-toolbar-tool-link-int-text-tooltip' ) );
 256                      $( '#wikieditor-toolbar-link-int-target, #wikieditor-toolbar-link-int-text' )
 257                          .each( function () {
 258                              if ( $( this ).val() === '' ) {
 259                                  $( this )
 260                                      .addClass( 'wikieditor-toolbar-dialog-hint' )
 261                                      .val( $( this ).data( 'tooltip' ) )
 262                                      .data( 'tooltip-mode', true );
 263                              }
 264                          } )
 265                          .focus( function () {
 266                              if ( $( this ).val() === $( this ).data( 'tooltip' ) ) {
 267                                  $( this )
 268                                      .val( '' )
 269                                      .removeClass( 'wikieditor-toolbar-dialog-hint' )
 270                                      .data( 'tooltip-mode', false );
 271                              }
 272                          } )
 273                          .bind( 'change', function () {
 274                              if ( $( this ).val() !== $( this ).data( 'tooltip' ) ) {
 275                                  $( this )
 276                                      .removeClass( 'wikieditor-toolbar-dialog-hint' )
 277                                      .data( 'tooltip-mode', false );
 278                              }
 279                          } )
 280                          .bind( 'blur', function () {
 281                              if ( $( this ).val() === '' ) {
 282                                  $( this )
 283                                      .addClass( 'wikieditor-toolbar-dialog-hint' )
 284                                      .val( $( this ).data( 'tooltip' ) )
 285                                      .data( 'tooltip-mode', true );
 286                              }
 287                          } );
 288  
 289                      // Automatically copy the value of the internal link page title field to the link text field unless the
 290                      // user has changed the link text field - this is a convenience thing since most link texts are going to
 291                      // be the the same as the page title - Also change the internal/external radio button accordingly
 292                      $( '#wikieditor-toolbar-link-int-target' ).bind( 'change keydown paste cut', function () {
 293                          // $( this ).val() is the old value, before the keypress - Defer this until $( this ).val() has
 294                          // been updated
 295                          setTimeout( function () {
 296                              if ( isExternalLink( $( '#wikieditor-toolbar-link-int-target' ).val() ) ) {
 297                                  $( '#wikieditor-toolbar-link-type-ext' ).prop( 'checked', true );
 298                                  updateWidget( 'external' );
 299                              } else {
 300                                  $( '#wikieditor-toolbar-link-type-int' ).prop( 'checked', true );
 301                                  updateExistence();
 302                              }
 303                              /*jshint eqeqeq:false */
 304                              if ( $( '#wikieditor-toolbar-link-int-text' ).data( 'untouched' ) ) {
 305                                  if ( $( '#wikieditor-toolbar-link-int-target' ).val() ==
 306                                      $( '#wikieditor-toolbar-link-int-target' ).data( 'tooltip' )
 307                                  ) {
 308                                      $( '#wikieditor-toolbar-link-int-text' )
 309                                          .addClass( 'wikieditor-toolbar-dialog-hint' )
 310                                          .val( $( '#wikieditor-toolbar-link-int-text' ).data( 'tooltip' ) )
 311                                          .change();
 312                                  } else {
 313                                      $( '#wikieditor-toolbar-link-int-text' )
 314                                          .val( $( '#wikieditor-toolbar-link-int-target' ).val() )
 315                                          .change();
 316                                  }
 317                              }
 318                          }, 0 );
 319                      } );
 320                      $( '#wikieditor-toolbar-link-int-text' ).bind( 'change keydown paste cut', function () {
 321                          var oldVal = $( this ).val();
 322                          var that = this;
 323                          setTimeout( function () {
 324                              if ( $( that ).val() !== oldVal ) {
 325                                  $( that ).data( 'untouched', false );
 326                              }
 327                          }, 0 );
 328                      } );
 329                      // Add images to the page existence widget, which will be shown mutually exclusively to communicate if
 330                      // the page exists, does not exist or the title is invalid (like if it contains a | character)
 331                      var existsMsg = mw.msg( 'wikieditor-toolbar-tool-link-int-target-status-exists' );
 332                      var notexistsMsg = mw.msg( 'wikieditor-toolbar-tool-link-int-target-status-notexists' );
 333                      var invalidMsg = mw.msg( 'wikieditor-toolbar-tool-link-int-target-status-invalid' );
 334                      var externalMsg = mw.msg( 'wikieditor-toolbar-tool-link-int-target-status-external' );
 335                      var loadingMsg = mw.msg( 'wikieditor-toolbar-tool-link-int-target-status-loading' );
 336                      var disambigMsg = mw.msg( 'wikieditor-toolbar-tool-link-int-target-status-disambig' );
 337                      $( '#wikieditor-toolbar-link-int-target-status' )
 338                          .append( $( '<div>' )
 339                              .attr( 'id', 'wikieditor-toolbar-link-int-target-status-exists' )
 340                              .append( existsMsg )
 341                          )
 342                          .append( $( '<div>' )
 343                              .attr( 'id', 'wikieditor-toolbar-link-int-target-status-notexists' )
 344                              .append( notexistsMsg )
 345                          )
 346                          .append( $( '<div>' )
 347                              .attr( 'id', 'wikieditor-toolbar-link-int-target-status-invalid' )
 348                              .append( invalidMsg )
 349                          )
 350                          .append( $( '<div>' )
 351                              .attr( 'id', 'wikieditor-toolbar-link-int-target-status-external' )
 352                              .append( externalMsg )
 353                          )
 354                          .append( $( '<div>' )
 355                              .attr( 'id', 'wikieditor-toolbar-link-int-target-status-loading' )
 356                              .append( $( '<img>' ).attr( {
 357                                  'src': $.wikiEditor.imgPath + 'dialogs/' + 'loading-small.gif',
 358                                  'alt': loadingMsg,
 359                                  'title': loadingMsg
 360                              } ) )
 361                          )
 362                          .append( $( '<div>' )
 363                              .attr( 'id', 'wikieditor-toolbar-link-int-target-status-disambig' )
 364                              .append( disambigMsg )
 365                          )
 366                          .data( 'existencecache', {} )
 367                          .children().hide();
 368  
 369                      $( '#wikieditor-toolbar-link-int-target' )
 370                          .bind( 'keyup paste cut', function () {
 371                              // Cancel the running timer if applicable
 372                              if ( typeof $( this ).data( 'timerID' ) !== 'undefined' ) {
 373                                  clearTimeout( $( this ).data( 'timerID' ) );
 374                              }
 375                              // Delay fetch for a while
 376                              // FIXME: Make 120 configurable elsewhere
 377                              var timerID = setTimeout( updateExistence, 120 );
 378                              $( this ).data( 'timerID', timerID );
 379                          } )
 380                          .change( function () {
 381                              // Cancel the running timer if applicable
 382                              if ( typeof $( this ).data( 'timerID' ) !== 'undefined' ) {
 383                                  clearTimeout( $( this ).data( 'timerID' ) );
 384                              }
 385                              // Fetch right now
 386                              updateExistence();
 387                          } );
 388  
 389                      // Title suggestions
 390                      $( '#wikieditor-toolbar-link-int-target' ).data( 'suggcache', {} ).suggestions( {
 391                          fetch: function () {
 392                              var that = this;
 393                              var title = $( this ).val();
 394  
 395                              if ( isExternalLink( title ) || title.indexOf( '|' ) !== -1 || title === '' ) {
 396                                  $( this ).suggestions( 'suggestions', [] );
 397                                  return;
 398                              }
 399  
 400                              var cache = $( this ).data( 'suggcache' );
 401                              if ( hasOwn.call( cache, title ) ) {
 402                                  $( this ).suggestions( 'suggestions', cache[title] );
 403                                  return;
 404                              }
 405  
 406                              var request = $.ajax( {
 407                                  url: mw.util.wikiScript( 'api' ),
 408                                  data: {
 409                                      action: 'opensearch',
 410                                      search: title,
 411                                      namespace: 0,
 412                                      suggest: '',
 413                                      format: 'json'
 414                                  },
 415                                  dataType: 'json',
 416                                  success: function ( data ) {
 417                                      cache[title] = data[1];
 418                                      $( that ).suggestions( 'suggestions', data[1] );
 419                                  }
 420                              } );
 421                              $( this ).data( 'request', request );
 422                          },
 423                          cancel: function () {
 424                              var request = $( this ).data( 'request' );
 425                              if ( request )
 426                                  request.abort();
 427                          }
 428                      } );
 429                  },
 430                  dialog: {
 431                      width: 500,
 432                      dialogClass: 'wikiEditor-toolbar-dialog',
 433                      buttons: {
 434                          'wikieditor-toolbar-tool-link-insert': function () {
 435  							function escapeInternalText( s ) {
 436                                  return s.replace( /(\]{2,})/g, '<nowiki>$1</nowiki>' );
 437                              }
 438  							function escapeExternalTarget( s ) {
 439                                  return s.replace( / /g, '%20' )
 440                                      .replace( /\[/g, '%5B' )
 441                                      .replace( /\]/g, '%5D' );
 442                              }
 443  							function escapeExternalText( s ) {
 444                                  return s.replace( /(\]+)/g, '<nowiki>$1</nowiki>' );
 445                              }
 446                              var insertText = '';
 447                              var whitespace = $( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace' );
 448                              var target = $( '#wikieditor-toolbar-link-int-target' ).val();
 449                              var text = $( '#wikieditor-toolbar-link-int-text' ).val();
 450                              // check if the tooltips were passed as target or text
 451                              if ( $( '#wikieditor-toolbar-link-int-target' ).data( 'tooltip-mode' ) )
 452                                  target = "";
 453                              if ( $( '#wikieditor-toolbar-link-int-text' ).data( 'tooltip-mode' ) )
 454                                  text = "";
 455                              if ( target === '' ) {
 456                                  alert( mw.msg( 'wikieditor-toolbar-tool-link-empty' ) );
 457                                  return;
 458                              }
 459                              if ( $.trim( text ) === '' ) {
 460                                  // [[Foo| ]] creates an invisible link
 461                                  // Instead, generate [[Foo|]]
 462                                  text = '';
 463                              }
 464                              if ( $( '#wikieditor-toolbar-link-type-int' ).is( ':checked' ) ) {
 465                                  // FIXME: Exactly how fragile is this?
 466                                  if ( $( '#wikieditor-toolbar-link-int-target-status-invalid' ).is( ':visible' ) ) {
 467                                      // Refuse to add links to invalid titles
 468                                      alert( mw.msg( 'wikieditor-toolbar-tool-link-int-invalid' ) );
 469                                      return;
 470                                  }
 471  
 472                                  if ( target === text || !text.length )
 473                                      insertText = '[[' + target + ']]';
 474                                  else
 475                                      insertText = '[[' + target + '|' + escapeInternalText( text ) + ']]';
 476                              } else {
 477                                  // Prepend http:// if there is no protocol
 478                                  if ( !target.match( /^[a-z]+:\/\/./ ) )
 479                                      target = 'http://' + target;
 480  
 481                                  // Detect if this is really an internal link in disguise
 482                                  var match = target.match( $( this ).data( 'articlePathRegex' ) );
 483                                  if ( match && !$( this ).data( 'ignoreLooksInternal' ) ) {
 484                                      var buttons = { };
 485                                      var that = this;
 486                                      buttons[ mw.msg( 'wikieditor-toolbar-tool-link-lookslikeinternal-int' ) ] =
 487                                          function () {
 488                                              $( '#wikieditor-toolbar-link-int-target' ).val( match[1] ).change();
 489                                              $( this ).dialog( 'close' );
 490                                          };
 491                                      buttons[ mw.msg( 'wikieditor-toolbar-tool-link-lookslikeinternal-ext' ) ] =
 492                                          function () {
 493                                              $( that ).data( 'ignoreLooksInternal', true );
 494                                              $( that ).closest( '.ui-dialog' ).find( 'button:first' ).click();
 495                                              $( that ).data( 'ignoreLooksInternal', false );
 496                                              $( this ).dialog( 'close' );
 497                                          };
 498                                      $.wikiEditor.modules.dialogs.quickDialog(
 499                                          mw.msg( 'wikieditor-toolbar-tool-link-lookslikeinternal', match[1] ),
 500                                          { buttons: buttons }
 501                                      );
 502                                      return;
 503                                  }
 504  
 505                                  var escTarget = escapeExternalTarget( target );
 506                                  var escText = escapeExternalText( text );
 507  
 508                                  if ( escTarget === escText )
 509                                      insertText = escTarget;
 510                                  else if ( text === '' )
 511                                      insertText = '[' + escTarget + ']';
 512                                  else
 513                                      insertText = '[' + escTarget + ' ' + escText + ']';
 514                              }
 515                              // Preserve whitespace in selection when replacing
 516                              if ( whitespace ) {
 517                                  insertText = whitespace[0] + insertText + whitespace[1];
 518                              }
 519                              $( this ).dialog( 'close' );
 520                              $.wikiEditor.modules.toolbar.fn.doAction( $( this ).data( 'context' ), {
 521                                  type: 'replace',
 522                                  options: {
 523                                      pre: insertText
 524                                  }
 525                              }, $( this ) );
 526  
 527                              // Blank form
 528                              $( '#wikieditor-toolbar-link-int-target, #wikieditor-toolbar-link-int-text' ).val( '' );
 529                              $( '#wikieditor-toolbar-link-type-int, #wikieditor-toolbar-link-type-ext' )
 530                                  .attr( 'checked', '' );
 531                          },
 532                          'wikieditor-toolbar-tool-link-cancel': function () {
 533                              // Clear any saved selection state
 534                              var context = $( this ).data( 'context' );
 535                              context.fn.restoreCursorAndScrollTop();
 536                              $( this ).dialog( 'close' );
 537                          }
 538                      },
 539                      open: function () {
 540                          var target, text, type, matches;
 541  
 542                          // Obtain the server name without the protocol. wgServer may be protocol-relative
 543                          var serverName = mw.config.get( 'wgServer' ).replace( /^(https?:)?\/\//, '' );
 544                          // Cache the articlepath regex
 545                          $( this ).data( 'articlePathRegex', new RegExp(
 546                              '^https?://' + $.escapeRE( serverName + mw.config.get( 'wgArticlePath' ) )
 547                                  .replace( /\\\$1/g, '(.*)' ) + '$'
 548                          ) );
 549                          // Pre-fill the text fields based on the current selection
 550                          var context = $( this ).data( 'context' );
 551                          // Restore and immediately save selection state, needed for inserting stuff later
 552                          context.fn.restoreCursorAndScrollTop();
 553                          context.fn.saveCursorAndScrollTop();
 554                          var selection = context.$textarea.textSelection( 'getSelection' );
 555                          $( '#wikieditor-toolbar-link-int-target' ).focus();
 556                          // Trigger the change event, so the link status indicator is up to date
 557                          $( '#wikieditor-toolbar-link-int-target' ).change();
 558                          $( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [ '', '' ] );
 559                          if ( selection !== '' ) {
 560                              if ( ( matches = selection.match( /^(\s*)\[\[([^\]\|]+)(\|([^\]\|]*))?\]\](\s*)$/ ) ) ) {
 561                                  // [[foo|bar]] or [[foo]]
 562                                  target = matches[2];
 563                                  text = ( matches[4] ? matches[4] : matches[2] );
 564                                  type = 'int';
 565                                  // Preserve whitespace when replacing
 566                                  $( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [ matches[1], matches[5] ] );
 567                              } else if ( ( matches = selection.match( /^(\s*)\[([^\] ]+)( ([^\]]+))?\](\s*)$/ ) ) ) {
 568                                  // [http://www.example.com foo] or [http://www.example.com]
 569                                  target = matches[2];
 570                                  text = ( matches[4] || '' );
 571                                  type = 'ext';
 572                                  // Preserve whitespace when replacing
 573                                  $( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [ matches[1], matches[5] ] );
 574                              } else {
 575                                  // Trim any leading and trailing whitespace from the selection,
 576                                  // but preserve it when replacing
 577                                  target = text = $.trim( selection );
 578                                  if ( target.length < selection.length ) {
 579                                      $( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [
 580                                          selection.substr( 0, selection.indexOf( target.charAt( 0 ) ) ),
 581                                          selection.substr(
 582                                              selection.lastIndexOf( target.charAt( target.length - 1 ) ) + 1
 583                                          ) ]
 584                                      );
 585                                  }
 586                              }
 587  
 588                              // Change the value by calling val() doesn't trigger the change event, so let's do that
 589                              // ourselves
 590                              if ( typeof text !== 'undefined' )
 591                                  $( '#wikieditor-toolbar-link-int-text' ).val( text ).change();
 592                              if ( typeof target !== 'undefined' )
 593                                  $( '#wikieditor-toolbar-link-int-target' ).val( target ).change();
 594                              if ( typeof type !== 'undefined' )
 595                                  $( '#wikieditor-toolbar-link-' + type ).prop( 'checked', true );
 596                          }
 597                          $( '#wikieditor-toolbar-link-int-text' ).data( 'untouched',
 598                              $( '#wikieditor-toolbar-link-int-text' ).val() ===
 599                                      $( '#wikieditor-toolbar-link-int-target' ).val() ||
 600                                  $( '#wikieditor-toolbar-link-int-text' ).hasClass( 'wikieditor-toolbar-dialog-hint' )
 601                          );
 602                          $( '#wikieditor-toolbar-link-int-target' ).suggestions();
 603  
 604                          // don't overwrite user's text
 605                          if ( selection !== '' ){
 606                              $( '#wikieditor-toolbar-link-int-text' ).data( 'untouched', false );
 607                          }
 608  
 609                          $( '#wikieditor-toolbar-link-int-text, #wikiedit-toolbar-link-int-target' )
 610                              .each( function () {
 611                                  if ( $( this ).val() === '' )
 612                                      $( this ).parent().find( 'label' ).show();
 613                              } );
 614  
 615                          if ( !$( this ).data( 'dialogkeypressset' ) ) {
 616                              $( this ).data( 'dialogkeypressset', true );
 617                              // Execute the action associated with the first button
 618                              // when the user presses Enter
 619                              $( this ).closest( '.ui-dialog' ).keypress( function ( e ) {
 620                                  if ( ( e.keyCode || e.which ) === 13 ) {
 621                                      var button = $( this ).data( 'dialogaction' ) || $( this ).find( 'button:first' );
 622                                      button.click();
 623                                      e.preventDefault();
 624                                  }
 625                              } );
 626  
 627                              // Make tabbing to a button and pressing
 628                              // Enter do what people expect
 629                              $( this ).closest( '.ui-dialog' ).find( 'button' ).focus( function () {
 630                                  $( this ).closest( '.ui-dialog' ).data( 'dialogaction', this );
 631                              } );
 632                          }
 633                      }
 634                  }
 635              },
 636              'insert-reference': {
 637                  titleMsg: 'wikieditor-toolbar-tool-reference-title',
 638                  id: 'wikieditor-toolbar-reference-dialog',
 639                  html: '\
 640                  <div class="wikieditor-toolbar-dialog-wrapper">\
 641                  <fieldset><div class="wikieditor-toolbar-table-form">\
 642                      <div class="wikieditor-toolbar-field-wrapper">\
 643                          <label for="wikieditor-toolbar-reference-text"\
 644                              rel="wikieditor-toolbar-tool-reference-text"></label>\
 645                          <input type="text" id="wikieditor-toolbar-reference-text"/>\
 646                      </div>\
 647                  </div></fieldset>\
 648                  </div>',
 649                  init: function () {
 650                      // Insert translated strings into labels
 651                      $( this ).find( '[rel]' ).each( function () {
 652                          $( this ).text( mw.msg( $( this ).attr( 'rel' ) ) );
 653                      } );
 654  
 655                  },
 656                  dialog: {
 657                      dialogClass: 'wikiEditor-toolbar-dialog',
 658                      width: 590,
 659                      buttons: {
 660                          'wikieditor-toolbar-tool-reference-insert': function () {
 661                              var insertText = $( '#wikieditor-toolbar-reference-text' ).val();
 662                              var whitespace = $( '#wikieditor-toolbar-reference-dialog' ).data( 'whitespace' );
 663                              var attributes = $( '#wikieditor-toolbar-reference-dialog' ).data( 'attributes' );
 664                              // Close the dialog
 665                              $( this ).dialog( 'close' );
 666                              $.wikiEditor.modules.toolbar.fn.doAction(
 667                                  $( this ).data( 'context' ),
 668                                  {
 669                                      type: 'replace',
 670                                      options: {
 671                                          pre: whitespace[0] + '<ref' + attributes + '>',
 672                                          peri: insertText,
 673                                          post: '</ref>' + whitespace[1]
 674                                      }
 675                                  },
 676                                  $( this )
 677                              );
 678                              // Restore form state
 679                              $( '#wikieditor-toolbar-reference-text' ).val( '' );
 680                          },
 681                          'wikieditor-toolbar-tool-reference-cancel': function () {
 682                              // Clear any saved selection state
 683                              var context = $( this ).data( 'context' );
 684                              context.fn.restoreCursorAndScrollTop();
 685                              $( this ).dialog( 'close' );
 686                          }
 687                      },
 688                      open: function () {
 689                          // Pre-fill the text fields based on the current selection
 690                          var context = $( this ).data( 'context' );
 691                          // Restore and immediately save selection state, needed for inserting stuff later
 692                          context.fn.restoreCursorAndScrollTop();
 693                          context.fn.saveCursorAndScrollTop();
 694                          var selection = context.$textarea.textSelection( 'getSelection' );
 695                          // set focus
 696                          $( '#wikieditor-toolbar-reference-text' ).focus();
 697                          $( '#wikieditor-toolbar-reference-dialog' )
 698                              .data( 'whitespace', [ '', '' ] )
 699                              .data( 'attributes', '' );
 700                          if ( selection !== '' ) {
 701                              var matches, text;
 702                              if ( ( matches = selection.match( /^(\s*)<ref([^\>]*)>([^<]*)<\/ref\>(\s*)$/ ) ) ) {
 703                                  text = matches[3];
 704                                  // Preserve whitespace when replacing
 705                                  $( '#wikieditor-toolbar-reference-dialog' )
 706                                      .data( 'whitespace', [ matches[1], matches[4] ] );
 707                                  $( '#wikieditor-toolbar-reference-dialog' ).data( 'attributes', matches[2] );
 708                              } else {
 709                                  text = selection;
 710                              }
 711                              $( '#wikieditor-toolbar-reference-text' ).val( text );
 712                          }
 713                          if ( !( $( this ).data( 'dialogkeypressset' ) ) ) {
 714                              $( this ).data( 'dialogkeypressset', true );
 715                              // Execute the action associated with the first button
 716                              // when the user presses Enter
 717                              $( this ).closest( '.ui-dialog' ).keypress( function ( e ) {
 718                                  if ( ( e.keyCode || e.which ) === 13 ) {
 719                                      var button = $( this ).data( 'dialogaction' ) || $( this ).find( 'button:first' );
 720                                      button.click();
 721                                      e.preventDefault();
 722                                  }
 723                              } );
 724                              // Make tabbing to a button and pressing
 725                              // Enter do what people expect
 726                              $( this ).closest( '.ui-dialog' ).find( 'button' ).focus( function () {
 727                                  $( this ).closest( '.ui-dialog' ).data( 'dialogaction', this );
 728                              } );
 729                          }
 730                      }
 731                  }
 732              },
 733              'insert-file': {
 734                  titleMsg: 'wikieditor-toolbar-tool-file-title',
 735                  id: 'wikieditor-toolbar-file-dialog',
 736                  html: '\
 737                      <fieldset>\
 738                          <div class="wikieditor-toolbar-field-wrapper">\
 739                              <label for="wikieditor-toolbar-file-target" rel="wikieditor-toolbar-file-target" id="wikieditor-toolbar-tool-file-target-label"></label>\
 740                              <input type="text" id="wikieditor-toolbar-file-target"/>\
 741                          </div>\
 742                          <div class="wikieditor-toolbar-field-wrapper">\
 743                              <label for="wikieditor-toolbar-file-caption" rel="wikieditor-toolbar-file-caption"></label>\
 744                              <input type="text" id="wikieditor-toolbar-file-caption"/>\
 745                          </div>\
 746                          <div class="wikieditor-toolbar-file-options">\
 747                              <div class="wikieditor-toolbar-field-wrapper">\
 748                                  <label for="wikieditor-toolbar-file-size" rel="wikieditor-toolbar-file-size"></label><br/>\
 749                                  <input type="text" id="wikieditor-toolbar-file-size" size="5"/>\
 750                              </div>\
 751                              <div class="wikieditor-toolbar-field-wrapper">\
 752                                  <label for="wikieditor-toolbar-file-float" rel="wikieditor-toolbar-file-float"></label><br/>\
 753                                  <select type="text" id="wikieditor-toolbar-file-float">\
 754                                  <option value="default" selected="selected" rel="wikieditor-toolbar-file-default"></option>\
 755                                  <option data-i18n-magic="img_none"></option>\
 756                                  <option data-i18n-magic="img_center"></option>\
 757                                  <option data-i18n-magic="img_left"></option>\
 758                                  <option data-i18n-magic="img_right"></option>\
 759                                  </select>\
 760                              </div>\
 761                              <div class="wikieditor-toolbar-field-wrapper">\
 762                                  <label for="wikieditor-toolbar-file-format" rel="wikieditor-toolbar-file-format"></label><br/>\
 763                                  <select type="text" id="wikieditor-toolbar-file-format">\
 764                                  <option selected="selected" data-i18n-magic="img_thumbnail">thumb</option>\
 765                                  <option data-i18n-magic="img_framed"></option>\
 766                                  <option data-i18n-magic="img_frameless"></option>\
 767                                  <option value="default" rel="wikieditor-toolbar-file-format-none"></option>\
 768                                  </select>\
 769                              </div>\
 770                          </div>\
 771                      </fieldset>',
 772                  init: function () {
 773                      var magicWordsI18N = mw.config.get( 'wgWikiEditorMagicWords' );
 774                      var defaultMsg = mw.msg( 'wikieditor-toolbar-file-default' );
 775                      $( this )
 776                          .find( '[data-i18n-magic]' )
 777                              .text( function () {
 778                                  return magicWordsI18N[ $( this ).attr( 'data-i18n-magic' ) ];
 779                              } )
 780                              .removeAttr( 'data-i18n-magic' )
 781                              .end()
 782                          .find( '#wikieditor-toolbar-file-size' )
 783                              .attr( 'placeholder', defaultMsg )
 784                              // The message may be long in some languages
 785                              .attr( 'size', defaultMsg.length )
 786                              .end()
 787                          .find( '[rel]' )
 788                              .text( function () {
 789                                  return mw.msg( $( this ).attr( 'rel' ) );
 790                              } )
 791                              .removeAttr( 'rel' )
 792                              .end();
 793                  },
 794                  dialog: {
 795                      resizable: false,
 796                      dialogClass: 'wikiEditor-toolbar-dialog',
 797                      width: 590,
 798                      buttons: {
 799                          'wikieditor-toolbar-tool-file-insert': function () {
 800                              var fileName, caption, fileFloat, fileFormat, fileSize, fileTitle,
 801                                  options, fileUse,
 802                                  hasPxRgx = /.+px$/,
 803                                  magicWordsI18N = mw.config.get( 'wgWikiEditorMagicWords' );
 804                              fileName = $( '#wikieditor-toolbar-file-target' ).val();
 805                              caption = $( '#wikieditor-toolbar-file-caption' ).val();
 806                              fileFloat = $( '#wikieditor-toolbar-file-float' ).val();
 807                              fileFormat = $( '#wikieditor-toolbar-file-format' ).val();
 808                              fileSize = $( '#wikieditor-toolbar-file-size' ).val();
 809                              // Append px to end to size if not already contains it
 810                              if ( fileSize !== '' && !hasPxRgx.test( fileSize ) ) {
 811                                  fileSize += 'px';
 812                              }
 813                              if ( fileName !== '' ) {
 814                                  fileTitle = new mw.Title( fileName );
 815                                  // Append file namespace prefix to filename if not already contains it
 816                                  if ( fileTitle.getNamespaceId() !== 6 ){
 817                                      fileTitle = new mw.Title( fileName, 6 );
 818                                  }
 819                                  fileName = fileTitle.toText();
 820                              }
 821                              options = [ fileSize, fileFormat, fileFloat ];
 822                              // Filter empty values
 823                              options = $.grep( options, function ( val ) {
 824                                  return val.length && val !== 'default';
 825                              } );
 826                              if ( caption.length ) {
 827                                  options.push( caption );
 828                              }
 829                              fileUse = options.length === 0 ? fileName : ( fileName + '|' + options.join( '|' ) );
 830                              $( this ).dialog( 'close' );
 831                              $.wikiEditor.modules.toolbar.fn.doAction(
 832                                  $( this ).data( 'context' ),
 833                                  {
 834                                      type: 'replace',
 835                                      options: {
 836                                          pre: '[[',
 837                                          peri: fileUse,
 838                                          post: ']]',
 839                                          ownline: true
 840                                      }
 841                                  },
 842                                  $( this )
 843                              );
 844  
 845                              // Restore form state
 846                              $( ['#wikieditor-toolbar-file-target',
 847                                  '#wikieditor-toolbar-file-caption',
 848                                  '#wikieditor-toolbar-file-size'].join( ',' )
 849                              ).val( '' );
 850                              $( '#wikieditor-toolbar-file-float' ).val( 'default' );
 851                              /*jshint camelcase: false */
 852                              $( '#wikieditor-toolbar-file-format' ).val( magicWordsI18N.img_thumbnail );
 853                          },
 854                          'wikieditor-toolbar-tool-file-cancel': function () {
 855                              $( this ).dialog( 'close' );
 856                          }
 857                      },
 858                      open: function () {
 859                          $( '#wikieditor-toolbar-file-target' ).focus();
 860                          if ( !( $( this ).data( 'dialogkeypressset' ) ) ) {
 861                              $( this ).data( 'dialogkeypressset', true );
 862                              // Execute the action associated with the first button
 863                              // when the user presses Enter
 864                              $( this ).closest( '.ui-dialog' ).keypress( function ( e ) {
 865                                  if ( e.which === 13 ) {
 866                                      var button = $( this ).data( 'dialogaction' ) ||
 867                                          $( this ).find( 'button:first' );
 868                                      button.click();
 869                                      e.preventDefault();
 870                                  }
 871                              } );
 872  
 873                              // Make tabbing to a button and pressing
 874                              // Enter do what people expect
 875                              $( this ).closest( '.ui-dialog' ).find( 'button' ).focus( function () {
 876                                  $( this ).closest( '.ui-dialog' ).data( 'dialogaction', this );
 877                              } );
 878                          }
 879                      }
 880                  }
 881              },
 882              'insert-table': {
 883                  titleMsg: 'wikieditor-toolbar-tool-table-title',
 884                  id: 'wikieditor-toolbar-table-dialog',
 885                  // FIXME: Localize 'x'?
 886                  html: '\
 887                      <div class="wikieditor-toolbar-dialog-wrapper">\
 888                      <fieldset><div class="wikieditor-toolbar-table-form">\
 889                          <div class="wikieditor-toolbar-field-wrapper">\
 890                              <input type="checkbox" id="wikieditor-toolbar-table-dimensions-header" checked/>\
 891                              <label for="wikieditor-toolbar-table-dimensions-header"\
 892                                  rel="wikieditor-toolbar-tool-table-dimensions-header"></label>\
 893                          </div>\
 894                          <div class="wikieditor-toolbar-field-wrapper">\
 895                              <input type="checkbox" id="wikieditor-toolbar-table-wikitable" checked/>\
 896                              <label for="wikieditor-toolbar-table-wikitable" rel="wikieditor-toolbar-tool-table-wikitable"></label>\
 897                          </div>\
 898                          <div class="wikieditor-toolbar-field-wrapper">\
 899                              <input type="checkbox" id="wikieditor-toolbar-table-sortable"/>\
 900                              <label for="wikieditor-toolbar-table-sortable" rel="wikieditor-toolbar-tool-table-sortable"></label>\
 901                          </div>\
 902                          <div class="wikieditor-toolbar-table-dimension-fields">\
 903                              <div class="wikieditor-toolbar-field-wrapper">\
 904                                  <label for="wikieditor-toolbar-table-dimensions-rows"\
 905                                      rel="wikieditor-toolbar-tool-table-dimensions-rows"></label><br/>\
 906                                  <input type="number" min="1" max="1000" id="wikieditor-toolbar-table-dimensions-rows" size="4"/>\
 907                              </div>\
 908                              <div class="wikieditor-toolbar-field-wrapper">\
 909                                  <label for="wikieditor-toolbar-table-dimensions-columns"\
 910                                      rel="wikieditor-toolbar-tool-table-dimensions-columns"></label><br/>\
 911                                  <input type="number" min="1" max="1000" id="wikieditor-toolbar-table-dimensions-columns" size="4"/>\
 912                              </div>\
 913                          </div>\
 914                      </div></fieldset>\
 915                      <div class="wikieditor-toolbar-table-preview-wrapper" >\
 916                          <span rel="wikieditor-toolbar-tool-table-example"></span>\
 917                          <div class="wikieditor-toolbar-table-preview-content">\
 918                              <table id="wikieditor-toolbar-table-preview" class="wikieditor-toolbar-table-preview wikitable">\
 919                              <thead>\
 920                                  <tr class="wikieditor-toolbar-table-preview-header">\
 921                                      <th rel="wikieditor-toolbar-tool-table-example-header"></th>\
 922                                      <th rel="wikieditor-toolbar-tool-table-example-header"></th>\
 923                                      <th rel="wikieditor-toolbar-tool-table-example-header"></th>\
 924                                  </tr>\
 925                              </thead><tbody>\
 926                                  <tr class="wikieditor-toolbar-table-preview-hidden" style="display: none;">\
 927                                      <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 928                                      <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 929                                      <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 930                                  </tr><tr>\
 931                                      <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 932                                      <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 933                                      <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 934                                  </tr><tr>\
 935                                      <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 936                                      <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 937                                      <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 938                                  </tr><tr>\
 939                                      <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 940                                      <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 941                                      <td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
 942                                  </tr>\
 943                              </tbody>\
 944                              </table>\
 945                          </div>\
 946                      </div></div>',
 947                  init: function () {
 948                      $( this ).find( '[rel]' ).each( function () {
 949                          $( this ).text( mw.msg( $( this ).attr( 'rel' ) ) );
 950                      } );
 951                      // Set tabindexes on form fields
 952                      $.wikiEditor.modules.dialogs.fn.setTabindexes( $( this ).find( 'input' ).not( '[tabindex]' ) );
 953  
 954                      $( '#wikieditor-toolbar-table-dimensions-rows' ).val( 3 );
 955                      $( '#wikieditor-toolbar-table-dimensions-columns' ).val( 3 );
 956                      $( '#wikieditor-toolbar-table-wikitable' ).click( function () {
 957                          $( '.wikieditor-toolbar-table-preview' ).toggleClass( 'wikitable' );
 958                      } );
 959  
 960                      // Hack for sortable preview: dynamically adding
 961                      // sortable class doesn't work, so we use a clone
 962                      $( '#wikieditor-toolbar-table-preview' )
 963                          .clone()
 964                          .attr( 'id', 'wikieditor-toolbar-table-preview2' )
 965                          .addClass( 'sortable' )
 966                          .insertAfter( $( '#wikieditor-toolbar-table-preview' ) )
 967                          .hide();
 968  
 969                      mw.loader.using( 'jquery.tablesorter', function () {
 970                          $( '#wikieditor-toolbar-table-preview2' ).tablesorter();
 971                      } );
 972  
 973                      $( '#wikieditor-toolbar-table-sortable' ).click( function () {
 974                          // Swap the currently shown one clone with the other one
 975                          $( '#wikieditor-toolbar-table-preview' )
 976                              .hide()
 977                              .attr( 'id', 'wikieditor-toolbar-table-preview3' );
 978                          $( '#wikieditor-toolbar-table-preview2' )
 979                              .attr( 'id', 'wikieditor-toolbar-table-preview' )
 980                              .show();
 981                          $( '#wikieditor-toolbar-table-preview3' ).attr( 'id', 'wikieditor-toolbar-table-preview2' );
 982                      } );
 983  
 984                      $( '#wikieditor-toolbar-table-dimensions-header' ).click( function () {
 985                          // Instead of show/hiding, switch the HTML around
 986                          // We do this because the sortable tables script styles the first row,
 987                          // visible or not
 988                          var headerHTML = $( '.wikieditor-toolbar-table-preview-header' ).html();
 989                          var hiddenHTML = $( '.wikieditor-toolbar-table-preview-hidden' ).html();
 990                          $( '.wikieditor-toolbar-table-preview-header' ).html( hiddenHTML );
 991                          $( '.wikieditor-toolbar-table-preview-hidden' ).html( headerHTML );
 992                          if ( typeof jQuery.fn.tablesorter === 'function' ) {
 993                              $( '#wikieditor-toolbar-table-preview, #wikieditor-toolbar-table-preview2' )
 994                                  .filter( '.sortable' )
 995                                  .tablesorter();
 996                          }
 997                      } );
 998                  },
 999                  dialog: {
1000                      resizable: false,
1001                      dialogClass: 'wikiEditor-toolbar-dialog',
1002                      width: 590,
1003                      buttons: {
1004                          'wikieditor-toolbar-tool-table-insert': function () {
1005                              var rowsVal = $( '#wikieditor-toolbar-table-dimensions-rows' ).val();
1006                              var colsVal = $( '#wikieditor-toolbar-table-dimensions-columns' ).val();
1007                              var rows = parseInt( rowsVal, 10 );
1008                              var cols = parseInt( colsVal, 10 );
1009                              var header = $( '#wikieditor-toolbar-table-dimensions-header' ).prop( 'checked' ) ? 1 : 0;
1010                              if ( isNaN( rows ) || isNaN( cols ) || String( rows ) !== rowsVal || String( cols ) !== colsVal || rowsVal < 0 || colsVal < 0 ) {
1011                                  alert( mw.msg( 'wikieditor-toolbar-tool-table-invalidnumber' ) );
1012                                  return;
1013                              }
1014                              if ( rows + header === 0 || cols === 0 ) {
1015                                  alert( mw.msg( 'wikieditor-toolbar-tool-table-zero' ) );
1016                                  return;
1017                              }
1018                              if ( ( rows * cols ) > 1000 ) {
1019                                  // 1000 is in the English message. The parameter replacement is kept for BC.
1020                                  alert( mw.msg( 'wikieditor-toolbar-tool-table-toomany', 1000 ) );
1021                                  return;
1022                              }
1023                              var headerText = mw.msg( 'wikieditor-toolbar-tool-table-example-header' );
1024                              var normalText = mw.msg( 'wikieditor-toolbar-tool-table-example' );
1025                              var table = "";
1026                              for ( var r = 0; r < rows + header; r++ ) {
1027                                  table += "|-\n";
1028                                  for ( var c = 0; c < cols; c++ ) {
1029                                      var isHeader = ( header && r === 0 );
1030                                      var delim = isHeader ? '!' : '|';
1031                                      if ( c > 0 ) {
1032                                          delim += delim;
1033                                      }
1034                                      table += delim + ' ' + ( isHeader ? headerText : normalText ) + ' ';
1035                                  }
1036                                  // Replace trailing space by newline
1037                                  // table[table.length - 1] is read-only
1038                                  table = table.substr( 0, table.length - 1 ) + "\n";
1039                              }
1040                              var classes = [];
1041                              if ( $( '#wikieditor-toolbar-table-wikitable' ).is( ':checked' ) )
1042                                  classes.push( 'wikitable' );
1043                              if ( $( '#wikieditor-toolbar-table-sortable' ).is( ':checked' ) )
1044                                  classes.push( 'sortable' );
1045                              var classStr = classes.length > 0 ? ' class="' + classes.join( ' ' ) + '"' : '';
1046                              $( this ).dialog( 'close' );
1047                              $.wikiEditor.modules.toolbar.fn.doAction(
1048                                  $( this ).data( 'context' ),
1049                                  {
1050                                      type: 'replace',
1051                                      options: {
1052                                          pre: '{|' + classStr + "\n",
1053                                          peri: table,
1054                                          post: '|}',
1055                                          ownline: true
1056                                      }
1057                                  },
1058                                  $( this )
1059                              );
1060  
1061                              // Restore form state
1062                                  $( '#wikieditor-toolbar-table-dimensions-rows' ).val( 3 );
1063                                  $( '#wikieditor-toolbar-table-dimensions-columns' ).val( 3 );
1064                              // Simulate clicks instead of setting values, so the according
1065                              // actions are performed
1066                                  if ( !$( '#wikieditor-toolbar-table-dimensions-header' ).is( ':checked' ) )
1067                                      $( '#wikieditor-toolbar-table-dimensions-header' ).click();
1068                                  if ( !$( '#wikieditor-toolbar-table-wikitable' ).is( ':checked' ) )
1069                                      $( '#wikieditor-toolbar-table-wikitable' ).click();
1070                                  if ( $( '#wikieditor-toolbar-table-sortable' ).is( ':checked' ) )
1071                                      $( '#wikieditor-toolbar-table-sortable' ).click();
1072                          },
1073                          'wikieditor-toolbar-tool-table-cancel': function () {
1074                              $( this ).dialog( 'close' );
1075                          }
1076                      },
1077                      open: function () {
1078                          $( '#wikieditor-toolbar-table-dimensions-rows' ).focus();
1079                          if ( !( $( this ).data( 'dialogkeypressset' ) ) ) {
1080                              $( this ).data( 'dialogkeypressset', true );
1081                              // Execute the action associated with the first button
1082                              // when the user presses Enter
1083                              $( this ).closest( '.ui-dialog' ).keypress( function ( e ) {
1084                                  if ( ( e.keyCode || e.which ) === 13 ) {
1085                                      var button = $( this ).data( 'dialogaction' ) || $( this ).find( 'button:first' );
1086                                      button.click();
1087                                      e.preventDefault();
1088                                  }
1089                              } );
1090  
1091                              // Make tabbing to a button and pressing
1092                              // Enter do what people expect
1093                              $( this ).closest( '.ui-dialog' ).find( 'button' ).focus( function () {
1094                                  $( this ).closest( '.ui-dialog' ).data( 'dialogaction', this );
1095                              } );
1096                          }
1097                      }
1098                  }
1099              },
1100              'search-and-replace': {
1101                  'browsers': {
1102                      // Left-to-right languages
1103                      'ltr': {
1104                          'msie': false,
1105                          'firefox': [['>=', 2]],
1106                          'opera': false,
1107                          'safari': [['>=', 3]],
1108                          'chrome': [['>=', 3]]
1109                      },
1110                      // Right-to-left languages
1111                      'rtl': {
1112                          'msie': false,
1113                          'firefox': [['>=', 2]],
1114                          'opera': false,
1115                          'safari': [['>=', 3]],
1116                          'chrome': [['>=', 3]]
1117                      }
1118                  },
1119                  titleMsg: 'wikieditor-toolbar-tool-replace-title',
1120                  id: 'wikieditor-toolbar-replace-dialog',
1121                  html: '\
1122                      <div id="wikieditor-toolbar-replace-message">\
1123                          <div id="wikieditor-toolbar-replace-nomatch" rel="wikieditor-toolbar-tool-replace-nomatch"></div>\
1124                          <div id="wikieditor-toolbar-replace-success"></div>\
1125                          <div id="wikieditor-toolbar-replace-emptysearch" rel="wikieditor-toolbar-tool-replace-emptysearch"></div>\
1126                          <div id="wikieditor-toolbar-replace-invalidregex"></div>\
1127                      </div>\
1128                      <fieldset>\
1129                          <div class="wikieditor-toolbar-field-wrapper">\
1130                              <label for="wikieditor-toolbar-replace-search" rel="wikieditor-toolbar-tool-replace-search"></label>\
1131                              <input type="text" id="wikieditor-toolbar-replace-search" style="width: 100%;"/>\
1132                          </div>\
1133                          <div class="wikieditor-toolbar-field-wrapper">\
1134                              <label for="wikieditor-toolbar-replace-replace" rel="wikieditor-toolbar-tool-replace-replace"></label>\
1135                              <input type="text" id="wikieditor-toolbar-replace-replace" style="width: 100%;"/>\
1136                          </div>\
1137                          <div class="wikieditor-toolbar-field-wrapper">\
1138                              <input type="checkbox" id="wikieditor-toolbar-replace-case"/>\
1139                              <label for="wikieditor-toolbar-replace-case" rel="wikieditor-toolbar-tool-replace-case"></label>\
1140                          </div>\
1141                          <div class="wikieditor-toolbar-field-wrapper">\
1142                              <input type="checkbox" id="wikieditor-toolbar-replace-regex"/>\
1143                              <label for="wikieditor-toolbar-replace-regex" rel="wikieditor-toolbar-tool-replace-regex"></label>\
1144                          </div>\
1145                      </fieldset>',
1146                  init: function () {
1147                      $( this ).find( '[rel]' ).each( function () {
1148                          $( this ).text( mw.msg( $( this ).attr( 'rel' ) ) );
1149                      } );
1150                      // Set tabindexes on form fields
1151                      $.wikiEditor.modules.dialogs.fn.setTabindexes( $( this ).find( 'input' ).not( '[tabindex]' ) );
1152  
1153                      // TODO: Find a cleaner way to share this function
1154                      $( this ).data( 'replaceCallback', function ( mode ) {
1155                          var offset, textRemainder, regex, index, i,
1156                              start, end;
1157  
1158                          $( '#wikieditor-toolbar-replace-nomatch, #wikieditor-toolbar-replace-success, #wikieditor-toolbar-replace-emptysearch, #wikieditor-toolbar-replace-invalidregex' ).hide();
1159  
1160                          // Search string cannot be empty
1161                          var searchStr = $( '#wikieditor-toolbar-replace-search' ).val();
1162                          if ( searchStr === '' ) {
1163                              $( '#wikieditor-toolbar-replace-emptysearch' ).show();
1164                              return;
1165                          }
1166  
1167                          // Replace string can be empty
1168                          var replaceStr = $( '#wikieditor-toolbar-replace-replace' ).val();
1169  
1170                          // Prepare the regular expression flags
1171                          var flags = 'm';
1172                          var matchCase = $( '#wikieditor-toolbar-replace-case' ).is( ':checked' );
1173                          if ( !matchCase ) {
1174                              flags += 'i';
1175                          }
1176                          var isRegex = $( '#wikieditor-toolbar-replace-regex' ).is( ':checked' );
1177                          if ( !isRegex ) {
1178                              searchStr = $.escapeRE( searchStr );
1179                          }
1180                          if ( mode === 'replaceAll' ) {
1181                              flags += 'g';
1182                          }
1183  
1184                          try {
1185                              regex = new RegExp( searchStr, flags );
1186                          } catch ( e ) {
1187                              $( '#wikieditor-toolbar-replace-invalidregex' )
1188                                  .text( mw.msg( 'wikieditor-toolbar-tool-replace-invalidregex',
1189                                      e.message ) )
1190                                  .show();
1191                              return;
1192                          }
1193  
1194                          var $textarea = $( this ).data( 'context' ).$textarea;
1195                          var text = $textarea.textSelection( 'getContents' );
1196                          var match = false;
1197                          if ( mode !== 'replaceAll' ) {
1198                              if ( mode === 'replace' ) {
1199                                  offset = $( this ).data( 'matchIndex' );
1200                              } else {
1201                                  offset = $( this ).data( 'offset' );
1202                              }
1203                              textRemainder = text.substr( offset );
1204                              match = textRemainder.match( regex );
1205                          }
1206                          if ( !match ) {
1207                              // Search hit BOTTOM, continuing at TOP
1208                              // TODO: Add a "Wrap around" option.
1209                              offset = 0;
1210                              textRemainder = text;
1211                              match = textRemainder.match( regex );
1212                          }
1213  
1214                          if ( !match ) {
1215                              $( '#wikieditor-toolbar-replace-nomatch' ).show();
1216                          } else if ( mode === 'replaceAll' ) {
1217                              // Instead of using repetitive .match() calls, we use one .match() call with /g
1218                              // and indexOf() followed by substr() to find the offsets. This is actually
1219                              // faster because our indexOf+substr loop is faster than a match loop, and the
1220                              // /g match is so ridiculously fast that it's negligible.
1221                              // FIXME: Repetitively calling encapsulateSelection() is probably the best strategy
1222                              // in Firefox/Webkit, but in IE replacing the entire content once is better.
1223                              for ( i = 0; i < match.length; i++ ) {
1224                                  index = textRemainder.indexOf( match[i] );
1225                                  if ( index === -1 ) {
1226                                      // This shouldn't happen
1227                                      break;
1228                                  }
1229                                  var matchedText = textRemainder.substr( index, match[i].length );
1230                                  textRemainder = textRemainder.substr( index + match[i].length );
1231  
1232                                  start = index + offset;
1233                                  end = start + match[i].length;
1234                                  // Make regex placeholder substitution ($1) work
1235                                  var replace = isRegex ? matchedText.replace( regex, replaceStr ) : replaceStr;
1236                                  var newEnd = start + replace.length;
1237                                  $textarea
1238                                      .textSelection( 'setSelection', { 'start': start, 'end': end } )
1239                                      .textSelection( 'encapsulateSelection', {
1240                                              'peri': replace,
1241                                              'replace': true } )
1242                                      .textSelection( 'setSelection', { 'start': start, 'end': newEnd } );
1243                                  offset = newEnd;
1244                              }
1245                              $( '#wikieditor-toolbar-replace-success' )
1246                                  .text( mw.msg( 'wikieditor-toolbar-tool-replace-success', match.length ) )
1247                                  .show();
1248                              $( this ).data( 'offset', 0 );
1249                          } else {
1250  
1251                              if ( mode === 'replace' ) {
1252                                  var actualReplacement;
1253  
1254                                  if ( isRegex ) {
1255                                      // If backreferences (like $1) are used, the actual actual replacement string will be different
1256                                      actualReplacement = match[0].replace( regex, replaceStr );
1257                                  } else {
1258                                      actualReplacement = replaceStr;
1259                                  }
1260  
1261                                  if ( match ) {
1262                                      // Do the replacement
1263                                      $textarea.textSelection( 'encapsulateSelection', {
1264                                              'peri': actualReplacement,
1265                                              'replace': true } );
1266                                      // Reload the text after replacement
1267                                      text = $textarea.textSelection( 'getContents' );
1268                                  }
1269  
1270                                  // Find the next instance
1271                                  offset = offset + match[0].length + actualReplacement.length;
1272                                  textRemainder = text.substr( offset );
1273                                  match = textRemainder.match( regex );
1274  
1275                                  if ( match ) {
1276                                      start = offset + match.index;
1277                                      end = start + match[0].length;
1278                                  } else {
1279                                      // If no new string was found, try searching from the beginning.
1280                                      // TODO: Add a "Wrap around" option.
1281                                      textRemainder = text;
1282                                      match = textRemainder.match( regex );
1283                                      if ( match ) {
1284                                          start = match.index;
1285                                          end = start + match[0].length;
1286                                      } else {
1287                                          // Give up
1288                                          start = 0;
1289                                          end = 0;
1290                                      }
1291                                  }
1292                              } else {
1293                                  start = offset + match.index;
1294                                  end = start + match[0].length;
1295                              }
1296  
1297                              $( this ).data( 'matchIndex', start );
1298  
1299                              $textarea.textSelection( 'setSelection', {
1300                                      'start': start,
1301                                      'end': end
1302                              } );
1303                              $textarea.textSelection( 'scrollToCaretPosition' );
1304                              $( this ).data( 'offset', end );
1305                              $textarea[0].focus();
1306                          }
1307                      } );
1308                  },
1309                  dialog: {
1310                      width: 500,
1311                      dialogClass: 'wikiEditor-toolbar-dialog',
1312                      modal: false,
1313                      buttons: {
1314                          'wikieditor-toolbar-tool-replace-button-findnext': function ( e ) {
1315                              $( this ).closest( '.ui-dialog' ).data( 'dialogaction', e.target );
1316                              $( this ).data( 'replaceCallback' ).call( this, 'find' );
1317                          },
1318                          'wikieditor-toolbar-tool-replace-button-replace': function ( e ) {
1319                              $( this ).closest( '.ui-dialog' ).data( 'dialogaction', e.target );
1320                              $( this ).data( 'replaceCallback' ).call( this, 'replace' );
1321                          },
1322                          'wikieditor-toolbar-tool-replace-button-replaceall': function ( e ) {
1323                              $( this ).closest( '.ui-dialog' ).data( 'dialogaction', e.target );
1324                              $( this ).data( 'replaceCallback' ).call( this, 'replaceAll' );
1325                          },
1326                          'wikieditor-toolbar-tool-replace-close': function () {
1327                              $( this ).dialog( 'close' );
1328                          }
1329                      },
1330                      open: function () {
1331                          $( this ).data( 'offset', 0 );
1332                          $( this ).data( 'matchIndex', 0 );
1333  
1334                          $( '#wikieditor-toolbar-replace-search' ).focus();
1335                          $( '#wikieditor-toolbar-replace-nomatch, #wikieditor-toolbar-replace-success, #wikieditor-toolbar-replace-emptysearch, #wikieditor-toolbar-replace-invalidregex' ).hide();
1336                          if ( !( $( this ).data( 'onetimeonlystuff' ) ) ) {
1337                              $( this ).data( 'onetimeonlystuff', true );
1338                              // Execute the action associated with the first button
1339                              // when the user presses Enter
1340                              $( this ).closest( '.ui-dialog' ).keypress( function ( e ) {
1341                                  if ( ( e.keyCode || e.which ) === 13 ) {
1342                                      var button = $( this ).data( 'dialogaction' ) || $( this ).find( 'button:first' );
1343                                      button.click();
1344                                      e.preventDefault();
1345                                  }
1346                              } );
1347                              // Make tabbing to a button and pressing
1348                              // Enter do what people expect
1349                              $( this ).closest( '.ui-dialog' ).find( 'button' ).focus( function () {
1350                                  $( this ).closest( '.ui-dialog' ).data( 'dialogaction', this );
1351                              } );
1352                          }
1353                          var dialog = $( this ).closest( '.ui-dialog' );
1354                          var that = this;
1355                          var context = $( this ).data( 'context' );
1356                          var textbox = context.$textarea;
1357  
1358                          $( textbox )
1359                              .bind( 'keypress.srdialog', function ( e ) {
1360                                  if ( e.which === 13 ) {
1361                                      // Enter
1362                                      var button = dialog.data( 'dialogaction' ) || dialog.find( 'button:first' );
1363                                      button.click();
1364                                      e.preventDefault();
1365                                  } else if ( e.which === 27 ) {
1366                                      // Escape
1367                                      $( that ).dialog( 'close' );
1368                                  }
1369                              } );
1370                      },
1371                      close: function () {
1372                          var context = $( this ).data( 'context' );
1373                          var textbox = context.$textarea;
1374                          $( textbox ).unbind( 'keypress.srdialog' );
1375                          $( this ).closest( '.ui-dialog' ).data( 'dialogaction', false );
1376                      }
1377                  }
1378              }
1379          } };
1380      }
1381  
1382  };
1383  
1384  }( jQuery, mediaWiki ) );


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1