build: Test JS code with jshint and jscs via npm

Change-Id: I039bc4c17fbba3c74a5050066b20af05434ca482
This commit is contained in:
paladox 2015-11-15 14:30:18 +00:00
parent f3f4dbe888
commit bdb67f719c
13 changed files with 2359 additions and 2289 deletions

7
.jscsrc Normal file
View file

@ -0,0 +1,7 @@
{
"preset": "wikimedia",
"validateQuoteMarks": null,
"requireVarDeclFirst": null,
"requireMultipleVarDecl": null,
"requireCamelCaseOrUpperCaseIdentifiers": null
}

2
.jshintignore Normal file
View file

@ -0,0 +1,2 @@
node_modules
vendor

View file

@ -1,10 +1,24 @@
/*jshint node:true */
module.exports = function ( grunt ) {
grunt.loadNpmTasks( 'grunt-banana-checker' );
grunt.loadNpmTasks( 'grunt-jsonlint' );
var conf = grunt.file.readJSON( 'extension.json' );
grunt.loadNpmTasks( 'grunt-contrib-jshint' );
grunt.loadNpmTasks( 'grunt-jsonlint' );
grunt.loadNpmTasks( 'grunt-banana-checker' );
grunt.loadNpmTasks( 'grunt-jscs' );
grunt.initConfig( {
jshint: {
options: {
jshintrc: true
},
all: [
'**/*.js',
'!node_modules/**'
]
},
jscs: {
src: '<%= jshint.all %>'
},
banana: conf.MessagesDirs,
jsonlint: {
all: [
@ -14,6 +28,6 @@ module.exports = function ( grunt ) {
}
} );
grunt.registerTask( 'test', [ 'jsonlint', 'banana' ] );
grunt.registerTask( 'test', [ 'jshint', 'jscs', 'jsonlint', 'banana' ] );
grunt.registerTask( 'default', 'test' );
};

View file

@ -34,12 +34,12 @@
}, data );
if ( mw.user.isAnon() ) {
data['user.class'] = 'IP';
data[ 'user.class' ] = 'IP';
}
data['action.' + action + '.type'] = data.type;
data['action.' + action + '.mechanism'] = data.mechanism;
data['action.' + action + '.timing'] = data.timing === undefined ?
data[ 'action.' + action + '.type' ] = data.type;
data[ 'action.' + action + '.mechanism' ] = data.mechanism;
data[ 'action.' + action + '.timing' ] = data.timing === undefined ?
0 : Math.floor( data.timing );
// Remove renamed properties
delete data.type;
@ -70,7 +70,7 @@
onUnloadFallback = window.onunload;
window.onunload = function () {
var fallbackResult, abortType,
caVeEdit = $( '#ca-ve-edit' )[0],
caVeEdit = $( '#ca-ve-edit' )[ 0 ],
switchingToVE = caVeEdit && (
document.activeElement === caVeEdit ||
$.contains( caVeEdit, document.activeElement )

View file

@ -20,32 +20,32 @@ $.wikiEditor.modules.dialogs.config = {
section: 'main',
group: 'insert',
tools: {
'link': {
link: {
labelMsg: 'wikieditor-toolbar-tool-link',
type: 'button',
icon: 'insert-link.png',
offset: [2, -1654],
offset: [ 2, -1654 ],
action: {
type: 'dialog',
module: 'insert-link'
}
},
'file': {
file: {
labelMsg: 'wikieditor-toolbar-tool-file',
type: 'button',
icon: 'insert-file.png',
offset: [2, -1438],
offset: [ 2, -1438 ],
action: {
type: 'dialog',
module: 'insert-file'
}
},
'reference': {
reference: {
labelMsg: 'wikieditor-toolbar-tool-reference',
filters: [ 'body.ns-subject' ],
type: 'button',
icon: 'insert-reference.png',
offset: [2, -1798],
offset: [ 2, -1798 ],
action: {
type: 'dialog',
module: 'insert-reference'
@ -57,11 +57,11 @@ $.wikiEditor.modules.dialogs.config = {
section: 'advanced',
group: 'insert',
tools: {
'table': {
table: {
labelMsg: 'wikieditor-toolbar-tool-table',
type: 'button',
icon: 'insert-table.png',
offset: [2, -1942],
offset: [ 2, -1942 ],
action: {
type: 'dialog',
module: 'insert-table'
@ -72,13 +72,13 @@ $.wikiEditor.modules.dialogs.config = {
.wikiEditor( 'addToToolbar', {
section: 'advanced',
groups: {
'search': {
search: {
tools: {
'replace': {
replace: {
labelMsg: 'wikieditor-toolbar-tool-replace',
type: 'button',
icon: 'search-replace.png',
offset: [-70, -214],
offset: [ -70, -214 ],
action: {
type: 'dialog',
module: 'search-and-replace'
@ -91,7 +91,7 @@ $.wikiEditor.modules.dialogs.config = {
},
getDefaultConfig: function () {
return { 'dialogs': {
return { dialogs: {
'insert-link': {
titleMsg: 'wikieditor-toolbar-tool-link-title',
id: 'wikieditor-toolbar-link-dialog',
@ -144,17 +144,17 @@ $.wikiEditor.modules.dialogs.config = {
internal = false;
}
// Abort previous request
var request = $( '#wikieditor-toolbar-link-int-target-status' ).data( 'request' );
var request = $( '#wikieditor-toolbar-link-int-target-status' ).data( 'request' ),
target = $( '#wikieditor-toolbar-link-int-target' ).val(),
cache = $( '#wikieditor-toolbar-link-int-target-status' ).data( 'existencecache' );
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] );
updateWidget( cache[ target ] );
return;
}
if ( target.replace( /^\s+$/,'' ) === '' ) {
if ( target.replace( /^\s+$/, '' ) === '' ) {
// Hide the widget when the textbox is empty
updateWidget( false );
return;
@ -191,7 +191,7 @@ $.wikiEditor.modules.dialogs.config = {
// This happens in some weird cases like interwiki links
status = false;
} else {
var page = data.query.pages[data.query.pageids[0]];
var page = data.query.pages[ data.query.pageids[ 0 ] ];
status = 'exists';
if ( page.missing !== undefined ) {
status = 'notexists';
@ -204,7 +204,7 @@ $.wikiEditor.modules.dialogs.config = {
// Cache the status of the link target if the force internal
// parameter was not passed
if ( !internal ) {
cache[target] = status;
cache[ target ] = status;
}
updateWidget( status );
} )
@ -299,8 +299,8 @@ $.wikiEditor.modules.dialogs.config = {
}, 0 );
} );
$( '#wikieditor-toolbar-link-int-text' ).bind( 'change keydown paste cut', function () {
var oldVal = $( this ).val();
var that = this;
var oldVal = $( this ).val(),
that = this;
setTimeout( function () {
if ( $( that ).val() !== oldVal ) {
$( that ).data( 'untouched', false );
@ -330,9 +330,9 @@ $.wikiEditor.modules.dialogs.config = {
.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
src: $.wikiEditor.imgPath + 'dialogs/' + 'loading-small.gif',
alt: loadingMsg,
title: loadingMsg
} ) )
)
.append( $( '<div>' )
@ -365,8 +365,8 @@ $.wikiEditor.modules.dialogs.config = {
// Title suggestions
$( '#wikieditor-toolbar-link-int-target' ).data( 'suggcache', {} ).suggestions( {
fetch: function () {
var that = this;
var title = $( this ).val();
var that = this,
title = $( this ).val();
if ( isExternalLink( title ) || title.indexOf( '|' ) !== -1 || title === '' ) {
$( this ).suggestions( 'suggestions', [] );
@ -375,7 +375,7 @@ $.wikiEditor.modules.dialogs.config = {
var cache = $( this ).data( 'suggcache' );
if ( hasOwn.call( cache, title ) ) {
$( this ).suggestions( 'suggestions', cache[title] );
$( this ).suggestions( 'suggestions', cache[ title ] );
return;
}
@ -386,15 +386,16 @@ $.wikiEditor.modules.dialogs.config = {
suggest: ''
} )
.done( function ( data ) {
cache[title] = data[1];
$( that ).suggestions( 'suggestions', data[1] );
cache[ title ] = data[ 1 ];
$( that ).suggestions( 'suggestions', data[ 1 ] );
} );
$( this ).data( 'request', request );
},
cancel: function () {
var request = $( this ).data( 'request' );
if ( request )
if ( request ) {
request.abort();
}
}
} );
},
@ -414,15 +415,17 @@ $.wikiEditor.modules.dialogs.config = {
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();
var insertText = '',
whitespace = $( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace' ),
target = $( '#wikieditor-toolbar-link-int-target' ).val(),
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' ) )
if ( $( '#wikieditor-toolbar-link-int-target' ).data( 'tooltip-mode' ) ) {
target = "";
if ( $( '#wikieditor-toolbar-link-int-text' ).data( 'tooltip-mode' ) )
}
if ( $( '#wikieditor-toolbar-link-int-text' ).data( 'tooltip-mode' ) ) {
text = "";
}
if ( target === '' ) {
alert( mw.msg( 'wikieditor-toolbar-tool-link-empty' ) );
return;
@ -440,24 +443,26 @@ $.wikiEditor.modules.dialogs.config = {
return;
}
if ( target === text || !text.length )
if ( target === text || !text.length ) {
insertText = '[[' + target + ']]';
else
} else {
insertText = '[[' + target + '|' + escapeInternalText( text ) + ']]';
}
} else {
target = $.trim( target );
// Prepend http:// if there is no protocol
if ( !target.match( /^[a-z]+:\/\/./ ) )
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;
var buttons = { },
that = this;
buttons[ mw.msg( 'wikieditor-toolbar-tool-link-lookslikeinternal-int' ) ] =
function () {
$( '#wikieditor-toolbar-link-int-target' ).val( match[1] ).change();
$( '#wikieditor-toolbar-link-int-target' ).val( match[ 1 ] ).change();
$( this ).dialog( 'close' );
};
buttons[ mw.msg( 'wikieditor-toolbar-tool-link-lookslikeinternal-ext' ) ] =
@ -468,25 +473,26 @@ $.wikiEditor.modules.dialogs.config = {
$( this ).dialog( 'close' );
};
$.wikiEditor.modules.dialogs.quickDialog(
mw.msg( 'wikieditor-toolbar-tool-link-lookslikeinternal', match[1] ),
mw.msg( 'wikieditor-toolbar-tool-link-lookslikeinternal', match[ 1 ] ),
{ buttons: buttons }
);
return;
}
var escTarget = escapeExternalTarget( target );
var escText = escapeExternalText( text );
var escTarget = escapeExternalTarget( target ),
escText = escapeExternalText( text );
if ( escTarget === escText )
if ( escTarget === escText ) {
insertText = escTarget;
else if ( text === '' )
} else if ( text === '' ) {
insertText = '[' + escTarget + ']';
else
} else {
insertText = '[' + escTarget + ' ' + escText + ']';
}
}
// Preserve whitespace in selection when replacing
if ( whitespace ) {
insertText = whitespace[0] + insertText + whitespace[1];
insertText = whitespace[ 0 ] + insertText + whitespace[ 1 ];
}
$( this ).dialog( 'close' );
$.wikiEditor.modules.toolbar.fn.doAction( $( this ).data( 'context' ), {
@ -531,18 +537,18 @@ $.wikiEditor.modules.dialogs.config = {
if ( selection !== '' ) {
if ( ( matches = selection.match( /^(\s*)\[\[([^\]\|]+)(\|([^\]\|]*))?\]\](\s*)$/ ) ) ) {
// [[foo|bar]] or [[foo]]
target = matches[2];
text = ( matches[4] ? matches[4] : matches[2] );
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] ] );
$( '#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] || '' );
target = matches[ 2 ];
text = ( matches[ 4 ] || '' );
type = 'ext';
// Preserve whitespace when replacing
$( '#wikieditor-toolbar-link-dialog' ).data( 'whitespace', [ matches[1], matches[5] ] );
$( '#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
@ -559,12 +565,15 @@ $.wikiEditor.modules.dialogs.config = {
// Change the value by calling val() doesn't trigger the change event, so let's do that
// ourselves
if ( typeof text !== 'undefined' )
if ( typeof text !== 'undefined' ) {
$( '#wikieditor-toolbar-link-int-text' ).val( text ).change();
if ( typeof target !== 'undefined' )
}
if ( typeof target !== 'undefined' ) {
$( '#wikieditor-toolbar-link-int-target' ).val( target ).change();
if ( typeof type !== 'undefined' )
}
if ( typeof type !== 'undefined' ) {
$( '#wikieditor-toolbar-link-' + type ).prop( 'checked', true );
}
}
$( '#wikieditor-toolbar-link-int-text' ).data( 'untouched',
$( '#wikieditor-toolbar-link-int-text' ).val() ===
@ -580,8 +589,9 @@ $.wikiEditor.modules.dialogs.config = {
$( '#wikieditor-toolbar-link-int-text, #wikiedit-toolbar-link-int-target' )
.each( function () {
if ( $( this ).val() === '' )
if ( $( this ).val() === '' ) {
$( this ).parent().find( 'label' ).show();
}
} );
if ( !$( this ).data( 'dialogkeypressset' ) ) {
@ -631,9 +641,9 @@ $.wikiEditor.modules.dialogs.config = {
{
type: 'replace',
options: {
pre: whitespace[0] + '<ref' + attributes + '>',
pre: whitespace[ 0 ] + '<ref' + attributes + '>',
peri: insertText,
post: '</ref>' + whitespace[1]
post: '</ref>' + whitespace[ 1 ]
}
},
$( this )
@ -663,11 +673,11 @@ $.wikiEditor.modules.dialogs.config = {
if ( selection !== '' ) {
var matches, text;
if ( ( matches = selection.match( /^(\s*)<ref([^\>]*)>([^<]*)<\/ref\>(\s*)$/ ) ) ) {
text = matches[3];
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] );
.data( 'whitespace', [ matches[ 1 ], matches[ 4 ] ] );
$( '#wikieditor-toolbar-reference-dialog' ).data( 'attributes', matches[ 2 ] );
} else {
text = selection;
}
@ -771,9 +781,9 @@ $.wikiEditor.modules.dialogs.config = {
);
// Restore form state
$( ['#wikieditor-toolbar-file-target',
$( [ '#wikieditor-toolbar-file-target',
'#wikieditor-toolbar-file-caption',
'#wikieditor-toolbar-file-size'].join( ',' )
'#wikieditor-toolbar-file-size' ].join( ',' )
).val( '' );
$( '#wikieditor-toolbar-file-float' ).val( 'default' );
/*jshint camelcase: false */
@ -924,10 +934,12 @@ $.wikiEditor.modules.dialogs.config = {
table = table.substr( 0, table.length - 1 ) + "\n";
}
var classes = [];
if ( $( '#wikieditor-toolbar-table-wikitable' ).is( ':checked' ) )
if ( $( '#wikieditor-toolbar-table-wikitable' ).is( ':checked' ) ) {
classes.push( 'wikitable' );
if ( $( '#wikieditor-toolbar-table-sortable' ).is( ':checked' ) )
}
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(
@ -945,16 +957,19 @@ $.wikiEditor.modules.dialogs.config = {
);
// Restore form state
$( '#wikieditor-toolbar-table-dimensions-rows' ).val( 3 );
$( '#wikieditor-toolbar-table-dimensions-columns' ).val( 3 );
$( '#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();
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' );
@ -984,22 +999,22 @@ $.wikiEditor.modules.dialogs.config = {
}
},
'search-and-replace': {
'browsers': {
browsers: {
// Left-to-right languages
'ltr': {
'msie': [['>=', 11]], // Known to work on 11.
'firefox': [['>=', 2]],
'opera': false,
'safari': [['>=', 3]],
'chrome': [['>=', 3]]
ltr: {
msie: [ [ '>=', 11 ] ], // Known to work on 11.
firefox: [ [ '>=', 2 ] ],
opera: false,
safari: [ [ '>=', 3 ] ],
chrome: [ [ '>=', 3 ] ]
},
// Right-to-left languages
'rtl': {
'msie': [['>=', 11]], // Works on 11 but dialog positioning is cruddy.
'firefox': [['>=', 2]],
'opera': false,
'safari': [['>=', 3]],
'chrome': [['>=', 3]]
rtl: {
msie: [ [ '>=', 11 ] ], // Works on 11 but dialog positioning is cruddy.
firefox: [ [ '>=', 2 ] ],
opera: false,
safari: [ [ '>=', 3 ] ],
chrome: [ [ '>=', 3 ] ]
}
},
titleMsg: 'wikieditor-toolbar-tool-replace-title',
@ -1083,25 +1098,25 @@ $.wikiEditor.modules.dialogs.config = {
// 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] );
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 );
var matchedText = textRemainder.substr( index, match[ i ].length );
textRemainder = textRemainder.substr( index + match[ i ].length );
start = index + offset;
end = start + match[i].length;
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( 'setSelection', { start: start, end: end } )
.textSelection( 'encapsulateSelection', {
'peri': replace,
'replace': true } )
.textSelection( 'setSelection', { 'start': start, 'end': newEnd } );
peri: replace,
replace: true } )
.textSelection( 'setSelection', { start: start, end: newEnd } );
offset = newEnd;
}
$( '#wikieditor-toolbar-replace-success' )
@ -1115,7 +1130,7 @@ $.wikiEditor.modules.dialogs.config = {
if ( isRegex ) {
// If backreferences (like $1) are used, the actual actual replacement string will be different
actualReplacement = match[0].replace( regex, replaceStr );
actualReplacement = match[ 0 ].replace( regex, replaceStr );
} else {
actualReplacement = replaceStr;
}
@ -1123,20 +1138,20 @@ $.wikiEditor.modules.dialogs.config = {
if ( match ) {
// Do the replacement
$textarea.textSelection( 'encapsulateSelection', {
'peri': actualReplacement,
'replace': true } );
peri: actualReplacement,
replace: true } );
// Reload the text after replacement
text = $textarea.textSelection( 'getContents' );
}
// Find the next instance
offset = offset + match[0].length + actualReplacement.length;
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;
end = start + match[ 0 ].length;
} else {
// If no new string was found, try searching from the beginning.
// TODO: Add a "Wrap around" option.
@ -1144,7 +1159,7 @@ $.wikiEditor.modules.dialogs.config = {
match = textRemainder.match( regex );
if ( match ) {
start = match.index;
end = start + match[0].length;
end = start + match[ 0 ].length;
} else {
// Give up
start = 0;
@ -1153,18 +1168,17 @@ $.wikiEditor.modules.dialogs.config = {
}
} else {
start = offset + match.index;
end = start + match[0].length;
end = start + match[ 0 ].length;
}
$( this ).data( 'matchIndex', start );
$textarea.textSelection( 'setSelection', {
'start': start,
'end': end
} );
start: start,
end: end } );
$textarea.textSelection( 'scrollToCaretPosition' );
$( this ).data( 'offset', end );
$textarea[0].focus();
$textarea[ 0 ].focus();
}
} );
},

View file

@ -11,25 +11,35 @@ $.wikiEditor.modules.dialogs = {
browsers: {
// Left-to-right languages
ltr: {
msie: [['>=', 7]],
msie: [ [ '>=', 7 ] ],
// jQuery UI appears to be broken in FF 2.0 - 2.0.0.4
firefox: [
['>=', 2], ['!=', '2.0'], ['!=', '2.0.0.1'], ['!=', '2.0.0.2'], ['!=', '2.0.0.3'], ['!=', '2.0.0.4']
[ '>=', 2 ],
[ '!=', '2.0' ],
[ '!=', '2.0.0.1' ],
[ '!=', '2.0.0.2' ],
[ '!=', '2.0.0.3' ],
[ '!=', '2.0.0.4' ]
],
opera: [['>=', 9.6]],
safari: [['>=', 3]],
chrome: [['>=', 3]]
opera: [ [ '>=', 9.6 ] ],
safari: [ [ '>=', 3 ] ],
chrome: [ [ '>=', 3 ] ]
},
// Right-to-left languages
rtl: {
msie: [['>=', 7]],
msie: [ [ '>=', 7 ] ],
// jQuery UI appears to be broken in FF 2.0 - 2.0.0.4
firefox: [
['>=', 2], ['!=', '2.0'], ['!=', '2.0.0.1'], ['!=', '2.0.0.2'], ['!=', '2.0.0.3'], ['!=', '2.0.0.4']
[ '>=', 2 ],
[ '!=', '2.0' ],
[ '!=', '2.0.0.1' ],
[ '!=', '2.0.0.2' ],
[ '!=', '2.0.0.3' ],
[ '!=', '2.0.0.4' ]
],
opera: [['>=', 9.6]],
safari: [['>=', 3]],
chrome: [['>=', 3]]
opera: [ [ '>=', 9.6 ] ],
safari: [ [ '>=', 3 ] ],
chrome: [ [ '>=', 3 ] ]
}
},
@ -42,7 +52,7 @@ $.wikiEditor.modules.dialogs = {
},
openDialog: function ( context, module ) {
if ( module in $.wikiEditor.modules.dialogs.modules ) {
var mod = $.wikiEditor.modules.dialogs.modules[module],
var mod = $.wikiEditor.modules.dialogs.modules[ module ],
$dialog = $( '#' + mod.id );
if ( $dialog.length === 0 ) {
$.wikiEditor.modules.dialogs.fn.reallyCreate( context, mod, module );
@ -59,7 +69,7 @@ $.wikiEditor.modules.dialogs = {
},
closeDialog: function ( context, module ) {
if ( module in $.wikiEditor.modules.dialogs.modules ) {
$( '#' + $.wikiEditor.modules.dialogs.modules[module].id ).dialog( 'close' );
$( '#' + $.wikiEditor.modules.dialogs.modules[ module ].id ).dialog( 'close' );
}
}
},
@ -79,12 +89,12 @@ $.wikiEditor.modules.dialogs = {
// Defer building of modules, unless they require immediate creation
for ( mod in config ) {
module = config[mod];
module = config[ mod ];
// Only create the dialog if it's supported, isn't filtered and doesn't exist yet
filtered = false;
if ( typeof module.filters !== 'undefined' ) {
for ( i = 0; i < module.filters.length; i++ ) {
if ( $( module.filters[i] ).length === 0 ) {
if ( $( module.filters[ i ] ).length === 0 ) {
filtered = true;
break;
}
@ -98,7 +108,7 @@ $.wikiEditor.modules.dialogs = {
// Re-select from the DOM, we might have removed the dialog just now
$existingDialog = $( '#' + module.id );
if ( !filtered && $.wikiEditor.isSupported( module ) && $existingDialog.length === 0 ) {
$.wikiEditor.modules.dialogs.modules[mod] = module;
$.wikiEditor.modules.dialogs.modules[ mod ] = module;
context.$textarea.trigger( 'wikiEditor-dialogs-setup-' + mod );
// If this dialog requires immediate creation, create it now
if ( typeof module.immediateCreate !== 'undefined' && module.immediateCreate ) {
@ -110,9 +120,10 @@ $.wikiEditor.modules.dialogs = {
/**
* Build the actual dialog. This done on-demand rather than in create()
*
* @param {Object} context Context object of editor dialog belongs to
* @param {Object} module Dialog module object
* @param {String} name Dialog name (key in $.wikiEditor.modules.dialogs.modules)
* @param {string} name Dialog name (key in $.wikiEditor.modules.dialogs.modules)
*/
reallyCreate: function ( context, module, name ) {
var msg, dialogDiv, $content,
@ -130,7 +141,7 @@ $.wikiEditor.modules.dialogs = {
// foo = { mw.msg( 'bar' ): baz }
configuration.newButtons = {};
for ( msg in configuration.buttons ) {
configuration.newButtons[mw.msg( msg )] = configuration.buttons[msg];
configuration.newButtons[ mw.msg( msg ) ] = configuration.buttons[ msg ];
}
configuration.buttons = configuration.newButtons;
if ( module.htmlTemplate ) {
@ -199,7 +210,7 @@ $.wikiEditor.modules.dialogs = {
wrapperWidth = Math.max( wrapper.get( 0 ).scrollWidth, wrapperWidth );
wrapper.width( wrapperWidth );
$( this ).data( 'wrapperWidth', wrapperWidth );
$( this ).dialog( { 'width': wrapper.width() } );
$( this ).dialog( { width: wrapper.width() } );
wrapper.css( 'left', parseInt( wrapper.css( 'left' ), 10 ) - ( wrapper.width() - oldWidth ) / 2 );
}
$( this ).css( 'white-space', oldWS );
@ -207,9 +218,11 @@ $.wikiEditor.modules.dialogs = {
$( this ).attr( 'style', $( this ).data( 'oldstyle' ) );
} );
},
/**
* Set the right tabindexes on elements in a dialog
* @param $elements Elements to set tabindexes on. If they already have tabindexes, this function can behave a bit weird
*
* @param {Object} $elements Elements to set tabindexes on. If they already have tabindexes, this function can behave a bit weird
*/
setTabindexes: function ( $elements ) {
// Get the highest tab index

View file

@ -9,6 +9,7 @@
*
*/
/*jshint onevar:false, boss:true */
// jscs:disable requireParamTypes
( function ( $, mw ) {
var hasOwn = Object.prototype.hasOwnProperty,
@ -21,7 +22,7 @@ fallbackChain = ( function () {
chain = mw.language.getFallbackLanguageChain();
// Do not fallback to 'en'
if ( chain.length >= 2 && !/^en-/.test( chain[chain.length - 2] ) ) {
if ( chain.length >= 2 && !/^en-/.test( chain[ chain.length - 2 ] ) ) {
chain.pop();
}
if ( isRTL ) {
@ -65,34 +66,34 @@ $.wikiEditor = {
// Left-to-right languages
ltr: {
// The toolbar layout is broken in IE6
msie: [['>=', 7]],
msie: [ [ '>=', 7 ] ],
// Layout issues in FF < 2
firefox: [['>=', 2]],
firefox: [ [ '>=', 2 ] ],
// Text selection bugs galore
opera: [['>=', 9.6]],
opera: [ [ '>=', 9.6 ] ],
// jQuery minimums
safari: [['>=', 3]],
chrome: [['>=', 3]],
netscape: [['>=', 9]],
safari: [ [ '>=', 3 ] ],
chrome: [ [ '>=', 3 ] ],
netscape: [ [ '>=', 9 ] ],
blackberry: false,
ipod: [['>=', 6]],
iphone: [['>=', 6]]
ipod: [ [ '>=', 6 ] ],
iphone: [ [ '>=', 6 ] ]
},
// Right-to-left languages
rtl: {
// The toolbar layout is broken in IE 7 in RTL mode, and IE6 in any mode
msie: [['>=', 8]],
msie: [ [ '>=', 8 ] ],
// Layout issues in FF < 2
firefox: [['>=', 2]],
firefox: [ [ '>=', 2 ] ],
// Text selection bugs galore
opera: [['>=', 9.6]],
opera: [ [ '>=', 9.6 ] ],
// jQuery minimums
safari: [['>=', 3]],
chrome: [['>=', 3]],
netscape: [['>=', 9]],
safari: [ [ '>=', 3 ] ],
chrome: [ [ '>=', 3 ] ],
netscape: [ [ '>=', 9 ] ],
blackberry: false,
ipod: [['>=', 6]],
iphone: [['>=', 6]]
ipod: [ [ '>=', 6 ] ],
iphone: [ [ '>=', 6 ] ]
}
},
@ -112,7 +113,8 @@ $.wikiEditor = {
* similar to another existing browser that things actually do work as expected. The merrits of this argument, which
* is essentially to blacklist rather than whitelist are debateable, but at this point we've decided it's the more
* "open-web" way to go.
* @param module Module object, defaults to $.wikiEditor
*
* @param {Object} module Module object, defaults to $.wikiEditor
*/
isSupported: function ( module ) {
// Fallback to the wikiEditor browser map if no special map is provided in the module
@ -128,13 +130,14 @@ $.wikiEditor = {
/**
* Checks if a module has a specific requirement
* @param module Module object
* @param requirement String identifying requirement
*
* @param {Object} module Module object
* @param {string} requirement String identifying requirement
*/
isRequired: function ( module, requirement ) {
if ( typeof module.req !== 'undefined' ) {
for ( var req in module.req ) {
if ( module.req[req] === requirement ) {
if ( module.req[ req ] === requirement ) {
return true;
}
}
@ -145,8 +148,8 @@ $.wikiEditor = {
/**
* Provides a way to extract messages from objects. Wraps a mediaWiki.message( ... ).plain() call.
*
* @param object Object to extract messages from
* @param property String of name of property which contains the message. This should be the base name of the
* @param {Object} object Object to extract messages from
* @param {string} property String of name of property which contains the message. This should be the base name of the
* property, which means that in the case of the object { this: 'that', fooMsg: 'bar' }, passing property as 'this'
* would return the raw text 'that', while passing property as 'foo' would return the internationalized message
* with the key 'bar'.
@ -156,16 +159,16 @@ $.wikiEditor = {
// Accept array of possible properties, of which the first one found will be used
if ( typeof property === 'object' ) {
for ( i in property ) {
if ( property[i] in object || property[i] + 'Msg' in object ) {
property = property[i];
if ( property[ i ] in object || property[ i ] + 'Msg' in object ) {
property = property[ i ];
break;
}
}
}
if ( property in object ) {
return object[property];
return object[ property ];
} else if ( property + 'Msg' in object ) {
p = object[property + 'Msg'];
p = object[ property + 'Msg' ];
if ( $.isArray( p ) && p.length >= 2 ) {
return mw.message.apply( mw.message, p ).plain();
} else {
@ -182,15 +185,15 @@ $.wikiEditor = {
* should ideally be the case so that you may use a string or object of any number of strings keyed by language
* with a default.
*
* @param object Object to extract property from
* @param {Object} object Object to extract property from
*/
autoLang: function ( object ) {
var i, key;
for ( i = 0; i < fallbackChain.length; i++ ) {
key = fallbackChain[i];
key = fallbackChain[ i ];
if ( hasOwn.call( object, key ) ) {
return object[key];
return object[ key ];
}
}
return object;
@ -200,14 +203,14 @@ $.wikiEditor = {
* Provides a way to extract the path of an icon in a certain language, automatically appending a version number for
* caching purposes and prepending an image path when icon paths are relative.
*
* @param icon Icon object from e.g. toolbar config
* @param path Default icon path, defaults to $.wikiEditor.imgPath
* @param {Object} icon Icon object from e.g. toolbar config
* @param {string} path Default icon path, defaults to $.wikiEditor.imgPath
*/
autoIcon: function ( icon, path ) {
var src = $.wikiEditor.autoLang( icon );
path = path || $.wikiEditor.imgPath;
// Prepend path if src is not absolute
if ( src.substr( 0, 7 ) !== 'http://' && src.substr( 0, 8 ) !== 'https://' && src[0] !== '/' ) {
if ( src.substr( 0, 7 ) !== 'http://' && src.substr( 0, 8 ) !== 'https://' && src[ 0 ] !== '/' ) {
src = path + src;
}
return src + '?' + mw.loader.getVersion( 'jquery.wikiEditor' );
@ -216,9 +219,10 @@ $.wikiEditor = {
/**
* Get the sprite offset for a language if available, icon for a language if available, or the default offset or icon,
* in that order of preference.
* @param icon Icon object, see autoIcon()
* @param offset Offset object
* @param path Icon path, see autoIcon()
*
* @param {Object} icon Icon object, see autoIcon()
* @param {Object} offset Offset object
* @param {string} path Icon path, see autoIcon()
*/
autoIconOrOffset: function ( icon, offset, path ) {
var i, key, src;
@ -226,14 +230,14 @@ $.wikiEditor = {
path = path || $.wikiEditor.imgPath;
for ( i = 0; i < fallbackChain.length; i++ ) {
key = fallbackChain[i];
key = fallbackChain[ i ];
if ( offset && hasOwn.call( offset, key ) ) {
return offset[key];
return offset[ key ];
}
if ( icon && hasOwn.call( icon, key ) ) {
src = icon[key];
src = icon[ key ];
// Prepend path if src is not absolute
if ( src.substr( 0, 7 ) !== 'http://' && src.substr( 0, 8 ) !== 'https://' && src[0] !== '/' ) {
if ( src.substr( 0, 7 ) !== 'http://' && src.substr( 0, 8 ) !== 'https://' && src[ 0 ] !== '/' ) {
src = path + src;
}
return src + '?' + mw.loader.getVersion( 'jquery.wikiEditor' );
@ -248,382 +252,382 @@ $.wikiEditor = {
*/
$.fn.wikiEditor = function () {
// Skip any further work when running in browsers that are unsupported
if ( !$.wikiEditor.isSupported() ) {
return $( this );
}
// Skip any further work when running in browsers that are unsupported
if ( !$.wikiEditor.isSupported() ) {
return $( this );
}
// Save browser profile for detailed tests.
var profile = $.client.profile();
// Save browser profile for detailed tests.
var profile = $.client.profile();
/* Initialization */
/* Initialization */
// The wikiEditor context is stored in the element's data, so when this function gets called again we can pick up right
// where we left off
var context = $( this ).data( 'wikiEditor-context' );
// On first call, we need to set things up, but on all following calls we can skip right to the API handling
if ( !context || typeof context === 'undefined' ) {
// The wikiEditor context is stored in the element's data, so when this function gets called again we can pick up right
// where we left off
var context = $( this ).data( 'wikiEditor-context' );
// On first call, we need to set things up, but on all following calls we can skip right to the API handling
if ( !context || typeof context === 'undefined' ) {
// Star filling the context with useful data - any jQuery selections, as usual should be named with a preceding $
context = {
// Reference to the textarea element which the wikiEditor is being built around
'$textarea': $( this ),
// Container for any number of mutually exclusive views that are accessible by tabs
'views': {},
// Container for any number of module-specific data - only including data for modules in use on this context
'modules': {},
// General place to shouve bits of data into
'data': {},
// Unique numeric ID of this instance used both for looking up and differentiating instances of wikiEditor
'instance': $.wikiEditor.instances.push( $( this ) ) - 1,
// Saved selection state for old IE (<=10)
'savedSelection': null,
// List of extensions active on this context
'extensions': []
};
// Star filling the context with useful data - any jQuery selections, as usual should be named with a preceding $
context = {
// Reference to the textarea element which the wikiEditor is being built around
$textarea: $( this ),
// Container for any number of mutually exclusive views that are accessible by tabs
views: {},
// Container for any number of module-specific data - only including data for modules in use on this context
modules: {},
// General place to shouve bits of data into
data: {},
// Unique numeric ID of this instance used both for looking up and differentiating instances of wikiEditor
instance: $.wikiEditor.instances.push( $( this ) ) - 1,
// Saved selection state for old IE (<=10)
savedSelection: null,
// List of extensions active on this context
extensions: []
};
/**
* Externally Accessible API
*
* These are available using calls to $( selection ).wikiEditor( call, data ) where selection is a jQuery selection
* of the textarea that the wikiEditor instance was built around.
*/
context.api = {
/**
* Activates a module on a specific context with optional configuration data.
* Externally Accessible API
*
* @param data Either a string of the name of a module to add without any additional configuration parameters,
* or an object with members keyed with module names and valued with configuration objects.
* These are available using calls to $( selection ).wikiEditor( call, data ) where selection is a jQuery selection
* of the textarea that the wikiEditor instance was built around.
*/
'addModule': function ( context, data ) {
var module, call,
modules = {};
if ( typeof data === 'string' ) {
modules[data] = {};
} else if ( typeof data === 'object' ) {
modules = data;
context.api = {
/*!
* Activates a module on a specific context with optional configuration data.
*
* @param data Either a string of the name of a module to add without any additional configuration parameters,
* or an object with members keyed with module names and valued with configuration objects.
*/
addModule: function ( context, data ) {
var module, call,
modules = {};
if ( typeof data === 'string' ) {
modules[ data ] = {};
} else if ( typeof data === 'object' ) {
modules = data;
}
for ( module in modules ) {
// Check for the existance of an available / supported module with a matching name and a create function
if ( typeof module === 'string' && typeof $.wikiEditor.modules[ module ] !== 'undefined' &&
$.wikiEditor.isSupported( $.wikiEditor.modules[ module ] )
) {
// Extend the context's core API with this module's own API calls
if ( 'api' in $.wikiEditor.modules[ module ] ) {
for ( call in $.wikiEditor.modules[ module ].api ) {
// Modules may not overwrite existing API functions - first come, first serve
if ( !( call in context.api ) ) {
context.api[ call ] = $.wikiEditor.modules[ module ].api[ call ];
}
}
}
// Activate the module on this context
if ( 'fn' in $.wikiEditor.modules[ module ] && 'create' in $.wikiEditor.modules[ module ].fn ) {
// Add a place for the module to put it's own stuff
context.modules[ module ] = {};
// Tell the module to create itself on the context
$.wikiEditor.modules[ module ].fn.create( context, modules[ module ] );
}
}
}
}
for ( module in modules ) {
// Check for the existance of an available / supported module with a matching name and a create function
if ( typeof module === 'string' && typeof $.wikiEditor.modules[module] !== 'undefined' &&
$.wikiEditor.isSupported( $.wikiEditor.modules[module] ) )
{
// Extend the context's core API with this module's own API calls
if ( 'api' in $.wikiEditor.modules[module] ) {
for ( call in $.wikiEditor.modules[module].api ) {
// Modules may not overwrite existing API functions - first come, first serve
if ( !( call in context.api ) ) {
context.api[call] = $.wikiEditor.modules[module].api[call];
};
/**
* Event Handlers
*
* These act as filters returning false if the event should be ignored or returning true if it should be passed
* on to all modules. This is also where we can attach some extra information to the events.
*/
context.evt = {
/* Empty until extensions add some; see jquery.wikiEditor.iframe.js for examples. */
};
/* Internal Functions */
context.fn = {
/**
* Executes core event filters as well as event handlers provided by modules.
*/
trigger: function ( name, event ) {
// Workaround for a scrolling bug in IE8 (bug 61908)
if ( profile.name === 'msie' && profile.versionNumber === 8 ) {
context.$textarea.css( 'width', context.$textarea.parent().width() );
}
// Event is an optional argument, but from here on out, at least the type field should be dependable
if ( typeof event === 'undefined' ) {
event = { type: 'custom' };
}
// Ensure there's a place for extra information to live
if ( typeof event.data === 'undefined' ) {
event.data = {};
}
// Allow filtering to occur
if ( name in context.evt ) {
if ( !context.evt[ name ]( event ) ) {
return false;
}
}
var returnFromModules = null; // they return null by default
// Pass the event around to all modules activated on this context
for ( var module in context.modules ) {
if (
module in $.wikiEditor.modules &&
'evt' in $.wikiEditor.modules[ module ] &&
name in $.wikiEditor.modules[ module ].evt
) {
var ret = $.wikiEditor.modules[ module ].evt[ name ]( context, event );
if ( ret !== null ) {
// if 1 returns false, the end result is false
if ( returnFromModules === null ) {
returnFromModules = ret;
} else {
returnFromModules = returnFromModules && ret;
}
}
}
// Activate the module on this context
if ( 'fn' in $.wikiEditor.modules[module] && 'create' in $.wikiEditor.modules[module].fn ) {
// Add a place for the module to put it's own stuff
context.modules[module] = {};
// Tell the module to create itself on the context
$.wikiEditor.modules[module].fn.create( context, modules[module] );
}
}
}
}
};
/**
* Event Handlers
*
* These act as filters returning false if the event should be ignored or returning true if it should be passed
* on to all modules. This is also where we can attach some extra information to the events.
*/
context.evt = {
/* Empty until extensions add some; see jquery.wikiEditor.iframe.js for examples. */
};
/* Internal Functions */
context.fn = {
/**
* Executes core event filters as well as event handlers provided by modules.
*/
trigger: function ( name, event ) {
// Workaround for a scrolling bug in IE8 (bug 61908)
if ( profile.name === 'msie' && profile.versionNumber === 8 ) {
context.$textarea.css( 'width', context.$textarea.parent().width() );
}
// Event is an optional argument, but from here on out, at least the type field should be dependable
if ( typeof event === 'undefined' ) {
event = { 'type': 'custom' };
}
// Ensure there's a place for extra information to live
if ( typeof event.data === 'undefined' ) {
event.data = {};
}
// Allow filtering to occur
if ( name in context.evt ) {
if ( !context.evt[name]( event ) ) {
return false;
if ( returnFromModules !== null ) {
return returnFromModules;
} else {
return true;
}
}
var returnFromModules = null; // they return null by default
// Pass the event around to all modules activated on this context
},
for ( var module in context.modules ) {
if (
module in $.wikiEditor.modules &&
'evt' in $.wikiEditor.modules[module] &&
name in $.wikiEditor.modules[module].evt
) {
var ret = $.wikiEditor.modules[module].evt[name]( context, event );
if ( ret !== null ) {
// if 1 returns false, the end result is false
if ( returnFromModules === null ) {
returnFromModules = ret;
} else {
returnFromModules = returnFromModules && ret;
}
}
}
}
if ( returnFromModules !== null ) {
return returnFromModules;
} else {
return true;
}
},
/**
* Adds a button to the UI
*/
addButton: function ( options ) {
// Ensure that buttons and tabs are visible
context.$controls.show();
context.$buttons.show();
return $( '<button>' )
.text( $.wikiEditor.autoMsg( options, 'caption' ) )
.click( options.action )
.appendTo( context.$buttons );
},
/**
* Adds a view to the UI, which is accessed using a set of tabs. Views are mutually exclusive and by default a
* wikitext view will be present. Only when more than one view exists will the tabs will be visible.
*/
addView: function ( options ) {
// Adds a tab
function addTab( options ) {
/**
* Adds a button to the UI
*/
addButton: function ( options ) {
// Ensure that buttons and tabs are visible
context.$controls.show();
context.$tabs.show();
// Return the newly appended tab
context.$buttons.show();
return $( '<button>' )
.text( $.wikiEditor.autoMsg( options, 'caption' ) )
.click( options.action )
.appendTo( context.$buttons );
},
/**
* Adds a view to the UI, which is accessed using a set of tabs. Views are mutually exclusive and by default a
* wikitext view will be present. Only when more than one view exists will the tabs will be visible.
*/
addView: function ( options ) {
// Adds a tab
function addTab( options ) {
// Ensure that buttons and tabs are visible
context.$controls.show();
context.$tabs.show();
// Return the newly appended tab
return $( '<div>' )
.attr( 'rel', 'wikiEditor-ui-view-' + options.name )
.addClass( context.view === options.name ? 'current' : null )
.append( $( '<a>' )
.attr( 'href', '#' )
.mousedown( function () {
// No dragging!
return false;
} )
.click( function ( event ) {
context.$ui.find( '.wikiEditor-ui-view' ).hide();
context.$ui.find( '.' + $( this ).parent().attr( 'rel' ) ).show();
context.$tabs.find( 'div' ).removeClass( 'current' );
$( this ).parent().addClass( 'current' );
$( this ).blur();
if ( 'init' in options && typeof options.init === 'function' ) {
options.init( context );
}
event.preventDefault();
return false;
} )
.text( $.wikiEditor.autoMsg( options, 'title' ) )
)
.appendTo( context.$tabs );
}
// Automatically add the previously not-needed wikitext tab
if ( !context.$tabs.children().length ) {
addTab( { name: 'wikitext', titleMsg: 'wikieditor-wikitext-tab' } );
}
// Add the tab for the view we were actually asked to add
addTab( options );
// Return newly appended view
return $( '<div>' )
.attr( 'rel', 'wikiEditor-ui-view-' + options.name )
.addClass( context.view === options.name ? 'current' : null )
.append( $( '<a>' )
.attr( 'href', '#' )
.mousedown( function () {
// No dragging!
return false;
} )
.click( function ( event ) {
context.$ui.find( '.wikiEditor-ui-view' ).hide();
context.$ui.find( '.' + $( this ).parent().attr( 'rel' ) ).show();
context.$tabs.find( 'div' ).removeClass( 'current' );
$( this ).parent().addClass( 'current' );
$( this ).blur();
if ( 'init' in options && typeof options.init === 'function' ) {
options.init( context );
}
event.preventDefault();
return false;
} )
.text( $.wikiEditor.autoMsg( options, 'title' ) )
)
.appendTo( context.$tabs );
}
// Automatically add the previously not-needed wikitext tab
if ( !context.$tabs.children().length ) {
addTab( { 'name': 'wikitext', 'titleMsg': 'wikieditor-wikitext-tab' } );
}
// Add the tab for the view we were actually asked to add
addTab( options );
// Return newly appended view
return $( '<div>' )
.addClass( 'wikiEditor-ui-view wikiEditor-ui-view-' + options.name )
.hide()
.appendTo( context.$ui );
},
.addClass( 'wikiEditor-ui-view wikiEditor-ui-view-' + options.name )
.hide()
.appendTo( context.$ui );
},
/**
* Save scrollTop and cursor position for old IE (<=10)
* Related to old IE 8 issues that are no longer reproducible
*/
saveCursorAndScrollTop: function () {
if ( profile.name === 'msie' && document.selection && document.selection.createRange ) {
var IHateIE8 = {
'scrollTop': context.$textarea.scrollTop(),
'pos': context.$textarea.textSelection( 'getCaretPosition', { startAndEnd: true } )
};
context.$textarea.data( 'IHateIE8', IHateIE8 );
}
},
/**
* Save scrollTop and cursor position for old IE (<=10)
* Related to old IE 8 issues that are no longer reproducible
*/
saveCursorAndScrollTop: function () {
if ( profile.name === 'msie' && document.selection && document.selection.createRange ) {
var IHateIE8 = {
scrollTop: context.$textarea.scrollTop(),
pos: context.$textarea.textSelection( 'getCaretPosition', { startAndEnd: true } )
};
context.$textarea.data( 'IHateIE8', IHateIE8 );
}
},
/**
* Restore scrollTo and cursor position for IE (<=10)
* Related to old IE 8 issues that are no longer reproducible
*/
restoreCursorAndScrollTop: function () {
if ( profile.name === 'msie' && document.selection && document.selection.createRange ) {
var IHateIE8 = context.$textarea.data( 'IHateIE' );
if ( IHateIE8 ) {
context.$textarea.scrollTop( IHateIE8.scrollTop );
context.$textarea.textSelection( 'setSelection', { start: IHateIE8.pos[0], end: IHateIE8.pos[1] } );
context.$textarea.data( 'IHateIE8', null );
/**
* Restore scrollTo and cursor position for IE (<=10)
* Related to old IE 8 issues that are no longer reproducible
*/
restoreCursorAndScrollTop: function () {
if ( profile.name === 'msie' && document.selection && document.selection.createRange ) {
var IHateIE8 = context.$textarea.data( 'IHateIE' );
if ( IHateIE8 ) {
context.$textarea.scrollTop( IHateIE8.scrollTop );
context.$textarea.textSelection( 'setSelection', { start: IHateIE8.pos[ 0 ], end: IHateIE8.pos[ 1 ] } );
context.$textarea.data( 'IHateIE8', null );
}
}
},
/**
* Save text selection for old IE (<=10)
*/
saveSelection: function () {
if ( profile.name === 'msie' && document.selection && document.selection.createRange ) {
context.$textarea.focus();
context.savedSelection = document.selection.createRange();
}
},
/**
* Restore text selection for old IE (<=10)
*/
restoreSelection: function () {
if ( profile.name === 'msie' && context.savedSelection !== null ) {
context.$textarea.focus();
context.savedSelection.select();
context.savedSelection = null;
}
}
},
};
/**
* Save text selection for old IE (<=10)
* Workaround for a scrolling bug in IE8 (bug 61908)
*/
saveSelection: function () {
if ( profile.name === 'msie' && document.selection && document.selection.createRange ) {
context.$textarea.focus();
context.savedSelection = document.selection.createRange();
}
},
/**
* Restore text selection for old IE (<=10)
*/
restoreSelection: function () {
if ( profile.name === 'msie' && context.savedSelection !== null ) {
context.$textarea.focus();
context.savedSelection.select();
context.savedSelection = null;
}
if ( profile.name === 'msie' && profile.versionNumber === 8 ) {
context.$textarea.css( 'height', context.$textarea.height() );
context.$textarea.css( 'width', context.$textarea.parent().width() );
}
};
/**
* Workaround for a scrolling bug in IE8 (bug 61908)
*/
if ( profile.name === 'msie' && profile.versionNumber === 8 ) {
context.$textarea.css( 'height', context.$textarea.height() );
context.$textarea.css( 'width', context.$textarea.parent().width() );
/**
* Base UI Construction
*
* The UI is built from several containers, the outer-most being a div classed as "wikiEditor-ui". These containers
* provide a certain amount of "free" layout, but in some situations procedural layout is needed, which is performed
* as a response to the "resize" event.
*/
// Assemble a temporary div to place over the wikiEditor while it's being constructed
/* Disabling our loading div for now
var $loader = $( '<div>' )
.addClass( 'wikiEditor-ui-loading' )
.append( $( '<span>' + mediaWiki.msg( 'wikieditor-loading' ) + '</span>' )
.css( 'marginTop', context.$textarea.height() / 2 ) );
*/
/* Preserving cursor and focus state, which will get lost due to wrapAll */
var hasFocus = context.$textarea.is( ':focus' ),
cursorPos = context.$textarea.textSelection( 'getCaretPosition', { startAndEnd: true } );
// Encapsulate the textarea with some containers for layout
context.$textarea
/* Disabling our loading div for now
.after( $loader )
.add( $loader )
*/
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui' ) )
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui-view wikiEditor-ui-view-wikitext' ) )
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui-left' ) )
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui-bottom' ) )
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui-text' ) );
// Restore scroll position after this wrapAll (tracked by mediawiki.action.edit)
context.$textarea.prop( 'scrollTop', $( '#wpScrolltop' ).val() );
// Restore focus and cursor if needed
if ( hasFocus ) {
context.$textarea.focus();
context.$textarea.textSelection( 'setSelection', { start: cursorPos[ 0 ], end: cursorPos[ 1 ] } );
}
// Get references to some of the newly created containers
context.$ui = context.$textarea.parent().parent().parent().parent().parent();
context.$wikitext = context.$textarea.parent().parent().parent().parent();
// Add in tab and button containers
context.$wikitext
.before(
$( '<div>' ).addClass( 'wikiEditor-ui-controls' )
.append( $( '<div>' ).addClass( 'wikiEditor-ui-tabs' ).hide() )
.append( $( '<div>' ).addClass( 'wikiEditor-ui-buttons' ) )
)
.before( $( '<div>' ).addClass( 'wikiEditor-ui-clear' ) );
// Get references to some of the newly created containers
context.$controls = context.$ui.find( '.wikiEditor-ui-buttons' ).hide();
context.$buttons = context.$ui.find( '.wikiEditor-ui-buttons' );
context.$tabs = context.$ui.find( '.wikiEditor-ui-tabs' );
// Clear all floating after the UI
context.$ui.after( $( '<div>' ).addClass( 'wikiEditor-ui-clear' ) );
// Attach a right container
context.$wikitext.append( $( '<div>' ).addClass( 'wikiEditor-ui-right' ) );
context.$wikitext.append( $( '<div>' ).addClass( 'wikiEditor-ui-clear' ) );
// Attach a top container to the left pane
context.$wikitext.find( '.wikiEditor-ui-left' ).prepend( $( '<div>' ).addClass( 'wikiEditor-ui-top' ) );
// Setup the intial view
context.view = 'wikitext';
// Trigger the "resize" event anytime the window is resized
$( window ).resize( function ( event ) {
context.fn.trigger( 'resize', event );
} );
}
/**
* Base UI Construction
*
* The UI is built from several containers, the outer-most being a div classed as "wikiEditor-ui". These containers
* provide a certain amount of "free" layout, but in some situations procedural layout is needed, which is performed
* as a response to the "resize" event.
*/
/* API Execution */
// Assemble a temporary div to place over the wikiEditor while it's being constructed
/* Disabling our loading div for now
var $loader = $( '<div>' )
.addClass( 'wikiEditor-ui-loading' )
.append( $( '<span>' + mediaWiki.msg( 'wikieditor-loading' ) + '</span>' )
.css( 'marginTop', context.$textarea.height() / 2 ) );
*/
/* Preserving cursor and focus state, which will get lost due to wrapAll */
var hasFocus = context.$textarea.is( ':focus' ),
cursorPos = context.$textarea.textSelection( 'getCaretPosition', { startAndEnd: true } );
// Encapsulate the textarea with some containers for layout
context.$textarea
/* Disabling our loading div for now
.after( $loader )
.add( $loader )
*/
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui' ) )
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui-view wikiEditor-ui-view-wikitext' ) )
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui-left' ) )
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui-bottom' ) )
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui-text' ) );
// Restore scroll position after this wrapAll (tracked by mediawiki.action.edit)
context.$textarea.prop( 'scrollTop', $( '#wpScrolltop' ).val() );
// Restore focus and cursor if needed
if ( hasFocus ) {
context.$textarea.focus();
context.$textarea.textSelection( 'setSelection', { start: cursorPos[0], end: cursorPos[1] } );
}
// Since javascript gives arguments as an object, we need to convert them so they can be used more easily
var args = $.makeArray( arguments );
// Get references to some of the newly created containers
context.$ui = context.$textarea.parent().parent().parent().parent().parent();
context.$wikitext = context.$textarea.parent().parent().parent().parent();
// Add in tab and button containers
context.$wikitext
.before(
$( '<div>' ).addClass( 'wikiEditor-ui-controls' )
.append( $( '<div>' ).addClass( 'wikiEditor-ui-tabs' ).hide() )
.append( $( '<div>' ).addClass( 'wikiEditor-ui-buttons' ) )
)
.before( $( '<div>' ).addClass( 'wikiEditor-ui-clear' ) );
// Get references to some of the newly created containers
context.$controls = context.$ui.find( '.wikiEditor-ui-buttons' ).hide();
context.$buttons = context.$ui.find( '.wikiEditor-ui-buttons' );
context.$tabs = context.$ui.find( '.wikiEditor-ui-tabs' );
// Clear all floating after the UI
context.$ui.after( $( '<div>' ).addClass( 'wikiEditor-ui-clear' ) );
// Attach a right container
context.$wikitext.append( $( '<div>' ).addClass( 'wikiEditor-ui-right' ) );
context.$wikitext.append( $( '<div>' ).addClass( 'wikiEditor-ui-clear' ) );
// Attach a top container to the left pane
context.$wikitext.find( '.wikiEditor-ui-left' ).prepend( $( '<div>' ).addClass( 'wikiEditor-ui-top' ) );
// Setup the intial view
context.view = 'wikitext';
// Trigger the "resize" event anytime the window is resized
$( window ).resize( function ( event ) {
context.fn.trigger( 'resize', event );
} );
}
/* API Execution */
// Since javascript gives arguments as an object, we need to convert them so they can be used more easily
var args = $.makeArray( arguments );
// Dynamically setup core extensions for modules that are required
if ( args[0] === 'addModule' && typeof args[1] !== 'undefined' ) {
var modules = args[1];
if ( typeof modules !== 'object' ) {
modules = {};
modules[args[1]] = '';
}
for ( var module in modules ) {
// Only allow modules which are supported (and thus actually being turned on) affect the decision to extend
if ( module in $.wikiEditor.modules && $.wikiEditor.isSupported( $.wikiEditor.modules[module] ) ) {
// Activate all required core extensions on context
for ( var e in $.wikiEditor.extensions ) {
if (
$.wikiEditor.isRequired( $.wikiEditor.modules[module], e ) &&
$.inArray( e, context.extensions ) === -1
) {
context.extensions[context.extensions.length] = e;
$.wikiEditor.extensions[e]( context );
// Dynamically setup core extensions for modules that are required
if ( args[ 0 ] === 'addModule' && typeof args[ 1 ] !== 'undefined' ) {
var modules = args[ 1 ];
if ( typeof modules !== 'object' ) {
modules = {};
modules[ args[ 1 ] ] = '';
}
for ( var module in modules ) {
// Only allow modules which are supported (and thus actually being turned on) affect the decision to extend
if ( module in $.wikiEditor.modules && $.wikiEditor.isSupported( $.wikiEditor.modules[ module ] ) ) {
// Activate all required core extensions on context
for ( var e in $.wikiEditor.extensions ) {
if (
$.wikiEditor.isRequired( $.wikiEditor.modules[ module ], e ) &&
$.inArray( e, context.extensions ) === -1
) {
context.extensions[ context.extensions.length ] = e;
$.wikiEditor.extensions[ e ]( context );
}
}
break;
}
break;
}
}
}
// There would need to be some arguments if the API is being called
if ( args.length > 0 ) {
// Handle API calls
var call = args.shift();
if ( call in context.api ) {
context.api[call]( context, typeof args[0] === 'undefined' ? {} : args[0] );
// There would need to be some arguments if the API is being called
if ( args.length > 0 ) {
// Handle API calls
var call = args.shift();
if ( call in context.api ) {
context.api[ call ]( context, typeof args[ 0 ] === 'undefined' ? {} : args[ 0 ] );
}
}
}
// Store the context for next time, and support chaining
return $( this ).data( 'wikiEditor-context', context );
// Store the context for next time, and support chaining
return $( this ).data( 'wikiEditor-context', context );
};

View file

@ -3,170 +3,170 @@
/*jshint onevar:false */
$.wikiEditor.modules.preview = {
/**
* Compatability map
*/
browsers: {
// Left-to-right languages
ltr: {
msie: [['>=', 7]],
firefox: [['>=', 3]],
opera: [['>=', 9.6]],
safari: [['>=', 4]]
},
// Right-to-left languages
rtl: {
msie: [['>=', 8]],
firefox: [['>=', 3]],
opera: [['>=', 9.6]],
safari: [['>=', 4]]
}
},
/**
* Internally used functions
*/
fn: {
/**
* Creates a preview module within a wikiEditor
* @param context Context object of editor to create module in
* @param config Configuration object to create module from
* Compatability map
*/
create: function ( context ) {
var api = new mw.Api();
if ( 'initialized' in context.modules.preview ) {
return;
browsers: {
// Left-to-right languages
ltr: {
msie: [ [ '>=', 7 ] ],
firefox: [ [ '>=', 3 ] ],
opera: [ [ '>=', 9.6 ] ],
safari: [ [ '>=', 4 ] ]
},
// Right-to-left languages
rtl: {
msie: [ [ '>=', 8 ] ],
firefox: [ [ '>=', 3 ] ],
opera: [ [ '>=', 9.6 ] ],
safari: [ [ '>=', 4 ] ]
}
context.modules.preview = {
'initialized': true,
'previewText': null,
'changesText': null
};
context.modules.preview.$preview = context.fn.addView( {
'name': 'preview',
'titleMsg': 'wikieditor-preview-tab',
'init': function ( context ) {
// Gets the latest copy of the wikitext
var wikitext = context.$textarea.textSelection( 'getContents' );
// Aborts when nothing has changed since the last preview
if ( context.modules.preview.previewText === wikitext ) {
return;
}
context.modules.preview.$preview.find( '.wikiEditor-preview-contents' ).empty();
context.modules.preview.$preview.find( '.wikiEditor-preview-loading' ).show();
api.post( {
action: 'parse',
title: mw.config.get( 'wgPageName' ),
text: wikitext,
prop: 'text|modules',
pst: ''
} ).done( function ( data ) {
if ( !data.parse || !data.parse.text || data.parse.text['*'] === undefined ) {
},
/**
* Internally used functions
*/
fn: {
/**
* Creates a preview module within a wikiEditor
*
* @param {Object} context Context object of editor to create module in
*/
create: function ( context ) {
var api = new mw.Api();
if ( 'initialized' in context.modules.preview ) {
return;
}
context.modules.preview = {
initialized: true,
previewText: null,
changesText: null
};
context.modules.preview.$preview = context.fn.addView( {
name: 'preview',
titleMsg: 'wikieditor-preview-tab',
init: function ( context ) {
// Gets the latest copy of the wikitext
var wikitext = context.$textarea.textSelection( 'getContents' );
// Aborts when nothing has changed since the last preview
if ( context.modules.preview.previewText === wikitext ) {
return;
}
context.modules.preview.previewText = wikitext;
context.modules.preview.$preview.find( '.wikiEditor-preview-loading' ).hide();
context.modules.preview.$preview.find( '.wikiEditor-preview-contents' )
.html( data.parse.text['*'] )
.append( '<div class="visualClear"></div>' )
.find( 'a:not([href^=#])' )
.click( false );
var loadmodules = data.parse.modules.concat(
data.parse.modulescripts,
data.parse.modulestyles
);
mw.loader.load( loadmodules );
} );
}
} );
context.$changesTab = context.fn.addView( {
'name': 'changes',
'titleMsg': 'wikieditor-preview-changes-tab',
'init': function ( context ) {
// Gets the latest copy of the wikitext
var wikitext = context.$textarea.textSelection( 'getContents' );
// Aborts when nothing has changed since the last time
if ( context.modules.preview.changesText === wikitext ) {
return;
}
context.$changesTab.find( 'table.diff tbody' ).empty();
context.$changesTab.find( '.wikiEditor-preview-loading' ).show();
// Call the API. First PST the input, then diff it
api.post( {
action: 'parse',
title: mw.config.get( 'wgPageName' ),
onlypst: '',
text: wikitext
} ).done( function ( data ) {
try {
var postdata2 = {
action: 'query',
indexpageids: '',
prop: 'revisions',
titles: mw.config.get( 'wgPageName' ),
rvdifftotext: data.parse.text['*'],
rvprop: ''
};
var section = $( '[name="wpSection"]' ).val();
if ( section !== '' ) {
postdata2.rvsection = section;
context.modules.preview.$preview.find( '.wikiEditor-preview-contents' ).empty();
context.modules.preview.$preview.find( '.wikiEditor-preview-loading' ).show();
api.post( {
action: 'parse',
title: mw.config.get( 'wgPageName' ),
text: wikitext,
prop: 'text|modules',
pst: ''
} ).done( function ( data ) {
if ( !data.parse || !data.parse.text || data.parse.text[ '*' ] === undefined ) {
return;
}
api.post( postdata2 )
.done( function ( data ) {
// Add diff CSS
mw.loader.load( 'mediawiki.action.history.diff' );
try {
var diff = data.query.pages[data.query.pageids[0]]
.revisions[0].diff['*'];
context.modules.preview.previewText = wikitext;
context.modules.preview.$preview.find( '.wikiEditor-preview-loading' ).hide();
context.modules.preview.$preview.find( '.wikiEditor-preview-contents' )
.html( data.parse.text[ '*' ] )
.append( '<div class="visualClear"></div>' )
.find( 'a:not([href^=#])' )
.click( false );
context.$changesTab.find( 'table.diff tbody' )
.html( diff )
.append( '<div class="visualClear"></div>' );
context.modules.preview.changesText = wikitext;
} catch ( e ) {
// "data.blah is undefined" error, ignore
}
context.$changesTab.find( '.wikiEditor-preview-loading' ).hide();
} );
} catch ( e ) {
// "data.blah is undefined" error, ignore
var loadmodules = data.parse.modules.concat(
data.parse.modulescripts,
data.parse.modulestyles
);
mw.loader.load( loadmodules );
} );
}
} );
context.$changesTab = context.fn.addView( {
name: 'changes',
titleMsg: 'wikieditor-preview-changes-tab',
init: function ( context ) {
// Gets the latest copy of the wikitext
var wikitext = context.$textarea.textSelection( 'getContents' );
// Aborts when nothing has changed since the last time
if ( context.modules.preview.changesText === wikitext ) {
return;
}
} );
}
} );
context.$changesTab.find( 'table.diff tbody' ).empty();
context.$changesTab.find( '.wikiEditor-preview-loading' ).show();
var loadingMsg = mw.msg( 'wikieditor-preview-loading' );
context.modules.preview.$preview
.add( context.$changesTab )
.append( $( '<div>' )
.addClass( 'wikiEditor-preview-loading' )
.append( $( '<img>' )
.addClass( 'wikiEditor-preview-spinner' )
.attr( {
'src': $.wikiEditor.imgPath + 'dialogs/loading.gif',
'valign': 'absmiddle',
'alt': loadingMsg,
'title': loadingMsg
} )
// Call the API. First PST the input, then diff it
api.post( {
action: 'parse',
title: mw.config.get( 'wgPageName' ),
onlypst: '',
text: wikitext
} ).done( function ( data ) {
try {
var postdata2 = {
action: 'query',
indexpageids: '',
prop: 'revisions',
titles: mw.config.get( 'wgPageName' ),
rvdifftotext: data.parse.text[ '*' ],
rvprop: ''
};
var section = $( '[name="wpSection"]' ).val();
if ( section !== '' ) {
postdata2.rvsection = section;
}
api.post( postdata2 )
.done( function ( data ) {
// Add diff CSS
mw.loader.load( 'mediawiki.action.history.diff' );
try {
var diff = data.query.pages[ data.query.pageids[ 0 ] ]
.revisions[ 0 ].diff[ '*' ];
context.$changesTab.find( 'table.diff tbody' )
.html( diff )
.append( '<div class="visualClear"></div>' );
context.modules.preview.changesText = wikitext;
} catch ( e ) {
// "data.blah is undefined" error, ignore
}
context.$changesTab.find( '.wikiEditor-preview-loading' ).hide();
} );
} catch ( e ) {
// "data.blah is undefined" error, ignore
}
} );
}
} );
var loadingMsg = mw.msg( 'wikieditor-preview-loading' );
context.modules.preview.$preview
.add( context.$changesTab )
.append( $( '<div>' )
.addClass( 'wikiEditor-preview-loading' )
.append( $( '<img>' )
.addClass( 'wikiEditor-preview-spinner' )
.attr( {
src: $.wikiEditor.imgPath + 'dialogs/loading.gif',
valign: 'absmiddle',
alt: loadingMsg,
title: loadingMsg
} )
)
.append(
$( '<span>' ).text( loadingMsg )
)
)
.append(
$( '<span>' ).text( loadingMsg )
)
)
.append( $( '<div>' )
.addClass( 'wikiEditor-preview-contents' )
);
context.$changesTab.find( '.wikiEditor-preview-contents' )
.html( '<table class="diff"><col class="diff-marker"/><col class="diff-content"/>' +
'<col class="diff-marker"/><col class="diff-content"/><tbody/></table>' );
.append( $( '<div>' )
.addClass( 'wikiEditor-preview-contents' )
);
context.$changesTab.find( '.wikiEditor-preview-contents' )
.html( '<table class="diff"><col class="diff-marker"/><col class="diff-content"/>' +
'<col class="diff-marker"/><col class="diff-content"/><tbody/></table>' );
}
}
}
};

View file

@ -4,159 +4,160 @@
$.wikiEditor.modules.publish = {
/**
* Compatability map
*/
browsers: {
// Left-to-right languages
ltr: {
msie: [['>=', 7]],
firefox: [['>=', 3]],
opera: [['>=', 9.6]],
safari: [['>=', 4]]
},
// Right-to-left languages
rtl: {
msie: [['>=', 8]],
firefox: [['>=', 3]],
opera: [['>=', 9.6]],
safari: [['>=', 4]]
}
},
/**
* Internally used functions
*/
fn: {
/**
* Creates a publish module within a wikiEditor
* @param context Context object of editor to create module in
* @param config Configuration object to create module from
* Compatability map
*/
create: function ( context ) {
// Build the dialog behind the Publish button
var dialogID = 'wikiEditor-' + context.instance + '-dialog';
$.wikiEditor.modules.dialogs.fn.create(
context,
{
previewsave: {
id: dialogID,
titleMsg: 'wikieditor-publish-dialog-title',
html: '\
<div class="wikiEditor-publish-dialog-copywarn"></div>\
<div class="wikiEditor-publish-dialog-editoptions">\
<form id="wikieditor-' + context.instance + '-publish-dialog-form">\
<div class="wikiEditor-publish-dialog-summary">\
<label for="wikiEditor-' + context.instance + '-dialog-summary"\
rel="wikieditor-publish-dialog-summary"></label>\
<br />\
<input type="text" id="wikiEditor-' + context.instance + '-dialog-summary"\
style="width: 100%;" />\
</div>\
<div class="wikiEditor-publish-dialog-options">\
<input type="checkbox"\
id="wikiEditor-' + context.instance + '-dialog-minor" />\
<label for="wikiEditor-' + context.instance + '-dialog-minor"\
rel="wikieditor-publish-dialog-minor"></label>\
<input type="checkbox"\
id="wikiEditor-' + context.instance + '-dialog-watch" />\
<label for="wikiEditor-' + context.instance + '-dialog-watch"\
rel="wikieditor-publish-dialog-watch"></label>\
</div>\
</form>\
</div>',
init: function () {
var i;
browsers: {
// Left-to-right languages
ltr: {
msie: [ [ '>=', 7 ] ],
firefox: [ [ '>=', 3 ] ],
opera: [ [ '>=', 9.6 ] ],
safari: [ [ '>=', 4 ] ]
},
// Right-to-left languages
rtl: {
msie: [ [ '>=', 8 ] ],
firefox: [ [ '>=', 3 ] ],
opera: [ [ '>=', 9.6 ] ],
safari: [ [ '>=', 4 ] ]
}
},
$( this ).find( '[rel]' ).each( function () {
$( this ).text( mediaWiki.msg( $( this ).attr( 'rel' ) ) );
} );
/**
* Internally used functions
*/
fn: {
/**
* Creates a publish module within a wikiEditor
*
* @param {Object} context Context object of editor to create module in
*/
create: function ( context ) {
// Build the dialog behind the Publish button
var dialogID = 'wikiEditor-' + context.instance + '-dialog';
$.wikiEditor.modules.dialogs.fn.create(
context,
{
previewsave: {
id: dialogID,
titleMsg: 'wikieditor-publish-dialog-title',
html: '\
<div class="wikiEditor-publish-dialog-copywarn"></div>\
<div class="wikiEditor-publish-dialog-editoptions">\
<form id="wikieditor-' + context.instance + '-publish-dialog-form">\
<div class="wikiEditor-publish-dialog-summary">\
<label for="wikiEditor-' + context.instance + '-dialog-summary"\
rel="wikieditor-publish-dialog-summary"></label>\
<br />\
<input type="text" id="wikiEditor-' + context.instance + '-dialog-summary"\
style="width: 100%;" />\
</div>\
<div class="wikiEditor-publish-dialog-options">\
<input type="checkbox"\
id="wikiEditor-' + context.instance + '-dialog-minor" />\
<label for="wikiEditor-' + context.instance + '-dialog-minor"\
rel="wikieditor-publish-dialog-minor"></label>\
<input type="checkbox"\
id="wikiEditor-' + context.instance + '-dialog-watch" />\
<label for="wikiEditor-' + context.instance + '-dialog-watch"\
rel="wikieditor-publish-dialog-watch"></label>\
</div>\
</form>\
</div>',
init: function () {
var i;
/* REALLY DIRTY HACK! */
// Reformat the copyright warning stuff, if available
if ( $( '#editpage-copywarn p' ).length ) {
var copyWarnHTML = $( '#editpage-copywarn p' ).html();
// TODO: internationalize by splitting on other characters that end statements
var copyWarnStatements = copyWarnHTML.split( '. ' );
var newCopyWarnHTML = '<ul>';
for ( i = 0; i < copyWarnStatements.length; i++ ) {
if ( copyWarnStatements[i] !== '' ) {
var copyWarnStatement = $.trim( copyWarnStatements[i] ).replace( /\.*$/, '' );
newCopyWarnHTML += '<li>' + copyWarnStatement + '.</li>';
$( this ).find( '[rel]' ).each( function () {
$( this ).text( mediaWiki.msg( $( this ).attr( 'rel' ) ) );
} );
/* REALLY DIRTY HACK! */
// Reformat the copyright warning stuff, if available
if ( $( '#editpage-copywarn p' ).length ) {
var copyWarnHTML = $( '#editpage-copywarn p' ).html();
// TODO: internationalize by splitting on other characters that end statements
var copyWarnStatements = copyWarnHTML.split( '. ' );
var newCopyWarnHTML = '<ul>';
for ( i = 0; i < copyWarnStatements.length; i++ ) {
if ( copyWarnStatements[ i ] !== '' ) {
var copyWarnStatement = $.trim( copyWarnStatements[ i ] ).replace( /\.*$/, '' );
newCopyWarnHTML += '<li>' + copyWarnStatement + '.</li>';
}
}
newCopyWarnHTML += '</ul>';
// No list if there's only one element
$( this ).find( '.wikiEditor-publish-dialog-copywarn' ).html(
copyWarnStatements.length > 1 ? newCopyWarnHTML : copyWarnHTML
);
}
newCopyWarnHTML += '</ul>';
// No list if there's only one element
$( this ).find( '.wikiEditor-publish-dialog-copywarn' ).html(
copyWarnStatements.length > 1 ? newCopyWarnHTML : copyWarnHTML
);
}
/* END OF REALLY DIRTY HACK */
/* END OF REALLY DIRTY HACK */
if ( $( '#wpMinoredit' ).length === 0 ) {
$( '#wikiEditor-' + context.instance + '-dialog-minor' ).hide();
} else if ( $( '#wpMinoredit' ).prop( 'checked' ) ) {
$( '#wikiEditor-' + context.instance + '-dialog-minor' )
.prop( 'checked', true );
}
if ( $( '#wpWatchthis' ).length === 0 ) {
$( '#wikiEditor-' + context.instance + '-dialog-watch' ).hide();
} else if ( $( '#wpWatchthis' ).prop( 'checked' ) ) {
$( '#wikiEditor-' + context.instance + '-dialog-watch' )
.prop( 'checked', true );
if ( $( '#wpMinoredit' ).length === 0 ) {
$( '#wikiEditor-' + context.instance + '-dialog-minor' ).hide();
} else if ( $( '#wpMinoredit' ).prop( 'checked' ) ) {
$( '#wikiEditor-' + context.instance + '-dialog-minor' )
.prop( 'checked', true );
}
if ( $( '#wpWatchthis' ).length === 0 ) {
$( '#wikiEditor-' + context.instance + '-dialog-watch' ).hide();
} else if ( $( '#wpWatchthis' ).prop( 'checked' ) ) {
$( '#wikiEditor-' + context.instance + '-dialog-watch' )
.prop( 'checked', true );
}
$( this ).find( 'form' ).submit( function ( e ) {
$( this ).closest( '.ui-dialog' ).find( 'button:first' ).click();
e.preventDefault();
} );
},
immediateCreate: true,
dialog: {
buttons: {
'wikieditor-publish-dialog-publish': function () {
var minorChecked = $( '#wikiEditor-' + context.instance +
'-dialog-minor' ).is( ':checked' ) ?
'checked' : '';
var watchChecked = $( '#wikiEditor-' + context.instance +
'-dialog-watch' ).is( ':checked' ) ?
'checked' : '';
$( '#wpMinoredit' ).prop( 'checked', minorChecked );
$( '#wpWatchthis' ).prop( 'checked', watchChecked );
$( '#wpSummary' ).val( $( '#wikiEditor-' + context.instance +
'-dialog-summary' ).val() );
$( '#editform' ).submit();
$( this ).find( 'form' ).submit( function ( e ) {
$( this ).closest( '.ui-dialog' ).find( 'button:first' ).click();
e.preventDefault();
} );
},
immediateCreate: true,
dialog: {
buttons: {
'wikieditor-publish-dialog-publish': function () {
var minorChecked = $( '#wikiEditor-' + context.instance +
'-dialog-minor' ).is( ':checked' ) ?
'checked' : '';
var watchChecked = $( '#wikiEditor-' + context.instance +
'-dialog-watch' ).is( ':checked' ) ?
'checked' : '';
$( '#wpMinoredit' ).prop( 'checked', minorChecked );
$( '#wpWatchthis' ).prop( 'checked', watchChecked );
$( '#wpSummary' ).val( $( '#wikiEditor-' + context.instance +
'-dialog-summary' ).val() );
$( '#editform' ).submit();
},
'wikieditor-publish-dialog-goback': function () {
$( this ).dialog( 'close' );
}
},
'wikieditor-publish-dialog-goback': function () {
$( this ).dialog( 'close' );
}
open: function () {
$( '#wikiEditor-' + context.instance + '-dialog-summary' ).focus();
},
width: 500
},
open: function () {
$( '#wikiEditor-' + context.instance + '-dialog-summary' ).focus();
},
width: 500
},
resizeme: false
resizeme: false
}
}
}
);
);
context.fn.addButton( {
'captionMsg': 'wikieditor-publish-button-publish',
'action': function () {
$( '#' + dialogID ).dialog( 'open' );
return false;
}
} );
context.fn.addButton( {
captionMsg: 'wikieditor-publish-button-publish',
action: function () {
$( '#' + dialogID ).dialog( 'open' );
return false;
}
} );
context.fn.addButton( {
'captionMsg': 'wikieditor-publish-button-cancel',
'action': function () {
window.location.href = $( '#mw-editform-cancel' ).attr( 'href' );
return false;
}
} );
context.fn.addButton( {
captionMsg: 'wikieditor-publish-button-cancel',
action: function () {
window.location.href = $( '#mw-editform-cancel' ).attr( 'href' );
return false;
}
} );
}
}
}
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,8 @@
"grunt": "0.4.5",
"grunt-cli": "0.1.13",
"grunt-banana-checker": "0.2.2",
"grunt-jsonlint": "1.0.4"
"grunt-jsonlint": "1.0.4",
"grunt-contrib-jshint": "0.11.3",
"grunt-jscs": "2.3.0"
}
}

View file

@ -78,7 +78,7 @@
label: 'Icons',
type: 'select',
list: {
wink : {
wink: {
label: 'Wink',
action: {
type: 'encapsulate',
@ -87,7 +87,7 @@
}
}
},
frown : {
frown: {
label: 'Frown',
action: {
type: 'encapsulate',
@ -96,7 +96,7 @@
}
}
},
bigSmile : {
bigSmile: {
label: 'Big smile',
action: {
type: 'encapsulate',
@ -178,23 +178,23 @@
data = {
section: 'info',
page: 'colors',
rows: [
{
name: { text: 'Red' },
temp: { text: 'Warm' },
swatch: { html: '<div style="width: 10px; height: 10px; background-color: red;">' }
},
{
name: { text: 'Blue' },
temp: { text: 'Cold' },
swatch: { html: '<div style="width: 10px; height: 10px; background-color: blue;">' }
},
{
name: { text: 'Silver' },
temp: { text: 'Neutral' },
swatch: { html: '<div style="width: 10px; height: 10px; background-color: silver;">' }
}
]
rows: [
{
name: { text: 'Red' },
temp: { text: 'Warm' },
swatch: { html: '<div style="width: 10px; height: 10px; background-color: red;">' }
},
{
name: { text: 'Blue' },
temp: { text: 'Cold' },
swatch: { html: '<div style="width: 10px; height: 10px; background-color: blue;">' }
},
{
name: { text: 'Silver' },
temp: { text: 'Neutral' },
swatch: { html: '<div style="width: 10px; height: 10px; background-color: silver;">' }
}
]
};
assert.equal( this.$ui.find( '*[rel="info"].section *[rel="colors"].page tr td' ).length, 0, 'Before adding table rows' );
this.$target.wikiEditor( 'addToToolbar', data );