mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/WikiEditor
synced 2024-11-12 09:57:16 +00:00
cf74f4e0a0
Bug: 64896 Change-Id: I67ea669a074317f44eb09cf759c0121bad259b3c
1383 lines
54 KiB
JavaScript
1383 lines
54 KiB
JavaScript
/**
|
|
* Configuration of Dialog module for wikiEditor
|
|
*/
|
|
/*jshint curly:false, noarg:false, quotmark:false, onevar:false */
|
|
/*global alert */
|
|
( function ( $, mw ) {
|
|
|
|
var hasOwn = Object.prototype.hasOwnProperty;
|
|
|
|
$.wikiEditor.modules.dialogs.config = {
|
|
|
|
replaceIcons: function ( $textarea ) {
|
|
$textarea
|
|
.wikiEditor( 'removeFromToolbar', { section: 'main', group: 'insert', tool: 'xlink' } )
|
|
.wikiEditor( 'removeFromToolbar', { section: 'main', group: 'insert', tool: 'ilink' } )
|
|
.wikiEditor( 'removeFromToolbar', { section: 'main', group: 'insert', tool: 'file' } )
|
|
.wikiEditor( 'removeFromToolbar', { section: 'main', group: 'insert', tool: 'reference' } )
|
|
.wikiEditor( 'removeFromToolbar', { section: 'advanced', group: 'insert', tool: 'table' } )
|
|
.wikiEditor( 'addToToolbar', {
|
|
section: 'main',
|
|
group: 'insert',
|
|
tools: {
|
|
'link': {
|
|
labelMsg: 'wikieditor-toolbar-tool-link',
|
|
type: 'button',
|
|
icon: 'insert-link.png',
|
|
offset: [2, -1654],
|
|
action: {
|
|
type: 'dialog',
|
|
module: 'insert-link'
|
|
}
|
|
},
|
|
'file': {
|
|
labelMsg: 'wikieditor-toolbar-tool-file',
|
|
type: 'button',
|
|
icon: 'insert-file.png',
|
|
offset: [2, -1438],
|
|
action: {
|
|
type: 'dialog',
|
|
module: 'insert-file'
|
|
}
|
|
},
|
|
'reference': {
|
|
labelMsg: 'wikieditor-toolbar-tool-reference',
|
|
filters: [ 'body.ns-subject' ],
|
|
type: 'button',
|
|
icon: 'insert-reference.png',
|
|
offset: [2, -1798],
|
|
action: {
|
|
type: 'dialog',
|
|
module: 'insert-reference'
|
|
}
|
|
}
|
|
}
|
|
} )
|
|
.wikiEditor( 'addToToolbar', {
|
|
section: 'advanced',
|
|
group: 'insert',
|
|
tools: {
|
|
'table': {
|
|
labelMsg: 'wikieditor-toolbar-tool-table',
|
|
type: 'button',
|
|
icon: 'insert-table.png',
|
|
offset: [2, -1942],
|
|
action: {
|
|
type: 'dialog',
|
|
module: 'insert-table'
|
|
}
|
|
}
|
|
}
|
|
} )
|
|
.wikiEditor( 'addToToolbar', {
|
|
section: 'advanced',
|
|
groups: {
|
|
'search': {
|
|
tools: {
|
|
'replace': {
|
|
labelMsg: 'wikieditor-toolbar-tool-replace',
|
|
type: 'button',
|
|
icon: 'search-replace.png',
|
|
offset: [-70, -214],
|
|
action: {
|
|
type: 'dialog',
|
|
module: 'search-and-replace'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} );
|
|
},
|
|
|
|
getDefaultConfig: function () {
|
|
return { 'dialogs': {
|
|
'insert-link': {
|
|
titleMsg: 'wikieditor-toolbar-tool-link-title',
|
|
id: 'wikieditor-toolbar-link-dialog',
|
|
html: '\
|
|
<fieldset>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<label for="wikieditor-toolbar-link-int-target" rel="wikieditor-toolbar-tool-link-int-target" id="wikieditor-toolbar-tool-link-int-target-label"></label>\
|
|
<div id="wikieditor-toolbar-link-int-target-status"></div>\
|
|
<input type="text" id="wikieditor-toolbar-link-int-target"/>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<label for="wikieditor-toolbar-link-int-text" rel="wikieditor-toolbar-tool-link-int-text"></label>\
|
|
<input type="text" id="wikieditor-toolbar-link-int-text"/>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<div class="wikieditor-toolbar-floated-field-wrapper">\
|
|
<input type="radio" id="wikieditor-toolbar-link-type-int" name="wikieditor-toolbar-link-type" selected/>\
|
|
<label for="wikieditor-toolbar-link-type-int" rel="wikieditor-toolbar-tool-link-int"></label>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-floated-field-wrapper">\
|
|
<input type="radio" id="wikieditor-toolbar-link-type-ext" name="wikieditor-toolbar-link-type"/>\
|
|
<label for="wikieditor-toolbar-link-type-ext" rel="wikieditor-toolbar-tool-link-ext"></label>\
|
|
</div>\
|
|
</div>\
|
|
</fieldset>',
|
|
|
|
init: function () {
|
|
function isExternalLink( s ) {
|
|
// The following things are considered to be external links:
|
|
// * Starts a URL protocol
|
|
// * Starts with www.
|
|
// All of these are potentially valid titles, and the latter two categories match about 6300
|
|
// titles in enwiki's ns0. Out of 6.9M titles, that's 0.09%
|
|
if ( typeof arguments.callee.regex === 'undefined' ) {
|
|
// Cache the regex
|
|
arguments.callee.regex =
|
|
new RegExp( "^(" + mw.config.get( 'wgUrlProtocols' ) + "|www\\.)", 'i' );
|
|
}
|
|
return s.match( arguments.callee.regex );
|
|
}
|
|
|
|
// Updates the status indicator above the target link
|
|
function updateWidget( status ) {
|
|
$( '#wikieditor-toolbar-link-int-target-status' ).children().hide();
|
|
$( '#wikieditor-toolbar-link-int-target' ).parent()
|
|
.removeClass(
|
|
'status-invalid status-external status-notexists status-exists status-loading'
|
|
);
|
|
if ( status ) {
|
|
$( '#wikieditor-toolbar-link-int-target-status-' + status ).show();
|
|
$( '#wikieditor-toolbar-link-int-target' ).parent().addClass( 'status-' + status );
|
|
}
|
|
if ( status === 'invalid' ) {
|
|
$( '.ui-dialog:visible .ui-dialog-buttonpane button:first' )
|
|
.attr( 'disabled', true )
|
|
.addClass( 'disabled' );
|
|
} else {
|
|
$( '.ui-dialog:visible .ui-dialog-buttonpane button:first' )
|
|
.removeAttr( 'disabled' )
|
|
.removeClass( 'disabled' );
|
|
}
|
|
}
|
|
|
|
// Updates the UI to show if the page title being inputed by the user exists or not
|
|
// accepts parameter internal for bypassing external link detection
|
|
function updateExistence( internal ) {
|
|
// ensure the internal parameter is a boolean
|
|
if ( internal !== true ) {
|
|
internal = false;
|
|
}
|
|
// Abort previous request
|
|
var request = $( '#wikieditor-toolbar-link-int-target-status' ).data( 'request' );
|
|
if ( request ) {
|
|
request.abort();
|
|
}
|
|
var target = $( '#wikieditor-toolbar-link-int-target' ).val();
|
|
var cache = $( '#wikieditor-toolbar-link-int-target-status' ).data( 'existencecache' );
|
|
if ( hasOwn.call( cache, target ) ) {
|
|
updateWidget( cache[target] );
|
|
return;
|
|
}
|
|
if ( target.replace( /^\s+$/,'' ) === '' ) {
|
|
// Hide the widget when the textbox is empty
|
|
updateWidget( false );
|
|
return;
|
|
}
|
|
// If the forced internal paremter was not true, check if the target is an external link
|
|
if ( !internal && isExternalLink( target ) ) {
|
|
updateWidget( 'external' );
|
|
return;
|
|
}
|
|
if ( target.indexOf( '|' ) !== -1 ) {
|
|
// Title contains | , which means it's invalid
|
|
// but confuses the API. Show invalid and bypass API
|
|
updateWidget( 'invalid' );
|
|
return;
|
|
}
|
|
// Show loading spinner while waiting for the API to respond
|
|
updateWidget( 'loading' );
|
|
// Call the API to check page status, saving the request object so it can be aborted if
|
|
// necessary.
|
|
// This used to request a page that would show whether or not the target exists, but we can
|
|
// also check whether it has the disambiguation property and still get existence information.
|
|
// If the Disambiguator extension is not installed then such a property won't be set.
|
|
$( '#wikieditor-toolbar-link-int-target-status' ).data(
|
|
'request',
|
|
( new mw.Api() ).get( {
|
|
action: 'query',
|
|
prop: 'pageprops',
|
|
titles: target,
|
|
ppprop: 'disambiguation',
|
|
indexpageids: true
|
|
} ).done( function ( data ) {
|
|
var status;
|
|
if ( !data.query || !data.query.pages ) {
|
|
// This happens in some weird cases like interwiki links
|
|
status = false;
|
|
} else {
|
|
var page = data.query.pages[data.query.pageids[0]];
|
|
status = 'exists';
|
|
if ( page.missing !== undefined ) {
|
|
status = 'notexists';
|
|
} else if ( page.invalid !== undefined ) {
|
|
status = 'invalid';
|
|
} else if ( page.pageprops !== undefined ) {
|
|
status = 'disambig';
|
|
}
|
|
}
|
|
// Cache the status of the link target if the force internal
|
|
// parameter was not passed
|
|
if ( !internal ) {
|
|
cache[target] = status;
|
|
}
|
|
updateWidget( status );
|
|
} )
|
|
);
|
|
}
|
|
$( '#wikieditor-toolbar-link-type-int, #wikieditor-toolbar-link-type-ext' ).click( function () {
|
|
if ( $( '#wikieditor-toolbar-link-type-ext' ).prop( 'checked' ) ) {
|
|
// Abort previous request
|
|
var request = $( '#wikieditor-toolbar-link-int-target-status' ).data( 'request' );
|
|
if ( request ) {
|
|
request.abort();
|
|
}
|
|
updateWidget( 'external' );
|
|
}
|
|
if ( $( '#wikieditor-toolbar-link-type-int' ).prop( 'checked' ) ) {
|
|
updateExistence( true );
|
|
}
|
|
} );
|
|
// Set labels of tabs based on rel values
|
|
$( this ).find( '[rel]' ).each( function () {
|
|
$( this ).text( mw.msg( $( this ).attr( 'rel' ) ) );
|
|
} );
|
|
// Set tabindexes on form fields
|
|
$.wikiEditor.modules.dialogs.fn.setTabindexes( $( this ).find( 'input' ).not( '[tabindex]' ) );
|
|
// Setup the tooltips in the textboxes
|
|
$( '#wikieditor-toolbar-link-int-target' )
|
|
.data( 'tooltip', mw.msg( 'wikieditor-toolbar-tool-link-int-target-tooltip' ) );
|
|
$( '#wikieditor-toolbar-link-int-text' )
|
|
.data( 'tooltip', mw.msg( 'wikieditor-toolbar-tool-link-int-text-tooltip' ) );
|
|
$( '#wikieditor-toolbar-link-int-target, #wikieditor-toolbar-link-int-text' )
|
|
.each( function () {
|
|
if ( $( this ).val() === '' ) {
|
|
$( this )
|
|
.addClass( 'wikieditor-toolbar-dialog-hint' )
|
|
.val( $( this ).data( 'tooltip' ) )
|
|
.data( 'tooltip-mode', true );
|
|
}
|
|
} )
|
|
.focus( function () {
|
|
if ( $( this ).val() === $( this ).data( 'tooltip' ) ) {
|
|
$( this )
|
|
.val( '' )
|
|
.removeClass( 'wikieditor-toolbar-dialog-hint' )
|
|
.data( 'tooltip-mode', false );
|
|
}
|
|
} )
|
|
.bind( 'change', function () {
|
|
if ( $( this ).val() !== $( this ).data( 'tooltip' ) ) {
|
|
$( this )
|
|
.removeClass( 'wikieditor-toolbar-dialog-hint' )
|
|
.data( 'tooltip-mode', false );
|
|
}
|
|
} )
|
|
.bind( 'blur', function () {
|
|
if ( $( this ).val() === '' ) {
|
|
$( this )
|
|
.addClass( 'wikieditor-toolbar-dialog-hint' )
|
|
.val( $( this ).data( 'tooltip' ) )
|
|
.data( 'tooltip-mode', true );
|
|
}
|
|
} );
|
|
|
|
// Automatically copy the value of the internal link page title field to the link text field unless the
|
|
// user has changed the link text field - this is a convenience thing since most link texts are going to
|
|
// be the the same as the page title - Also change the internal/external radio button accordingly
|
|
$( '#wikieditor-toolbar-link-int-target' ).bind( 'change keydown paste cut', function () {
|
|
// $( this ).val() is the old value, before the keypress - Defer this until $( this ).val() has
|
|
// been updated
|
|
setTimeout( function () {
|
|
if ( isExternalLink( $( '#wikieditor-toolbar-link-int-target' ).val() ) ) {
|
|
$( '#wikieditor-toolbar-link-type-ext' ).prop( 'checked', true );
|
|
updateWidget( 'external' );
|
|
} else {
|
|
$( '#wikieditor-toolbar-link-type-int' ).prop( 'checked', true );
|
|
updateExistence();
|
|
}
|
|
/*jshint eqeqeq:false */
|
|
if ( $( '#wikieditor-toolbar-link-int-text' ).data( 'untouched' ) ) {
|
|
if ( $( '#wikieditor-toolbar-link-int-target' ).val() ==
|
|
$( '#wikieditor-toolbar-link-int-target' ).data( 'tooltip' )
|
|
) {
|
|
$( '#wikieditor-toolbar-link-int-text' )
|
|
.addClass( 'wikieditor-toolbar-dialog-hint' )
|
|
.val( $( '#wikieditor-toolbar-link-int-text' ).data( 'tooltip' ) )
|
|
.change();
|
|
} else {
|
|
$( '#wikieditor-toolbar-link-int-text' )
|
|
.val( $( '#wikieditor-toolbar-link-int-target' ).val() )
|
|
.change();
|
|
}
|
|
}
|
|
}, 0 );
|
|
} );
|
|
$( '#wikieditor-toolbar-link-int-text' ).bind( 'change keydown paste cut', function () {
|
|
var oldVal = $( this ).val();
|
|
var that = this;
|
|
setTimeout( function () {
|
|
if ( $( that ).val() !== oldVal ) {
|
|
$( that ).data( 'untouched', false );
|
|
}
|
|
}, 0 );
|
|
} );
|
|
// Add images to the page existence widget, which will be shown mutually exclusively to communicate if
|
|
// the page exists, does not exist or the title is invalid (like if it contains a | character)
|
|
var existsMsg = mw.msg( 'wikieditor-toolbar-tool-link-int-target-status-exists' );
|
|
var notexistsMsg = mw.msg( 'wikieditor-toolbar-tool-link-int-target-status-notexists' );
|
|
var invalidMsg = mw.msg( 'wikieditor-toolbar-tool-link-int-target-status-invalid' );
|
|
var externalMsg = mw.msg( 'wikieditor-toolbar-tool-link-int-target-status-external' );
|
|
var loadingMsg = mw.msg( 'wikieditor-toolbar-tool-link-int-target-status-loading' );
|
|
var disambigMsg = mw.msg( 'wikieditor-toolbar-tool-link-int-target-status-disambig' );
|
|
$( '#wikieditor-toolbar-link-int-target-status' )
|
|
.append( $( '<div>' )
|
|
.attr( 'id', 'wikieditor-toolbar-link-int-target-status-exists' )
|
|
.append( existsMsg )
|
|
)
|
|
.append( $( '<div>' )
|
|
.attr( 'id', 'wikieditor-toolbar-link-int-target-status-notexists' )
|
|
.append( notexistsMsg )
|
|
)
|
|
.append( $( '<div>' )
|
|
.attr( 'id', 'wikieditor-toolbar-link-int-target-status-invalid' )
|
|
.append( invalidMsg )
|
|
)
|
|
.append( $( '<div>' )
|
|
.attr( 'id', 'wikieditor-toolbar-link-int-target-status-external' )
|
|
.append( externalMsg )
|
|
)
|
|
.append( $( '<div>' )
|
|
.attr( 'id', 'wikieditor-toolbar-link-int-target-status-loading' )
|
|
.append( $( '<img>' ).attr( {
|
|
'src': $.wikiEditor.imgPath + 'dialogs/' + 'loading-small.gif',
|
|
'alt': loadingMsg,
|
|
'title': loadingMsg
|
|
} ) )
|
|
)
|
|
.append( $( '<div>' )
|
|
.attr( 'id', 'wikieditor-toolbar-link-int-target-status-disambig' )
|
|
.append( disambigMsg )
|
|
)
|
|
.data( 'existencecache', {} )
|
|
.children().hide();
|
|
|
|
$( '#wikieditor-toolbar-link-int-target' )
|
|
.bind( 'keyup paste cut', function () {
|
|
// Cancel the running timer if applicable
|
|
if ( typeof $( this ).data( 'timerID' ) !== 'undefined' ) {
|
|
clearTimeout( $( this ).data( 'timerID' ) );
|
|
}
|
|
// Delay fetch for a while
|
|
// FIXME: Make 120 configurable elsewhere
|
|
var timerID = setTimeout( updateExistence, 120 );
|
|
$( this ).data( 'timerID', timerID );
|
|
} )
|
|
.change( function () {
|
|
// Cancel the running timer if applicable
|
|
if ( typeof $( this ).data( 'timerID' ) !== 'undefined' ) {
|
|
clearTimeout( $( this ).data( 'timerID' ) );
|
|
}
|
|
// Fetch right now
|
|
updateExistence();
|
|
} );
|
|
|
|
// Title suggestions
|
|
$( '#wikieditor-toolbar-link-int-target' ).data( 'suggcache', {} ).suggestions( {
|
|
fetch: function () {
|
|
var that = this;
|
|
var title = $( this ).val();
|
|
|
|
if ( isExternalLink( title ) || title.indexOf( '|' ) !== -1 || title === '' ) {
|
|
$( this ).suggestions( 'suggestions', [] );
|
|
return;
|
|
}
|
|
|
|
var cache = $( this ).data( 'suggcache' );
|
|
if ( hasOwn.call( cache, title ) ) {
|
|
$( this ).suggestions( 'suggestions', cache[title] );
|
|
return;
|
|
}
|
|
|
|
var request = $.ajax( {
|
|
url: mw.util.wikiScript( 'api' ),
|
|
data: {
|
|
action: 'opensearch',
|
|
search: title,
|
|
namespace: 0,
|
|
suggest: '',
|
|
format: 'json'
|
|
},
|
|
dataType: 'json',
|
|
success: function ( data ) {
|
|
cache[title] = data[1];
|
|
$( that ).suggestions( 'suggestions', data[1] );
|
|
}
|
|
} );
|
|
$( this ).data( 'request', request );
|
|
},
|
|
cancel: function () {
|
|
var request = $( this ).data( 'request' );
|
|
if ( request )
|
|
request.abort();
|
|
}
|
|
} );
|
|
},
|
|
dialog: {
|
|
width: 500,
|
|
dialogClass: 'wikiEditor-toolbar-dialog',
|
|
buttons: {
|
|
'wikieditor-toolbar-tool-link-insert': function () {
|
|
function escapeInternalText( s ) {
|
|
return s.replace( /(\]{2,})/g, '<nowiki>$1</nowiki>' );
|
|
}
|
|
function escapeExternalTarget( s ) {
|
|
return s.replace( / /g, '%20' )
|
|
.replace( /\[/g, '%5B' )
|
|
.replace( /\]/g, '%5D' );
|
|
}
|
|
function escapeExternalText( s ) {
|
|
return s.replace( /(\]+)/g, '<nowiki>$1</nowiki>' );
|
|
}
|
|
var insertText = '';
|
|
var whitespace = $( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace' );
|
|
var target = $( '#wikieditor-toolbar-link-int-target' ).val();
|
|
var text = $( '#wikieditor-toolbar-link-int-text' ).val();
|
|
// check if the tooltips were passed as target or text
|
|
if ( $( '#wikieditor-toolbar-link-int-target' ).data( 'tooltip-mode' ) )
|
|
target = "";
|
|
if ( $( '#wikieditor-toolbar-link-int-text' ).data( 'tooltip-mode' ) )
|
|
text = "";
|
|
if ( target === '' ) {
|
|
alert( mw.msg( 'wikieditor-toolbar-tool-link-empty' ) );
|
|
return;
|
|
}
|
|
if ( $.trim( text ) === '' ) {
|
|
// [[Foo| ]] creates an invisible link
|
|
// Instead, generate [[Foo|]]
|
|
text = '';
|
|
}
|
|
if ( $( '#wikieditor-toolbar-link-type-int' ).is( ':checked' ) ) {
|
|
// FIXME: Exactly how fragile is this?
|
|
if ( $( '#wikieditor-toolbar-link-int-target-status-invalid' ).is( ':visible' ) ) {
|
|
// Refuse to add links to invalid titles
|
|
alert( mw.msg( 'wikieditor-toolbar-tool-link-int-invalid' ) );
|
|
return;
|
|
}
|
|
|
|
if ( target === text || !text.length )
|
|
insertText = '[[' + target + ']]';
|
|
else
|
|
insertText = '[[' + target + '|' + escapeInternalText( text ) + ']]';
|
|
} else {
|
|
// Prepend http:// if there is no protocol
|
|
if ( !target.match( /^[a-z]+:\/\/./ ) )
|
|
target = 'http://' + target;
|
|
|
|
// Detect if this is really an internal link in disguise
|
|
var match = target.match( $( this ).data( 'articlePathRegex' ) );
|
|
if ( match && !$( this ).data( 'ignoreLooksInternal' ) ) {
|
|
var buttons = { };
|
|
var that = this;
|
|
buttons[ mw.msg( 'wikieditor-toolbar-tool-link-lookslikeinternal-int' ) ] =
|
|
function () {
|
|
$( '#wikieditor-toolbar-link-int-target' ).val( match[1] ).change();
|
|
$( this ).dialog( 'close' );
|
|
};
|
|
buttons[ mw.msg( 'wikieditor-toolbar-tool-link-lookslikeinternal-ext' ) ] =
|
|
function () {
|
|
$( that ).data( 'ignoreLooksInternal', true );
|
|
$( that ).closest( '.ui-dialog' ).find( 'button:first' ).click();
|
|
$( that ).data( 'ignoreLooksInternal', false );
|
|
$( this ).dialog( 'close' );
|
|
};
|
|
$.wikiEditor.modules.dialogs.quickDialog(
|
|
mw.msg( 'wikieditor-toolbar-tool-link-lookslikeinternal', match[1] ),
|
|
{ buttons: buttons }
|
|
);
|
|
return;
|
|
}
|
|
|
|
var escTarget = escapeExternalTarget( target );
|
|
var escText = escapeExternalText( text );
|
|
|
|
if ( escTarget === escText )
|
|
insertText = escTarget;
|
|
else if ( text === '' )
|
|
insertText = '[' + escTarget + ']';
|
|
else
|
|
insertText = '[' + escTarget + ' ' + escText + ']';
|
|
}
|
|
// Preserve whitespace in selection when replacing
|
|
if ( whitespace ) {
|
|
insertText = whitespace[0] + insertText + whitespace[1];
|
|
}
|
|
$( this ).dialog( 'close' );
|
|
$.wikiEditor.modules.toolbar.fn.doAction( $( this ).data( 'context' ), {
|
|
type: 'replace',
|
|
options: {
|
|
pre: insertText
|
|
}
|
|
}, $( this ) );
|
|
|
|
// Blank form
|
|
$( '#wikieditor-toolbar-link-int-target, #wikieditor-toolbar-link-int-text' ).val( '' );
|
|
$( '#wikieditor-toolbar-link-type-int, #wikieditor-toolbar-link-type-ext' )
|
|
.attr( 'checked', '' );
|
|
},
|
|
'wikieditor-toolbar-tool-link-cancel': function () {
|
|
// Clear any saved selection state
|
|
var context = $( this ).data( 'context' );
|
|
context.fn.restoreCursorAndScrollTop();
|
|
$( this ).dialog( 'close' );
|
|
}
|
|
},
|
|
open: function () {
|
|
var target, text, type, matches;
|
|
|
|
// Obtain the server name without the protocol. wgServer may be protocol-relative
|
|
var serverName = mw.config.get( 'wgServer' ).replace( /^(https?:)?\/\//, '' );
|
|
// Cache the articlepath regex
|
|
$( this ).data( 'articlePathRegex', new RegExp(
|
|
'^https?://' + $.escapeRE( serverName + mw.config.get( 'wgArticlePath' ) )
|
|
.replace( /\\\$1/g, '(.*)' ) + '$'
|
|
) );
|
|
// Pre-fill the text fields based on the current selection
|
|
var context = $( this ).data( 'context' );
|
|
// Restore and immediately save selection state, needed for inserting stuff later
|
|
context.fn.restoreCursorAndScrollTop();
|
|
context.fn.saveCursorAndScrollTop();
|
|
var selection = context.$textarea.textSelection( 'getSelection' );
|
|
$( '#wikieditor-toolbar-link-int-target' ).focus();
|
|
// Trigger the change event, so the link status indicator is up to date
|
|
$( '#wikieditor-toolbar-link-int-target' ).change();
|
|
$( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [ '', '' ] );
|
|
if ( selection !== '' ) {
|
|
if ( ( matches = selection.match( /^(\s*)\[\[([^\]\|]+)(\|([^\]\|]*))?\]\](\s*)$/ ) ) ) {
|
|
// [[foo|bar]] or [[foo]]
|
|
target = matches[2];
|
|
text = ( matches[4] ? matches[4] : matches[2] );
|
|
type = 'int';
|
|
// Preserve whitespace when replacing
|
|
$( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [ matches[1], matches[5] ] );
|
|
} else if ( ( matches = selection.match( /^(\s*)\[([^\] ]+)( ([^\]]+))?\](\s*)$/ ) ) ) {
|
|
// [http://www.example.com foo] or [http://www.example.com]
|
|
target = matches[2];
|
|
text = ( matches[4] || '' );
|
|
type = 'ext';
|
|
// Preserve whitespace when replacing
|
|
$( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [ matches[1], matches[5] ] );
|
|
} else {
|
|
// Trim any leading and trailing whitespace from the selection,
|
|
// but preserve it when replacing
|
|
target = text = $.trim( selection );
|
|
if ( target.length < selection.length ) {
|
|
$( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [
|
|
selection.substr( 0, selection.indexOf( target.charAt( 0 ) ) ),
|
|
selection.substr(
|
|
selection.lastIndexOf( target.charAt( target.length - 1 ) ) + 1
|
|
) ]
|
|
);
|
|
}
|
|
}
|
|
|
|
// Change the value by calling val() doesn't trigger the change event, so let's do that
|
|
// ourselves
|
|
if ( typeof text !== 'undefined' )
|
|
$( '#wikieditor-toolbar-link-int-text' ).val( text ).change();
|
|
if ( typeof target !== 'undefined' )
|
|
$( '#wikieditor-toolbar-link-int-target' ).val( target ).change();
|
|
if ( typeof type !== 'undefined' )
|
|
$( '#wikieditor-toolbar-link-' + type ).prop( 'checked', true );
|
|
}
|
|
$( '#wikieditor-toolbar-link-int-text' ).data( 'untouched',
|
|
$( '#wikieditor-toolbar-link-int-text' ).val() ===
|
|
$( '#wikieditor-toolbar-link-int-target' ).val() ||
|
|
$( '#wikieditor-toolbar-link-int-text' ).hasClass( 'wikieditor-toolbar-dialog-hint' )
|
|
);
|
|
$( '#wikieditor-toolbar-link-int-target' ).suggestions();
|
|
|
|
// don't overwrite user's text
|
|
if ( selection !== '' ){
|
|
$( '#wikieditor-toolbar-link-int-text' ).data( 'untouched', false );
|
|
}
|
|
|
|
$( '#wikieditor-toolbar-link-int-text, #wikiedit-toolbar-link-int-target' )
|
|
.each( function () {
|
|
if ( $( this ).val() === '' )
|
|
$( this ).parent().find( 'label' ).show();
|
|
} );
|
|
|
|
if ( !$( this ).data( 'dialogkeypressset' ) ) {
|
|
$( this ).data( 'dialogkeypressset', true );
|
|
// Execute the action associated with the first button
|
|
// when the user presses Enter
|
|
$( this ).closest( '.ui-dialog' ).keypress( function ( e ) {
|
|
if ( ( e.keyCode || e.which ) === 13 ) {
|
|
var button = $( this ).data( 'dialogaction' ) || $( this ).find( 'button:first' );
|
|
button.click();
|
|
e.preventDefault();
|
|
}
|
|
} );
|
|
|
|
// Make tabbing to a button and pressing
|
|
// Enter do what people expect
|
|
$( this ).closest( '.ui-dialog' ).find( 'button' ).focus( function () {
|
|
$( this ).closest( '.ui-dialog' ).data( 'dialogaction', this );
|
|
} );
|
|
}
|
|
}
|
|
}
|
|
},
|
|
'insert-reference': {
|
|
titleMsg: 'wikieditor-toolbar-tool-reference-title',
|
|
id: 'wikieditor-toolbar-reference-dialog',
|
|
html: '\
|
|
<div class="wikieditor-toolbar-dialog-wrapper">\
|
|
<fieldset><div class="wikieditor-toolbar-table-form">\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<label for="wikieditor-toolbar-reference-text"\
|
|
rel="wikieditor-toolbar-tool-reference-text"></label>\
|
|
<input type="text" id="wikieditor-toolbar-reference-text"/>\
|
|
</div>\
|
|
</div></fieldset>\
|
|
</div>',
|
|
init: function () {
|
|
// Insert translated strings into labels
|
|
$( this ).find( '[rel]' ).each( function () {
|
|
$( this ).text( mw.msg( $( this ).attr( 'rel' ) ) );
|
|
} );
|
|
|
|
},
|
|
dialog: {
|
|
dialogClass: 'wikiEditor-toolbar-dialog',
|
|
width: 590,
|
|
buttons: {
|
|
'wikieditor-toolbar-tool-reference-insert': function () {
|
|
var insertText = $( '#wikieditor-toolbar-reference-text' ).val();
|
|
var whitespace = $( '#wikieditor-toolbar-reference-dialog' ).data( 'whitespace' );
|
|
var attributes = $( '#wikieditor-toolbar-reference-dialog' ).data( 'attributes' );
|
|
// Close the dialog
|
|
$( this ).dialog( 'close' );
|
|
$.wikiEditor.modules.toolbar.fn.doAction(
|
|
$( this ).data( 'context' ),
|
|
{
|
|
type: 'replace',
|
|
options: {
|
|
pre: whitespace[0] + '<ref' + attributes + '>',
|
|
peri: insertText,
|
|
post: '</ref>' + whitespace[1]
|
|
}
|
|
},
|
|
$( this )
|
|
);
|
|
// Restore form state
|
|
$( '#wikieditor-toolbar-reference-text' ).val( '' );
|
|
},
|
|
'wikieditor-toolbar-tool-reference-cancel': function () {
|
|
// Clear any saved selection state
|
|
var context = $( this ).data( 'context' );
|
|
context.fn.restoreCursorAndScrollTop();
|
|
$( this ).dialog( 'close' );
|
|
}
|
|
},
|
|
open: function () {
|
|
// Pre-fill the text fields based on the current selection
|
|
var context = $( this ).data( 'context' );
|
|
// Restore and immediately save selection state, needed for inserting stuff later
|
|
context.fn.restoreCursorAndScrollTop();
|
|
context.fn.saveCursorAndScrollTop();
|
|
var selection = context.$textarea.textSelection( 'getSelection' );
|
|
// set focus
|
|
$( '#wikieditor-toolbar-reference-text' ).focus();
|
|
$( '#wikieditor-toolbar-reference-dialog' )
|
|
.data( 'whitespace', [ '', '' ] )
|
|
.data( 'attributes', '' );
|
|
if ( selection !== '' ) {
|
|
var matches, text;
|
|
if ( ( matches = selection.match( /^(\s*)<ref([^\>]*)>([^<]*)<\/ref\>(\s*)$/ ) ) ) {
|
|
text = matches[3];
|
|
// Preserve whitespace when replacing
|
|
$( '#wikieditor-toolbar-reference-dialog' )
|
|
.data( 'whitespace', [ matches[1], matches[4] ] );
|
|
$( '#wikieditor-toolbar-reference-dialog' ).data( 'attributes', matches[2] );
|
|
} else {
|
|
text = selection;
|
|
}
|
|
$( '#wikieditor-toolbar-reference-text' ).val( text );
|
|
}
|
|
if ( !( $( this ).data( 'dialogkeypressset' ) ) ) {
|
|
$( this ).data( 'dialogkeypressset', true );
|
|
// Execute the action associated with the first button
|
|
// when the user presses Enter
|
|
$( this ).closest( '.ui-dialog' ).keypress( function ( e ) {
|
|
if ( ( e.keyCode || e.which ) === 13 ) {
|
|
var button = $( this ).data( 'dialogaction' ) || $( this ).find( 'button:first' );
|
|
button.click();
|
|
e.preventDefault();
|
|
}
|
|
} );
|
|
// Make tabbing to a button and pressing
|
|
// Enter do what people expect
|
|
$( this ).closest( '.ui-dialog' ).find( 'button' ).focus( function () {
|
|
$( this ).closest( '.ui-dialog' ).data( 'dialogaction', this );
|
|
} );
|
|
}
|
|
}
|
|
}
|
|
},
|
|
'insert-file': {
|
|
titleMsg: 'wikieditor-toolbar-tool-file-title',
|
|
id: 'wikieditor-toolbar-file-dialog',
|
|
html: '\
|
|
<fieldset>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<label for="wikieditor-toolbar-file-target" rel="wikieditor-toolbar-file-target" id="wikieditor-toolbar-tool-file-target-label"></label>\
|
|
<input type="text" id="wikieditor-toolbar-file-target"/>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<label for="wikieditor-toolbar-file-caption" rel="wikieditor-toolbar-file-caption"></label>\
|
|
<input type="text" id="wikieditor-toolbar-file-caption"/>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-file-options">\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<label for="wikieditor-toolbar-file-size" rel="wikieditor-toolbar-file-size"></label><br/>\
|
|
<input type="text" id="wikieditor-toolbar-file-size" size="5"/>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<label for="wikieditor-toolbar-file-float" rel="wikieditor-toolbar-file-float"></label><br/>\
|
|
<select type="text" id="wikieditor-toolbar-file-float">\
|
|
<option value="default" selected="selected" rel="wikieditor-toolbar-file-default"></option>\
|
|
<option data-i18n-magic="img_none"></option>\
|
|
<option data-i18n-magic="img_center"></option>\
|
|
<option data-i18n-magic="img_left"></option>\
|
|
<option data-i18n-magic="img_right"></option>\
|
|
</select>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<label for="wikieditor-toolbar-file-format" rel="wikieditor-toolbar-file-format"></label><br/>\
|
|
<select type="text" id="wikieditor-toolbar-file-format">\
|
|
<option selected="selected" data-i18n-magic="img_thumbnail">thumb</option>\
|
|
<option data-i18n-magic="img_framed"></option>\
|
|
<option data-i18n-magic="img_frameless"></option>\
|
|
<option value="default" rel="wikieditor-toolbar-file-format-none"></option>\
|
|
</select>\
|
|
</div>\
|
|
</div>\
|
|
</fieldset>',
|
|
init: function () {
|
|
var magicWordsI18N = mw.config.get( 'wgWikiEditorMagicWords' );
|
|
var defaultMsg = mw.msg( 'wikieditor-toolbar-file-default' );
|
|
$( this )
|
|
.find( '[data-i18n-magic]' )
|
|
.text( function () {
|
|
return magicWordsI18N[ $( this ).attr( 'data-i18n-magic' ) ];
|
|
} )
|
|
.removeAttr( 'data-i18n-magic' )
|
|
.end()
|
|
.find( '#wikieditor-toolbar-file-size' )
|
|
.attr( 'placeholder', defaultMsg )
|
|
// The message may be long in some languages
|
|
.attr( 'size', defaultMsg.length )
|
|
.end()
|
|
.find( '[rel]' )
|
|
.text( function () {
|
|
return mw.msg( $( this ).attr( 'rel' ) );
|
|
} )
|
|
.removeAttr( 'rel' )
|
|
.end();
|
|
},
|
|
dialog: {
|
|
resizable: false,
|
|
dialogClass: 'wikiEditor-toolbar-dialog',
|
|
width: 590,
|
|
buttons: {
|
|
'wikieditor-toolbar-tool-file-insert': function () {
|
|
var fileName, caption, fileFloat, fileFormat, fileSize, fileTitle,
|
|
options, fileUse,
|
|
hasPxRgx = /.+px$/;
|
|
fileName = $( '#wikieditor-toolbar-file-target' ).val();
|
|
caption = $( '#wikieditor-toolbar-file-caption' ).val();
|
|
fileFloat = $( '#wikieditor-toolbar-file-float' ).val();
|
|
fileFormat = $( '#wikieditor-toolbar-file-format' ).val();
|
|
fileSize = $( '#wikieditor-toolbar-file-size' ).val();
|
|
// Append px to end to size if not already contains it
|
|
if ( fileSize !== '' && !hasPxRgx.test( fileSize ) ) {
|
|
fileSize += 'px';
|
|
}
|
|
if ( fileName !== '' ) {
|
|
fileTitle = new mw.Title( fileName );
|
|
// Append file namespace prefix to filename if not already contains it
|
|
if ( fileTitle.getNamespaceId() !== 6 ){
|
|
fileTitle = new mw.Title( fileName, 6 );
|
|
}
|
|
fileName = fileTitle.toText();
|
|
}
|
|
options = [ fileSize, fileFormat, fileFloat ];
|
|
// Filter empty values
|
|
options = $.grep( options, function ( val ) {
|
|
return val.length && val !== 'default';
|
|
} );
|
|
if ( caption.length ) {
|
|
options.push( caption );
|
|
}
|
|
fileUse = options.length === 0 ? fileName : ( fileName + '|' + options.join( '|' ) );
|
|
$( this ).dialog( 'close' );
|
|
$.wikiEditor.modules.toolbar.fn.doAction(
|
|
$( this ).data( 'context' ),
|
|
{
|
|
type: 'replace',
|
|
options: {
|
|
pre: '[[',
|
|
peri: fileUse,
|
|
post: ']]',
|
|
ownline: true
|
|
}
|
|
},
|
|
$( this )
|
|
);
|
|
|
|
// Restore form state
|
|
$( ['#wikieditor-toolbar-file-target',
|
|
'#wikieditor-toolbar-file-caption',
|
|
'#wikieditor-toolbar-file-size',
|
|
'#wikieditor-toolbar-file-float',
|
|
'#wikieditor-toolbar-file-format'].join( ',' )
|
|
).val( '' );
|
|
},
|
|
'wikieditor-toolbar-tool-file-cancel': function () {
|
|
$( this ).dialog( 'close' );
|
|
}
|
|
},
|
|
open: function () {
|
|
$( '#wikieditor-toolbar-file-target' ).focus();
|
|
if ( !( $( this ).data( 'dialogkeypressset' ) ) ) {
|
|
$( this ).data( 'dialogkeypressset', true );
|
|
// Execute the action associated with the first button
|
|
// when the user presses Enter
|
|
$( this ).closest( '.ui-dialog' ).keypress( function ( e ) {
|
|
if ( e.which === 13 ) {
|
|
var button = $( this ).data( 'dialogaction' ) ||
|
|
$( this ).find( 'button:first' );
|
|
button.click();
|
|
e.preventDefault();
|
|
}
|
|
} );
|
|
|
|
// Make tabbing to a button and pressing
|
|
// Enter do what people expect
|
|
$( this ).closest( '.ui-dialog' ).find( 'button' ).focus( function () {
|
|
$( this ).closest( '.ui-dialog' ).data( 'dialogaction', this );
|
|
} );
|
|
}
|
|
}
|
|
}
|
|
},
|
|
'insert-table': {
|
|
titleMsg: 'wikieditor-toolbar-tool-table-title',
|
|
id: 'wikieditor-toolbar-table-dialog',
|
|
// FIXME: Localize 'x'?
|
|
html: '\
|
|
<div class="wikieditor-toolbar-dialog-wrapper">\
|
|
<fieldset><div class="wikieditor-toolbar-table-form">\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<input type="checkbox" id="wikieditor-toolbar-table-dimensions-header" checked/>\
|
|
<label for="wikieditor-toolbar-table-dimensions-header"\
|
|
rel="wikieditor-toolbar-tool-table-dimensions-header"></label>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<input type="checkbox" id="wikieditor-toolbar-table-wikitable" checked/>\
|
|
<label for="wikieditor-toolbar-table-wikitable" rel="wikieditor-toolbar-tool-table-wikitable"></label>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<input type="checkbox" id="wikieditor-toolbar-table-sortable"/>\
|
|
<label for="wikieditor-toolbar-table-sortable" rel="wikieditor-toolbar-tool-table-sortable"></label>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-table-dimension-fields">\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<label for="wikieditor-toolbar-table-dimensions-rows"\
|
|
rel="wikieditor-toolbar-tool-table-dimensions-rows"></label><br/>\
|
|
<input type="number" min="1" max="1000" id="wikieditor-toolbar-table-dimensions-rows" size="4"/>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<label for="wikieditor-toolbar-table-dimensions-columns"\
|
|
rel="wikieditor-toolbar-tool-table-dimensions-columns"></label><br/>\
|
|
<input type="number" min="1" max="1000" id="wikieditor-toolbar-table-dimensions-columns" size="4"/>\
|
|
</div>\
|
|
</div>\
|
|
</div></fieldset>\
|
|
<div class="wikieditor-toolbar-table-preview-wrapper" >\
|
|
<span rel="wikieditor-toolbar-tool-table-example"></span>\
|
|
<div class="wikieditor-toolbar-table-preview-content">\
|
|
<table id="wikieditor-toolbar-table-preview" class="wikieditor-toolbar-table-preview wikitable">\
|
|
<thead>\
|
|
<tr class="wikieditor-toolbar-table-preview-header">\
|
|
<th rel="wikieditor-toolbar-tool-table-example-header"></th>\
|
|
<th rel="wikieditor-toolbar-tool-table-example-header"></th>\
|
|
<th rel="wikieditor-toolbar-tool-table-example-header"></th>\
|
|
</tr>\
|
|
</thead><tbody>\
|
|
<tr class="wikieditor-toolbar-table-preview-hidden" style="display: none;">\
|
|
<td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
|
|
<td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
|
|
<td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
|
|
</tr><tr>\
|
|
<td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
|
|
<td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
|
|
<td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
|
|
</tr><tr>\
|
|
<td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
|
|
<td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
|
|
<td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
|
|
</tr><tr>\
|
|
<td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
|
|
<td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
|
|
<td rel="wikieditor-toolbar-tool-table-example-cell-text"></td>\
|
|
</tr>\
|
|
</tbody>\
|
|
</table>\
|
|
</div>\
|
|
</div></div>',
|
|
init: function () {
|
|
$( this ).find( '[rel]' ).each( function () {
|
|
$( this ).text( mw.msg( $( this ).attr( 'rel' ) ) );
|
|
} );
|
|
// Set tabindexes on form fields
|
|
$.wikiEditor.modules.dialogs.fn.setTabindexes( $( this ).find( 'input' ).not( '[tabindex]' ) );
|
|
|
|
$( '#wikieditor-toolbar-table-dimensions-rows' ).val( 3 );
|
|
$( '#wikieditor-toolbar-table-dimensions-columns' ).val( 3 );
|
|
$( '#wikieditor-toolbar-table-wikitable' ).click( function () {
|
|
$( '.wikieditor-toolbar-table-preview' ).toggleClass( 'wikitable' );
|
|
} );
|
|
|
|
// Hack for sortable preview: dynamically adding
|
|
// sortable class doesn't work, so we use a clone
|
|
$( '#wikieditor-toolbar-table-preview' )
|
|
.clone()
|
|
.attr( 'id', 'wikieditor-toolbar-table-preview2' )
|
|
.addClass( 'sortable' )
|
|
.insertAfter( $( '#wikieditor-toolbar-table-preview' ) )
|
|
.hide();
|
|
|
|
mw.loader.using( 'jquery.tablesorter', function () {
|
|
$( '#wikieditor-toolbar-table-preview2' ).tablesorter();
|
|
} );
|
|
|
|
$( '#wikieditor-toolbar-table-sortable' ).click( function () {
|
|
// Swap the currently shown one clone with the other one
|
|
$( '#wikieditor-toolbar-table-preview' )
|
|
.hide()
|
|
.attr( 'id', 'wikieditor-toolbar-table-preview3' );
|
|
$( '#wikieditor-toolbar-table-preview2' )
|
|
.attr( 'id', 'wikieditor-toolbar-table-preview' )
|
|
.show();
|
|
$( '#wikieditor-toolbar-table-preview3' ).attr( 'id', 'wikieditor-toolbar-table-preview2' );
|
|
} );
|
|
|
|
$( '#wikieditor-toolbar-table-dimensions-header' ).click( function () {
|
|
// Instead of show/hiding, switch the HTML around
|
|
// We do this because the sortable tables script styles the first row,
|
|
// visible or not
|
|
var headerHTML = $( '.wikieditor-toolbar-table-preview-header' ).html();
|
|
var hiddenHTML = $( '.wikieditor-toolbar-table-preview-hidden' ).html();
|
|
$( '.wikieditor-toolbar-table-preview-header' ).html( hiddenHTML );
|
|
$( '.wikieditor-toolbar-table-preview-hidden' ).html( headerHTML );
|
|
if ( typeof jQuery.fn.tablesorter === 'function' ) {
|
|
$( '#wikieditor-toolbar-table-preview, #wikieditor-toolbar-table-preview2' )
|
|
.filter( '.sortable' )
|
|
.tablesorter();
|
|
}
|
|
} );
|
|
},
|
|
dialog: {
|
|
resizable: false,
|
|
dialogClass: 'wikiEditor-toolbar-dialog',
|
|
width: 590,
|
|
buttons: {
|
|
'wikieditor-toolbar-tool-table-insert': function () {
|
|
var rowsVal = $( '#wikieditor-toolbar-table-dimensions-rows' ).val();
|
|
var colsVal = $( '#wikieditor-toolbar-table-dimensions-columns' ).val();
|
|
var rows = parseInt( rowsVal, 10 );
|
|
var cols = parseInt( colsVal, 10 );
|
|
var header = $( '#wikieditor-toolbar-table-dimensions-header' ).prop( 'checked' ) ? 1 : 0;
|
|
if ( isNaN( rows ) || isNaN( cols ) || String( rows ) !== rowsVal || String( cols ) !== colsVal || rowsVal < 0 || colsVal < 0 ) {
|
|
alert( mw.msg( 'wikieditor-toolbar-tool-table-invalidnumber' ) );
|
|
return;
|
|
}
|
|
if ( rows + header === 0 || cols === 0 ) {
|
|
alert( mw.msg( 'wikieditor-toolbar-tool-table-zero' ) );
|
|
return;
|
|
}
|
|
if ( ( rows * cols ) > 1000 ) {
|
|
// 1000 is in the English message. The parameter replacement is kept for BC.
|
|
alert( mw.msg( 'wikieditor-toolbar-tool-table-toomany', 1000 ) );
|
|
return;
|
|
}
|
|
var headerText = mw.msg( 'wikieditor-toolbar-tool-table-example-header' );
|
|
var normalText = mw.msg( 'wikieditor-toolbar-tool-table-example' );
|
|
var table = "";
|
|
for ( var r = 0; r < rows + header; r++ ) {
|
|
table += "|-\n";
|
|
for ( var c = 0; c < cols; c++ ) {
|
|
var isHeader = ( header && r === 0 );
|
|
var delim = isHeader ? '!' : '|';
|
|
if ( c > 0 ) {
|
|
delim += delim;
|
|
}
|
|
table += delim + ' ' + ( isHeader ? headerText : normalText ) + ' ';
|
|
}
|
|
// Replace trailing space by newline
|
|
// table[table.length - 1] is read-only
|
|
table = table.substr( 0, table.length - 1 ) + "\n";
|
|
}
|
|
var classes = [];
|
|
if ( $( '#wikieditor-toolbar-table-wikitable' ).is( ':checked' ) )
|
|
classes.push( 'wikitable' );
|
|
if ( $( '#wikieditor-toolbar-table-sortable' ).is( ':checked' ) )
|
|
classes.push( 'sortable' );
|
|
var classStr = classes.length > 0 ? ' class="' + classes.join( ' ' ) + '"' : '';
|
|
$( this ).dialog( 'close' );
|
|
$.wikiEditor.modules.toolbar.fn.doAction(
|
|
$( this ).data( 'context' ),
|
|
{
|
|
type: 'replace',
|
|
options: {
|
|
pre: '{|' + classStr + "\n",
|
|
peri: table,
|
|
post: '|}',
|
|
ownline: true
|
|
}
|
|
},
|
|
$( this )
|
|
);
|
|
|
|
// Restore form state
|
|
$( '#wikieditor-toolbar-table-dimensions-rows' ).val( 3 );
|
|
$( '#wikieditor-toolbar-table-dimensions-columns' ).val( 3 );
|
|
// Simulate clicks instead of setting values, so the according
|
|
// actions are performed
|
|
if ( !$( '#wikieditor-toolbar-table-dimensions-header' ).is( ':checked' ) )
|
|
$( '#wikieditor-toolbar-table-dimensions-header' ).click();
|
|
if ( !$( '#wikieditor-toolbar-table-wikitable' ).is( ':checked' ) )
|
|
$( '#wikieditor-toolbar-table-wikitable' ).click();
|
|
if ( $( '#wikieditor-toolbar-table-sortable' ).is( ':checked' ) )
|
|
$( '#wikieditor-toolbar-table-sortable' ).click();
|
|
},
|
|
'wikieditor-toolbar-tool-table-cancel': function () {
|
|
$( this ).dialog( 'close' );
|
|
}
|
|
},
|
|
open: function () {
|
|
$( '#wikieditor-toolbar-table-dimensions-rows' ).focus();
|
|
if ( !( $( this ).data( 'dialogkeypressset' ) ) ) {
|
|
$( this ).data( 'dialogkeypressset', true );
|
|
// Execute the action associated with the first button
|
|
// when the user presses Enter
|
|
$( this ).closest( '.ui-dialog' ).keypress( function ( e ) {
|
|
if ( ( e.keyCode || e.which ) === 13 ) {
|
|
var button = $( this ).data( 'dialogaction' ) || $( this ).find( 'button:first' );
|
|
button.click();
|
|
e.preventDefault();
|
|
}
|
|
} );
|
|
|
|
// Make tabbing to a button and pressing
|
|
// Enter do what people expect
|
|
$( this ).closest( '.ui-dialog' ).find( 'button' ).focus( function () {
|
|
$( this ).closest( '.ui-dialog' ).data( 'dialogaction', this );
|
|
} );
|
|
}
|
|
}
|
|
}
|
|
},
|
|
'search-and-replace': {
|
|
'browsers': {
|
|
// Left-to-right languages
|
|
'ltr': {
|
|
'msie': false,
|
|
'firefox': [['>=', 2]],
|
|
'opera': false,
|
|
'safari': [['>=', 3]],
|
|
'chrome': [['>=', 3]]
|
|
},
|
|
// Right-to-left languages
|
|
'rtl': {
|
|
'msie': false,
|
|
'firefox': [['>=', 2]],
|
|
'opera': false,
|
|
'safari': [['>=', 3]],
|
|
'chrome': [['>=', 3]]
|
|
}
|
|
},
|
|
titleMsg: 'wikieditor-toolbar-tool-replace-title',
|
|
id: 'wikieditor-toolbar-replace-dialog',
|
|
html: '\
|
|
<div id="wikieditor-toolbar-replace-message">\
|
|
<div id="wikieditor-toolbar-replace-nomatch" rel="wikieditor-toolbar-tool-replace-nomatch"></div>\
|
|
<div id="wikieditor-toolbar-replace-success"></div>\
|
|
<div id="wikieditor-toolbar-replace-emptysearch" rel="wikieditor-toolbar-tool-replace-emptysearch"></div>\
|
|
<div id="wikieditor-toolbar-replace-invalidregex"></div>\
|
|
</div>\
|
|
<fieldset>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<label for="wikieditor-toolbar-replace-search" rel="wikieditor-toolbar-tool-replace-search"></label>\
|
|
<input type="text" id="wikieditor-toolbar-replace-search" style="width: 100%;"/>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<label for="wikieditor-toolbar-replace-replace" rel="wikieditor-toolbar-tool-replace-replace"></label>\
|
|
<input type="text" id="wikieditor-toolbar-replace-replace" style="width: 100%;"/>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<input type="checkbox" id="wikieditor-toolbar-replace-case"/>\
|
|
<label for="wikieditor-toolbar-replace-case" rel="wikieditor-toolbar-tool-replace-case"></label>\
|
|
</div>\
|
|
<div class="wikieditor-toolbar-field-wrapper">\
|
|
<input type="checkbox" id="wikieditor-toolbar-replace-regex"/>\
|
|
<label for="wikieditor-toolbar-replace-regex" rel="wikieditor-toolbar-tool-replace-regex"></label>\
|
|
</div>\
|
|
</fieldset>',
|
|
init: function () {
|
|
$( this ).find( '[rel]' ).each( function () {
|
|
$( this ).text( mw.msg( $( this ).attr( 'rel' ) ) );
|
|
} );
|
|
// Set tabindexes on form fields
|
|
$.wikiEditor.modules.dialogs.fn.setTabindexes( $( this ).find( 'input' ).not( '[tabindex]' ) );
|
|
|
|
// TODO: Find a cleaner way to share this function
|
|
$( this ).data( 'replaceCallback', function ( mode ) {
|
|
var offset, textRemainder, regex, index, i,
|
|
start, end;
|
|
|
|
$( '#wikieditor-toolbar-replace-nomatch, #wikieditor-toolbar-replace-success, #wikieditor-toolbar-replace-emptysearch, #wikieditor-toolbar-replace-invalidregex' ).hide();
|
|
|
|
// Search string cannot be empty
|
|
var searchStr = $( '#wikieditor-toolbar-replace-search' ).val();
|
|
if ( searchStr === '' ) {
|
|
$( '#wikieditor-toolbar-replace-emptysearch' ).show();
|
|
return;
|
|
}
|
|
|
|
// Replace string can be empty
|
|
var replaceStr = $( '#wikieditor-toolbar-replace-replace' ).val();
|
|
|
|
// Prepare the regular expression flags
|
|
var flags = 'm';
|
|
var matchCase = $( '#wikieditor-toolbar-replace-case' ).is( ':checked' );
|
|
if ( !matchCase ) {
|
|
flags += 'i';
|
|
}
|
|
var isRegex = $( '#wikieditor-toolbar-replace-regex' ).is( ':checked' );
|
|
if ( !isRegex ) {
|
|
searchStr = $.escapeRE( searchStr );
|
|
}
|
|
if ( mode === 'replaceAll' ) {
|
|
flags += 'g';
|
|
}
|
|
|
|
try {
|
|
regex = new RegExp( searchStr, flags );
|
|
} catch ( e ) {
|
|
$( '#wikieditor-toolbar-replace-invalidregex' )
|
|
.text( mw.msg( 'wikieditor-toolbar-tool-replace-invalidregex',
|
|
e.message ) )
|
|
.show();
|
|
return;
|
|
}
|
|
|
|
var $textarea = $( this ).data( 'context' ).$textarea;
|
|
var text = $textarea.textSelection( 'getContents' );
|
|
var match = false;
|
|
if ( mode !== 'replaceAll' ) {
|
|
if ( mode === 'replace' ) {
|
|
offset = $( this ).data( 'matchIndex' );
|
|
} else {
|
|
offset = $( this ).data( 'offset' );
|
|
}
|
|
textRemainder = text.substr( offset );
|
|
match = textRemainder.match( regex );
|
|
}
|
|
if ( !match ) {
|
|
// Search hit BOTTOM, continuing at TOP
|
|
// TODO: Add a "Wrap around" option.
|
|
offset = 0;
|
|
textRemainder = text;
|
|
match = textRemainder.match( regex );
|
|
}
|
|
|
|
if ( !match ) {
|
|
$( '#wikieditor-toolbar-replace-nomatch' ).show();
|
|
} else if ( mode === 'replaceAll' ) {
|
|
// Instead of using repetitive .match() calls, we use one .match() call with /g
|
|
// and indexOf() followed by substr() to find the offsets. This is actually
|
|
// faster because our indexOf+substr loop is faster than a match loop, and the
|
|
// /g match is so ridiculously fast that it's negligible.
|
|
// FIXME: Repetitively calling encapsulateSelection() is probably the best strategy
|
|
// in Firefox/Webkit, but in IE replacing the entire content once is better.
|
|
for ( i = 0; i < match.length; i++ ) {
|
|
index = textRemainder.indexOf( match[i] );
|
|
if ( index === -1 ) {
|
|
// This shouldn't happen
|
|
break;
|
|
}
|
|
var matchedText = textRemainder.substr( index, match[i].length );
|
|
textRemainder = textRemainder.substr( index + match[i].length );
|
|
|
|
start = index + offset;
|
|
end = start + match[i].length;
|
|
// Make regex placeholder substitution ($1) work
|
|
var replace = isRegex ? matchedText.replace( regex, replaceStr ) : replaceStr;
|
|
var newEnd = start + replace.length;
|
|
$textarea
|
|
.textSelection( 'setSelection', { 'start': start, 'end': end } )
|
|
.textSelection( 'encapsulateSelection', {
|
|
'peri': replace,
|
|
'replace': true } )
|
|
.textSelection( 'setSelection', { 'start': start, 'end': newEnd } );
|
|
offset = newEnd;
|
|
}
|
|
$( '#wikieditor-toolbar-replace-success' )
|
|
.text( mw.msg( 'wikieditor-toolbar-tool-replace-success', match.length ) )
|
|
.show();
|
|
$( this ).data( 'offset', 0 );
|
|
} else {
|
|
|
|
if ( mode === 'replace' ) {
|
|
var actualReplacement;
|
|
|
|
if ( isRegex ) {
|
|
// If backreferences (like $1) are used, the actual actual replacement string will be different
|
|
actualReplacement = match[0].replace( regex, replaceStr );
|
|
} else {
|
|
actualReplacement = replaceStr;
|
|
}
|
|
|
|
if ( match ) {
|
|
// Do the replacement
|
|
$textarea.textSelection( 'encapsulateSelection', {
|
|
'peri': actualReplacement,
|
|
'replace': true } );
|
|
// Reload the text after replacement
|
|
text = $textarea.textSelection( 'getContents' );
|
|
}
|
|
|
|
// Find the next instance
|
|
offset = offset + match[0].length + actualReplacement.length;
|
|
textRemainder = text.substr( offset );
|
|
match = textRemainder.match( regex );
|
|
|
|
if ( match ) {
|
|
start = offset + match.index;
|
|
end = start + match[0].length;
|
|
} else {
|
|
// If no new string was found, try searching from the beginning.
|
|
// TODO: Add a "Wrap around" option.
|
|
textRemainder = text;
|
|
match = textRemainder.match( regex );
|
|
if ( match ) {
|
|
start = match.index;
|
|
end = start + match[0].length;
|
|
} else {
|
|
// Give up
|
|
start = 0;
|
|
end = 0;
|
|
}
|
|
}
|
|
} else {
|
|
start = offset + match.index;
|
|
end = start + match[0].length;
|
|
}
|
|
|
|
$( this ).data( 'matchIndex', start );
|
|
|
|
$textarea.textSelection( 'setSelection', {
|
|
'start': start,
|
|
'end': end
|
|
} );
|
|
$textarea.textSelection( 'scrollToCaretPosition' );
|
|
$( this ).data( 'offset', end );
|
|
$textarea[0].focus();
|
|
}
|
|
} );
|
|
},
|
|
dialog: {
|
|
width: 500,
|
|
dialogClass: 'wikiEditor-toolbar-dialog',
|
|
modal: false,
|
|
buttons: {
|
|
'wikieditor-toolbar-tool-replace-button-findnext': function ( e ) {
|
|
$( this ).closest( '.ui-dialog' ).data( 'dialogaction', e.target );
|
|
$( this ).data( 'replaceCallback' ).call( this, 'find' );
|
|
},
|
|
'wikieditor-toolbar-tool-replace-button-replace': function ( e ) {
|
|
$( this ).closest( '.ui-dialog' ).data( 'dialogaction', e.target );
|
|
$( this ).data( 'replaceCallback' ).call( this, 'replace' );
|
|
},
|
|
'wikieditor-toolbar-tool-replace-button-replaceall': function ( e ) {
|
|
$( this ).closest( '.ui-dialog' ).data( 'dialogaction', e.target );
|
|
$( this ).data( 'replaceCallback' ).call( this, 'replaceAll' );
|
|
},
|
|
'wikieditor-toolbar-tool-replace-close': function () {
|
|
$( this ).dialog( 'close' );
|
|
}
|
|
},
|
|
open: function () {
|
|
$( this ).data( 'offset', 0 );
|
|
$( this ).data( 'matchIndex', 0 );
|
|
|
|
$( '#wikieditor-toolbar-replace-search' ).focus();
|
|
$( '#wikieditor-toolbar-replace-nomatch, #wikieditor-toolbar-replace-success, #wikieditor-toolbar-replace-emptysearch, #wikieditor-toolbar-replace-invalidregex' ).hide();
|
|
if ( !( $( this ).data( 'onetimeonlystuff' ) ) ) {
|
|
$( this ).data( 'onetimeonlystuff', true );
|
|
// Execute the action associated with the first button
|
|
// when the user presses Enter
|
|
$( this ).closest( '.ui-dialog' ).keypress( function ( e ) {
|
|
if ( ( e.keyCode || e.which ) === 13 ) {
|
|
var button = $( this ).data( 'dialogaction' ) || $( this ).find( 'button:first' );
|
|
button.click();
|
|
e.preventDefault();
|
|
}
|
|
} );
|
|
// Make tabbing to a button and pressing
|
|
// Enter do what people expect
|
|
$( this ).closest( '.ui-dialog' ).find( 'button' ).focus( function () {
|
|
$( this ).closest( '.ui-dialog' ).data( 'dialogaction', this );
|
|
} );
|
|
}
|
|
var dialog = $( this ).closest( '.ui-dialog' );
|
|
var that = this;
|
|
var context = $( this ).data( 'context' );
|
|
var textbox = context.$textarea;
|
|
|
|
$( textbox )
|
|
.bind( 'keypress.srdialog', function ( e ) {
|
|
if ( e.which === 13 ) {
|
|
// Enter
|
|
var button = dialog.data( 'dialogaction' ) || dialog.find( 'button:first' );
|
|
button.click();
|
|
e.preventDefault();
|
|
} else if ( e.which === 27 ) {
|
|
// Escape
|
|
$( that ).dialog( 'close' );
|
|
}
|
|
} );
|
|
},
|
|
close: function () {
|
|
var context = $( this ).data( 'context' );
|
|
var textbox = context.$textarea;
|
|
$( textbox ).unbind( 'keypress.srdialog' );
|
|
$( this ).closest( '.ui-dialog' ).data( 'dialogaction', false );
|
|
}
|
|
}
|
|
}
|
|
} };
|
|
}
|
|
|
|
};
|
|
|
|
}( jQuery, mediaWiki ) );
|