mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/WikiEditor
synced 2024-11-27 17:50:44 +00:00
WikiEditor: Linting and conventions
* Code clean up in preparation for enabling linting in the future * Update code to use latest code conventions and best practices: - Make use of jQuery.Event (e.g. no need to check both e.keyCode and e.which) - jQuery: .size() -> .length - jQuery: (where appropiate) .attr() -> .prop() Setting properties like 'checked' via attr() has been deprecated in jQuery. - Whitespace - Single quotes instead of double quotes - Use literal keys in object literals instead of strings - Pass mediaWiki to closure, use mw. locally instead of "mediaWiki" global directly. - Fix indentation - Brackets around if, else and for bodies - Strict comparison to 0, null, false, true etc. - Fix missing radix parameter in parseInt - Use local $ instead of global $ - Use `foo || bar` instead of `foo ? foo : bar` - Variable scope hoisting - Double/redundant variable declarations - ['foo'] is better written in dot notation - New line at EOF - Consistency in jQuery construction: Tag name for element creation $( '<div>' ) Valid html for html parsing $( '<div foo="bar"></div>' ) - Fix regex escape warnings per JSLint/JSHint. Do escape ][, don't escape >< - .. * Add .jshintrc / .jshintignore * Updated most files, but not all. Too much at once. Change-Id: I445639b25a9688b3cdf9e5449e3d31cbcfa9c7ae
This commit is contained in:
parent
955ee768ca
commit
7721909f9f
2
.jshintignore
Normal file
2
.jshintignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
# upstream lib from Google
|
||||
modules/contentCollector.js
|
9
.jshintrc
Normal file
9
.jshintrc
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"predef": [
|
||||
"mediaWiki",
|
||||
"jQuery"
|
||||
],
|
||||
"browser": true,
|
||||
"smarttabs": true,
|
||||
"multistr": true
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* CSS for WikiEditor
|
||||
*/
|
||||
|
||||
|
@ -7,10 +7,13 @@ form#editform {
|
|||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* These IDs (#wpSummaryLabel and #wpSummary) could change in MediaWiki */
|
||||
#wpSummary, #wpSummaryLabel {
|
||||
#wpSummary,
|
||||
#wpSummaryLabel {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
/* This ID (#wpTextbox1) could change in MediaWiki */
|
||||
.wikiEditor-ui textarea#wpTextbox1 {
|
||||
border: none;
|
||||
|
@ -19,6 +22,7 @@ form#editform {
|
|||
line-height: 1.5em;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.wikiEditor-ui .wikiEditor-ui-text > textarea#wpTextbox1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
|
@ -12,4 +12,4 @@ $( document ).ready( function() {
|
|||
|
||||
// Add dialogs module
|
||||
$( '#wpTextbox1' ).wikiEditor( 'addModule', $.wikiEditor.modules.dialogs.config.getDefaultConfig() );
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
* JavaScript for WikiEditor Template Editor
|
||||
*/
|
||||
|
||||
$( document ).ready( function() {
|
||||
$( document ).ready( function () {
|
||||
// Disable in template namespace
|
||||
if ( mw.config.get( 'wgNamespaceNumber' ) == 10 ) {
|
||||
if ( mw.config.get( 'wgNamespaceNumber' ) === 10 ) {
|
||||
return true;
|
||||
}
|
||||
// Add template editor module
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
* JavaScript for WikiEditor Templates
|
||||
*/
|
||||
|
||||
$( document ).ready( function() {
|
||||
$( document ).ready( function () {
|
||||
// Disable for template namespace
|
||||
if ( mw.config.get( 'wgNamespaceNumber' ) == 10 ) {
|
||||
if ( mw.config.get( 'wgNamespaceNumber' ) === 10 ) {
|
||||
return true;
|
||||
}
|
||||
// Add templates module
|
||||
$( '#wpTextbox1' ).wikiEditor( 'addModule', 'templates' );
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
var textareaId = '#wpTextbox1';
|
||||
var wikiEditorTests = {
|
||||
// Add emoticons section
|
||||
'add_sections_toolbar': {
|
||||
'call': 'addToToolbar',
|
||||
'data': {
|
||||
add_sections_toolbar: {
|
||||
call: 'addToToolbar',
|
||||
data: {
|
||||
'sections': {
|
||||
'emoticons': {
|
||||
'type': 'toolbar',
|
||||
|
@ -14,30 +14,30 @@ var wikiEditorTests = {
|
|||
}
|
||||
}
|
||||
},
|
||||
'test': '*[rel=emoticons].section',
|
||||
'pre': 0,
|
||||
'post': 1
|
||||
test: '*[rel=emoticons].section',
|
||||
pre: 0,
|
||||
post: 1
|
||||
},
|
||||
// Add faces group to emoticons section
|
||||
'add_groups': {
|
||||
'call': 'addToToolbar',
|
||||
'data': {
|
||||
'section': 'emoticons',
|
||||
call: 'addToToolbar',
|
||||
data: {
|
||||
section: 'emoticons',
|
||||
'groups': {
|
||||
'faces': {
|
||||
'label': 'Faces'
|
||||
}
|
||||
}
|
||||
},
|
||||
'test': '*[rel=emoticons].section *[rel=faces].group',
|
||||
'pre': 0,
|
||||
'post': 1
|
||||
test: '*[rel=emoticons].section *[rel=faces].group',
|
||||
pre: 0,
|
||||
post: 1
|
||||
},
|
||||
// Add smile tool to faces group of emoticons section
|
||||
'add_tools': {
|
||||
'call': 'addToToolbar',
|
||||
'data': {
|
||||
'section': 'emoticons',
|
||||
call: 'addToToolbar',
|
||||
data: {
|
||||
section: 'emoticons',
|
||||
'group': 'faces',
|
||||
'tools': {
|
||||
'smile': {
|
||||
|
@ -47,20 +47,20 @@ var wikiEditorTests = {
|
|||
action: {
|
||||
type: 'encapsulate',
|
||||
options: {
|
||||
pre: ":)"
|
||||
pre: ':)'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'test': '*[rel=emoticons].section *[rel=faces].group *[rel=smile].tool',
|
||||
'pre': 0,
|
||||
'post': 1
|
||||
test: '*[rel=emoticons].section *[rel=faces].group *[rel=smile].tool',
|
||||
pre: 0,
|
||||
post: 1
|
||||
},
|
||||
// Add info section
|
||||
'add_sections_booklet': {
|
||||
'call': 'addToToolbar',
|
||||
'data': {
|
||||
call: 'addToToolbar',
|
||||
data: {
|
||||
'sections': {
|
||||
'info': {
|
||||
'type': 'booklet',
|
||||
|
@ -68,16 +68,16 @@ var wikiEditorTests = {
|
|||
}
|
||||
}
|
||||
},
|
||||
'test': '*[rel=info].section',
|
||||
'pre': 0,
|
||||
'post': 1
|
||||
test: '*[rel=info].section',
|
||||
pre: 0,
|
||||
post: 1
|
||||
},
|
||||
// Add info section
|
||||
'add_pages_table': {
|
||||
'call': 'addToToolbar',
|
||||
'data': {
|
||||
'section': 'info',
|
||||
'pages': {
|
||||
call: 'addToToolbar',
|
||||
data: {
|
||||
section: 'info',
|
||||
pages: {
|
||||
'colors': {
|
||||
'layout': 'table',
|
||||
'label': 'Colors',
|
||||
|
@ -89,44 +89,44 @@ var wikiEditorTests = {
|
|||
}
|
||||
}
|
||||
},
|
||||
'test': '*[rel=info].section *[rel=colors].page',
|
||||
'pre': 0,
|
||||
'post': 1
|
||||
test: '*[rel=info].section *[rel=colors].page',
|
||||
pre: 0,
|
||||
post: 1
|
||||
},
|
||||
// Add colors rows
|
||||
'add_rows': {
|
||||
'call': 'addToToolbar',
|
||||
'data': {
|
||||
'section': 'info',
|
||||
'page': 'colors',
|
||||
call: 'addToToolbar',
|
||||
data: {
|
||||
section: 'info',
|
||||
page: 'colors',
|
||||
'rows': [
|
||||
{
|
||||
'name': { text: 'Red' },
|
||||
'temp': { text: 'Warm' },
|
||||
'swatch': { html: '<div style="width:10px;height:10px;background-color:red;">' }
|
||||
'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;">' }
|
||||
'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;">' }
|
||||
'swatch': { html: '<div style="width: 10px; height: 10px; background-color: silver;">' }
|
||||
}
|
||||
]
|
||||
},
|
||||
'test': '*[rel=info].section *[rel=colors].page tr td',
|
||||
'pre': 0,
|
||||
'post': 9
|
||||
test: '*[rel=info].section *[rel=colors].page tr td',
|
||||
pre: 0,
|
||||
post: 9
|
||||
},
|
||||
// Add
|
||||
'add_pages_characters': {
|
||||
'call': 'addToToolbar',
|
||||
'data': {
|
||||
'section': 'info',
|
||||
'pages': {
|
||||
call: 'addToToolbar',
|
||||
data: {
|
||||
section: 'info',
|
||||
pages: {
|
||||
'emoticons': {
|
||||
'layout': 'characters',
|
||||
'label': 'Emoticons'
|
||||
|
@ -137,110 +137,118 @@ var wikiEditorTests = {
|
|||
}
|
||||
}
|
||||
},
|
||||
'test': '*[rel=info].section *[rel=emoticons].page',
|
||||
'pre': 0,
|
||||
'post': 1
|
||||
test: '*[rel=info].section *[rel=emoticons].page',
|
||||
pre: 0,
|
||||
post: 1
|
||||
},
|
||||
// Add
|
||||
'add_characters': {
|
||||
'call': 'addToToolbar',
|
||||
'data': {
|
||||
'section': 'info',
|
||||
'page': 'emoticons',
|
||||
'characters': [ ':)', ':))', ':(', '<3', ';)' ]
|
||||
call: 'addToToolbar',
|
||||
data: {
|
||||
section: 'info',
|
||||
page: 'emoticons',
|
||||
characters: [ ':)', ':))', ':(', '<3', ';)' ]
|
||||
},
|
||||
'test': '*[rel=info].section *[rel=emoticons].page *[rel=":)"]',
|
||||
'pre': 0,
|
||||
'post': 1
|
||||
test: '*[rel=info].section *[rel=emoticons].page *[rel=":)"]',
|
||||
pre: 0,
|
||||
post: 1
|
||||
},
|
||||
// Remove page
|
||||
'remove_page': {
|
||||
'call': 'removeFromToolbar',
|
||||
'data': {
|
||||
'section': 'info',
|
||||
'page': 'removeme'
|
||||
call: 'removeFromToolbar',
|
||||
data: {
|
||||
section: 'info',
|
||||
page: 'removeme'
|
||||
},
|
||||
'test': '*[rel=info].section *[rel=removeme].page',
|
||||
'pre': 1,
|
||||
'post': 0
|
||||
test: '*[rel=info].section *[rel=removeme].page',
|
||||
pre: 1,
|
||||
post: 0
|
||||
},
|
||||
// Remove :)) from emoticon characters
|
||||
'remove_character': {
|
||||
'call': 'removeFromToolbar',
|
||||
'data': {
|
||||
'section': 'info',
|
||||
'page': 'emoticons',
|
||||
call: 'removeFromToolbar',
|
||||
data: {
|
||||
section: 'info',
|
||||
page: 'emoticons',
|
||||
'character': ':))'
|
||||
},
|
||||
'test': '*[rel=info].section *[rel=emoticons].page *[rel=":))"]',
|
||||
'pre': 1,
|
||||
'post': 0
|
||||
test: '*[rel=info].section *[rel=emoticons].page *[rel=":))"]',
|
||||
pre: 1,
|
||||
post: 0
|
||||
},
|
||||
// Remove row from colors table of info section
|
||||
'remove_row': {
|
||||
'call': 'removeFromToolbar',
|
||||
'data': {
|
||||
'section': 'info',
|
||||
'page': 'colors',
|
||||
call: 'removeFromToolbar',
|
||||
data: {
|
||||
section: 'info',
|
||||
page: 'colors',
|
||||
'row': 0
|
||||
},
|
||||
'test': '*[rel=info].section *[rel=colors].page tr td',
|
||||
'pre': 9,
|
||||
'post': 6
|
||||
test: '*[rel=info].section *[rel=colors].page tr td',
|
||||
pre: 9,
|
||||
post: 6
|
||||
}
|
||||
};
|
||||
$(document).ready( function() {
|
||||
var button = $( '<button>Run wikiEditor Tests!</button>' )
|
||||
|
||||
jQuery(document).ready( function ( $ ) {
|
||||
var $button = $( '<button>Run wikiEditor Tests!</button>' )
|
||||
.css( {
|
||||
'position': 'fixed',
|
||||
'bottom': 0,
|
||||
'right': 0,
|
||||
'width': '100%',
|
||||
'backgroundColor': '#333333',
|
||||
'opacity': 0.75,
|
||||
'color': '#DDDDDD',
|
||||
'padding': '0.5em',
|
||||
'border': 'none',
|
||||
'display': 'none'
|
||||
position: 'fixed',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
width: '100%',
|
||||
backgroundColor: '#333',
|
||||
opacity: 0.75,
|
||||
color: '#DDDDDD',
|
||||
padding: '0.7em',
|
||||
border: 'none',
|
||||
display: 'none'
|
||||
} )
|
||||
.click( function() {
|
||||
if ( $(this).attr( 'enabled' ) == 'false' ) {
|
||||
.click( function () {
|
||||
if ( $(this).data( 'testDone' ) ) {
|
||||
$(this).slideUp( 'fast' );
|
||||
return false;
|
||||
}
|
||||
var messages = [ 'Running tests for wikiEditor API' ];
|
||||
var $target = $( textareaId );
|
||||
var $ui = $target.data( 'wikiEditor-context' ).$ui;
|
||||
var passes = 0;
|
||||
var tests = 0;
|
||||
for ( var test in wikiEditorTests ) {
|
||||
var pre = $ui.find( wikiEditorTests[test].test ).size() ==
|
||||
wikiEditorTests[test].pre;
|
||||
|
||||
var test, pre, post,
|
||||
messages = [ 'Running tests for wikiEditor API' ],
|
||||
$target = $( textareaId ),
|
||||
$ui = $target.data( 'wikiEditor-context' ).$ui,
|
||||
passes = 0,
|
||||
tests = 0;
|
||||
|
||||
for ( test in wikiEditorTests ) {
|
||||
pre = $ui.find( wikiEditorTests[test].test ).length === wikiEditorTests[test].pre;
|
||||
messages.push ( test + '-pre: ' + ( pre ? 'PASS' : 'FAIL' ) );
|
||||
$target.wikiEditor(
|
||||
wikiEditorTests[test].call,
|
||||
wikiEditorTests[test].data
|
||||
);
|
||||
var post = $ui.find( wikiEditorTests[test].test ).size() ==
|
||||
wikiEditorTests[test].post;
|
||||
post = $ui.find( wikiEditorTests[test].test ).length === wikiEditorTests[test].post;
|
||||
messages.push ( test + '-post: ' + ( post ? 'PASS' : 'FAIL' ) );
|
||||
if ( pre && post ) {
|
||||
passes++;
|
||||
}
|
||||
tests++;
|
||||
}
|
||||
if ( window.console !== undefined ) {
|
||||
|
||||
if ( window.console ) {
|
||||
for ( var i = 0; i < messages.length; i++ ) {
|
||||
console.log( messages[i] );
|
||||
window.console.log( messages[i] );
|
||||
}
|
||||
}
|
||||
|
||||
$(this)
|
||||
.attr( 'title', messages.join( " | " ) )
|
||||
.text( passes + ' / ' + tests + ' were successful' )
|
||||
.css( 'backgroundColor', passes < tests ? 'red' : 'green' )
|
||||
.attr( 'enabled', 'false' )
|
||||
.data( 'testDone', 'true' )
|
||||
.blur();
|
||||
} )
|
||||
.appendTo( $( 'body' ) );
|
||||
setTimeout( function() { button.slideDown( 'fast' ) }, 2000 );
|
||||
|
||||
setTimeout( function () {
|
||||
$button.slideDown( 'fast' );
|
||||
}, 1500 );
|
||||
|
||||
} );
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,56 +1,68 @@
|
|||
/*
|
||||
/**
|
||||
* CSS for WikiEditor Dialogs jQuery plugin
|
||||
*/
|
||||
|
||||
.wikiEditor-toolbar-dialog table {
|
||||
margin-top: 0.75em;
|
||||
}
|
||||
|
||||
.wikiEditor-toolbar-dialog table td {
|
||||
padding: 0.5em;
|
||||
height: 3em;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Put suggestions (default z-index 99) on top of dialogs (z-index 1002) */
|
||||
div.suggestions {
|
||||
z-index: 1099;
|
||||
}
|
||||
|
||||
.wikiEditor-toolbar-dialog table td {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.wikiEditor-toolbar-dialog .ui-dialog-content fieldset {
|
||||
border: none !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.wikiEditor-toolbar-dialog .ui-widget-header {
|
||||
border-bottom:1px solid #6bc8f3 !important;
|
||||
}
|
||||
|
||||
.wikiEditor-toolbar-dialog .ui-dialog-content input[type=text] {
|
||||
-moz-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-khtml-box-sizing: border-box;
|
||||
}
|
||||
|
||||
.wikiEditor-toolbar-dialog .ui-dialog-content input[type="radio"],
|
||||
.wikiEditor-toolbar-dialog .ui-dialog-content input[type="checkbox"] {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.wikiEditor-toolbar-dialog .ui-dialog-titlebar-close {
|
||||
padding: 0;
|
||||
}
|
||||
body .wikiEditor-toolbar-dialog .ui-dialog-titlebar-close {
|
||||
right: 0.9em;
|
||||
}
|
||||
|
||||
.wikieditor-toolbar-field-wrapper {
|
||||
padding: 0 0 25px 0;
|
||||
}
|
||||
|
||||
.wikieditor-toolbar-floated-field-wrapper {
|
||||
float: left;
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
.wikieditor-toolbar-dialog-hint {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.wikiEditor-toolbar-dialog {
|
||||
border: none;
|
||||
}
|
|
@ -1,217 +1,231 @@
|
|||
/**
|
||||
* Dialog Module for wikiEditor
|
||||
*/
|
||||
( function( $ ) { $.wikiEditor.modules.dialogs = {
|
||||
( function ( $, mw ) {
|
||||
|
||||
/**
|
||||
* Compatability map
|
||||
*/
|
||||
'browsers': {
|
||||
// Left-to-right languages
|
||||
'ltr': {
|
||||
'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']
|
||||
],
|
||||
'opera': [['>=', 9.6]],
|
||||
'safari': [['>=', 3]],
|
||||
'chrome': [['>=', 3]]
|
||||
},
|
||||
// Right-to-left languages
|
||||
'rtl': {
|
||||
'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']
|
||||
],
|
||||
'opera': [['>=', 9.6]],
|
||||
'safari': [['>=', 3]],
|
||||
'chrome': [['>=', 3]]
|
||||
}
|
||||
},
|
||||
/**
|
||||
* API accessible functions
|
||||
*/
|
||||
api: {
|
||||
addDialog: function( context, data ) {
|
||||
$.wikiEditor.modules.dialogs.fn.create( context, data )
|
||||
},
|
||||
openDialog: function( context, module ) {
|
||||
if ( module in $.wikiEditor.modules.dialogs.modules ) {
|
||||
var mod = $.wikiEditor.modules.dialogs.modules[module];
|
||||
var $dialog = $( '#' + mod.id );
|
||||
if ( $dialog.length == 0 ) {
|
||||
$.wikiEditor.modules.dialogs.fn.reallyCreate( context, mod, module );
|
||||
$dialog = $( '#' + mod.id );
|
||||
}
|
||||
$.wikiEditor.modules.dialogs = {
|
||||
|
||||
// Workaround for bug in jQuery UI: close button in top right retains focus
|
||||
$dialog.closest( '.ui-dialog' )
|
||||
.find( '.ui-dialog-titlebar-close' )
|
||||
.removeClass( 'ui-state-focus' );
|
||||
|
||||
$dialog.dialog( 'open' );
|
||||
}
|
||||
},
|
||||
closeDialog: function( context, module ) {
|
||||
if ( module in $.wikiEditor.modules.dialogs.modules ) {
|
||||
$( '#' + $.wikiEditor.modules.dialogs.modules[module].id ).dialog( 'close' );
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Internally used functions
|
||||
*/
|
||||
fn: {
|
||||
/**
|
||||
* Creates a dialog module within a wikiEditor
|
||||
*
|
||||
* @param {Object} context Context object of editor to create module in
|
||||
* @param {Object} config Configuration object to create module from
|
||||
* Compatability map
|
||||
*/
|
||||
create: function( context, config ) {
|
||||
// Defer building of modules, but do check whether they need the iframe rightaway
|
||||
for ( var mod in config ) {
|
||||
var module = config[mod];
|
||||
// Only create the dialog if it's supported, isn't filtered and doesn't exist yet
|
||||
var filtered = false;
|
||||
if ( typeof module.filters != 'undefined' ) {
|
||||
for ( var i = 0; i < module.filters.length; i++ ) {
|
||||
if ( $( module.filters[i] ).length == 0 ) {
|
||||
filtered = true;
|
||||
break;
|
||||
browsers: {
|
||||
// Left-to-right languages
|
||||
ltr: {
|
||||
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']
|
||||
],
|
||||
opera: [['>=', 9.6]],
|
||||
safari: [['>=', 3]],
|
||||
chrome: [['>=', 3]]
|
||||
},
|
||||
// Right-to-left languages
|
||||
rtl: {
|
||||
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']
|
||||
],
|
||||
opera: [['>=', 9.6]],
|
||||
safari: [['>=', 3]],
|
||||
chrome: [['>=', 3]]
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* API accessible functions
|
||||
*/
|
||||
api: {
|
||||
addDialog: function ( context, data ) {
|
||||
$.wikiEditor.modules.dialogs.fn.create( context, data );
|
||||
},
|
||||
openDialog: function ( context, module ) {
|
||||
if ( module in $.wikiEditor.modules.dialogs.modules ) {
|
||||
var mod = $.wikiEditor.modules.dialogs.modules[module];
|
||||
var $dialog = $( '#' + mod.id );
|
||||
if ( $dialog.length === 0 ) {
|
||||
$.wikiEditor.modules.dialogs.fn.reallyCreate( context, mod, module );
|
||||
$dialog = $( '#' + mod.id );
|
||||
}
|
||||
|
||||
// Workaround for bug in jQuery UI: close button in top right retains focus
|
||||
$dialog.closest( '.ui-dialog' )
|
||||
.find( '.ui-dialog-titlebar-close' )
|
||||
.removeClass( 'ui-state-focus' );
|
||||
|
||||
$dialog.dialog( 'open' );
|
||||
}
|
||||
},
|
||||
closeDialog: function ( context, module ) {
|
||||
if ( module in $.wikiEditor.modules.dialogs.modules ) {
|
||||
$( '#' + $.wikiEditor.modules.dialogs.modules[module].id ).dialog( 'close' );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Internally used functions
|
||||
*/
|
||||
fn: {
|
||||
/**
|
||||
* Creates a dialog module within a wikiEditor
|
||||
*
|
||||
* @param {Object} context Context object of editor to create module in
|
||||
* @param {Object} config Configuration object to create module from
|
||||
*/
|
||||
create: function ( context, config ) {
|
||||
var mod, module, filtered, i, $existingDialog;
|
||||
|
||||
// Defer building of modules, but do check whether they need the iframe rightaway
|
||||
for ( mod in config ) {
|
||||
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 ) {
|
||||
filtered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the dialog already exists, but for another textarea, simply remove it
|
||||
$existingDialog = $( '#' + module.id );
|
||||
if ( $existingDialog.length > 0 && $existingDialog.data( 'context' ).$textarea != context.$textarea ) {
|
||||
$existingDialog.remove();
|
||||
}
|
||||
// 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;
|
||||
// If this dialog requires the iframe, set it up
|
||||
if ( typeof context.$iframe === 'undefined' && $.wikiEditor.isRequired( module, 'iframe' ) ) {
|
||||
context.fn.setupIframe();
|
||||
}
|
||||
context.$textarea.trigger( 'wikiEditor-dialogs-setup-' + mod );
|
||||
// If this dialog requires immediate creation, create it now
|
||||
if ( typeof module.immediateCreate !== 'undefined' && module.immediateCreate ) {
|
||||
$.wikiEditor.modules.dialogs.fn.reallyCreate( context, module, mod );
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the dialog already exists, but for another textarea, simply remove it
|
||||
var $existingDialog = $( '#' + module.id );
|
||||
if ( $existingDialog.length > 0 && $existingDialog.data( 'context' ).$textarea != context.$textarea ) {
|
||||
$existingDialog.remove();
|
||||
},
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
reallyCreate: function ( context, module, name ) {
|
||||
var msg,
|
||||
configuration = module.dialog;
|
||||
// Add some stuff to configuration
|
||||
configuration.bgiframe = true;
|
||||
configuration.autoOpen = false;
|
||||
configuration.modal = true;
|
||||
configuration.title = $.wikiEditor.autoMsg( module, 'title' );
|
||||
// Transform messages in keys
|
||||
// Stupid JS won't let us do stuff like
|
||||
// foo = { mw.msg( 'bar' ): baz }
|
||||
configuration.newButtons = {};
|
||||
for ( msg in configuration.buttons ) {
|
||||
configuration.newButtons[mw.msg( msg )] = configuration.buttons[msg];
|
||||
}
|
||||
// Re-select from the DOM, we might have removed the dialog just now
|
||||
$existingDialog = $( '#' + module.id );
|
||||
if ( !filtered && $.wikiEditor.isSupported( module ) && $existingDialog.size() === 0 ) {
|
||||
$.wikiEditor.modules.dialogs.modules[mod] = module;
|
||||
// If this dialog requires the iframe, set it up
|
||||
if ( typeof context.$iframe == 'undefined' && $.wikiEditor.isRequired( module, 'iframe' ) ) {
|
||||
context.fn.setupIframe();
|
||||
}
|
||||
context.$textarea.trigger( 'wikiEditor-dialogs-setup-' + mod );
|
||||
// If this dialog requires immediate creation, create it now
|
||||
if ( typeof module.immediateCreate !== 'undefined' && module.immediateCreate ) {
|
||||
$.wikiEditor.modules.dialogs.fn.reallyCreate( context, module, mod );
|
||||
}
|
||||
configuration.buttons = configuration.newButtons;
|
||||
// Create the dialog <div>
|
||||
var dialogDiv = $( '<div>' )
|
||||
.attr( 'id', module.id )
|
||||
.html( module.html )
|
||||
.data( 'context', context )
|
||||
.appendTo( $( 'body' ) )
|
||||
.each( module.init )
|
||||
.dialog( configuration );
|
||||
// Set tabindexes on buttons added by .dialog()
|
||||
$.wikiEditor.modules.dialogs.fn.setTabindexes( dialogDiv.closest( '.ui-dialog' )
|
||||
.find( 'button' ).not( '[tabindex]' ) );
|
||||
if ( !( 'resizeme' in module ) || module.resizeme ) {
|
||||
dialogDiv
|
||||
.bind( 'dialogopen', $.wikiEditor.modules.dialogs.fn.resize )
|
||||
.find( '.ui-tabs' ).bind( 'tabsshow', function () {
|
||||
$(this).closest( '.ui-dialog-content' ).each(
|
||||
$.wikiEditor.modules.dialogs.fn.resize );
|
||||
});
|
||||
}
|
||||
dialogDiv.bind( 'dialogclose', function () {
|
||||
context.fn.restoreSelection();
|
||||
} );
|
||||
|
||||
// Let the outside world know we set up this dialog
|
||||
context.$textarea.trigger( 'wikiEditor-dialogs-loaded-' + name );
|
||||
},
|
||||
|
||||
/**
|
||||
* Resize a dialog so its contents fit
|
||||
*
|
||||
* Usage: dialog.each( resize ); or dialog.bind( 'blah', resize );
|
||||
* NOTE: This function assumes $.ui.dialog has already been loaded
|
||||
*/
|
||||
resize: function () {
|
||||
var wrapper = $(this).closest( '.ui-dialog' );
|
||||
var oldWidth = wrapper.width();
|
||||
// Make sure elements don't wrapped so we get an accurate idea of whether they really fit. Also temporarily show
|
||||
// hidden elements. Work around jQuery bug where <div style="display: inline;"/> inside a dialog is both
|
||||
// :visible and :hidden
|
||||
var oldHidden = $(this).find( '*' ).not( ':visible' );
|
||||
// Save the style attributes of the hidden elements to restore them later. Calling hide() after show() messes up
|
||||
// for elements hidden with a class
|
||||
oldHidden.each( function () {
|
||||
$(this).data( 'oldstyle', $(this).attr( 'style' ) );
|
||||
});
|
||||
oldHidden.show();
|
||||
var oldWS = $(this).css( 'white-space' );
|
||||
$(this).css( 'white-space', 'nowrap' );
|
||||
if ( wrapper.width() <= $(this).get(0).scrollWidth ) {
|
||||
var thisWidth = $(this).data( 'thisWidth' ) ? $(this).data( 'thisWidth' ) : 0;
|
||||
thisWidth = Math.max( $(this).get(0).width, thisWidth );
|
||||
$(this).width( thisWidth );
|
||||
$(this).data( 'thisWidth', thisWidth );
|
||||
var wrapperWidth = $(this).data( 'wrapperWidth' ) ? $(this).data( 'wrapperWidth' ) : 0;
|
||||
wrapperWidth = Math.max( wrapper.get(0).scrollWidth, wrapperWidth );
|
||||
wrapper.width( wrapperWidth );
|
||||
$(this).data( 'wrapperWidth', wrapperWidth );
|
||||
$(this).dialog( { 'width': wrapper.width() } );
|
||||
wrapper.css( 'left', parseInt( wrapper.css( 'left' ), 10 ) - ( wrapper.width() - oldWidth ) / 2 );
|
||||
}
|
||||
$(this).css( 'white-space', oldWS );
|
||||
oldHidden.each( function () {
|
||||
$(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
|
||||
*/
|
||||
setTabindexes: function ( $elements ) {
|
||||
// Get the highest tab index
|
||||
var tabIndex = $( document ).lastTabIndex() + 1;
|
||||
$elements.each( function () {
|
||||
$(this).attr( 'tabindex', tabIndex++ );
|
||||
} );
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
reallyCreate: function( context, module, name ) {
|
||||
var configuration = module.dialog;
|
||||
// Add some stuff to configuration
|
||||
configuration.bgiframe = true;
|
||||
configuration.autoOpen = false;
|
||||
configuration.modal = true;
|
||||
configuration.title = $.wikiEditor.autoMsg( module, 'title' );
|
||||
// Transform messages in keys
|
||||
// Stupid JS won't let us do stuff like
|
||||
// foo = { mediaWiki.msg( 'bar' ): baz }
|
||||
configuration.newButtons = {};
|
||||
for ( var msg in configuration.buttons )
|
||||
configuration.newButtons[mediaWiki.msg( msg )] = configuration.buttons[msg];
|
||||
configuration.buttons = configuration.newButtons;
|
||||
// Create the dialog <div>
|
||||
var dialogDiv = $( '<div />' )
|
||||
.attr( 'id', module.id )
|
||||
.html( module.html )
|
||||
.data( 'context', context )
|
||||
|
||||
// This stuff is just hanging here, perhaps we could come up with a better home for this stuff
|
||||
modules: {},
|
||||
|
||||
quickDialog: function ( body, settings ) {
|
||||
$( '<div>' )
|
||||
.text( body )
|
||||
.appendTo( $( 'body' ) )
|
||||
.each( module.init )
|
||||
.dialog( configuration );
|
||||
// Set tabindexes on buttons added by .dialog()
|
||||
$.wikiEditor.modules.dialogs.fn.setTabindexes( dialogDiv.closest( '.ui-dialog' )
|
||||
.find( 'button' ).not( '[tabindex]' ) );
|
||||
if ( !( 'resizeme' in module ) || module.resizeme ) {
|
||||
dialogDiv
|
||||
.bind( 'dialogopen', $.wikiEditor.modules.dialogs.fn.resize )
|
||||
.find( '.ui-tabs' ).bind( 'tabsshow', function() {
|
||||
$(this).closest( '.ui-dialog-content' ).each(
|
||||
$.wikiEditor.modules.dialogs.fn.resize );
|
||||
});
|
||||
}
|
||||
dialogDiv.bind( 'dialogclose', function() {
|
||||
context.fn.restoreSelection();
|
||||
} );
|
||||
|
||||
// Let the outside world know we set up this dialog
|
||||
context.$textarea.trigger( 'wikiEditor-dialogs-loaded-' + name );
|
||||
},
|
||||
/**
|
||||
* Resize a dialog so its contents fit
|
||||
*
|
||||
* Usage: dialog.each( resize ); or dialog.bind( 'blah', resize );
|
||||
* NOTE: This function assumes $.ui.dialog has already been loaded
|
||||
*/
|
||||
resize: function() {
|
||||
var wrapper = $(this).closest( '.ui-dialog' );
|
||||
var oldWidth = wrapper.width();
|
||||
// Make sure elements don't wrapped so we get an accurate idea of whether they really fit. Also temporarily show
|
||||
// hidden elements. Work around jQuery bug where <div style="display:inline;" /> inside a dialog is both
|
||||
// :visible and :hidden
|
||||
var oldHidden = $(this).find( '*' ).not( ':visible' );
|
||||
// Save the style attributes of the hidden elements to restore them later. Calling hide() after show() messes up
|
||||
// for elements hidden with a class
|
||||
oldHidden.each( function() {
|
||||
$(this).data( 'oldstyle', $(this).attr( 'style' ) );
|
||||
});
|
||||
oldHidden.show();
|
||||
var oldWS = $(this).css( 'white-space' );
|
||||
$(this).css( 'white-space', 'nowrap' );
|
||||
if ( wrapper.width() <= $(this).get(0).scrollWidth ) {
|
||||
var thisWidth = $(this).data( 'thisWidth' ) ? $(this).data( 'thisWidth' ) : 0;
|
||||
thisWidth = Math.max( $(this).get(0).width, thisWidth );
|
||||
$(this).width( thisWidth );
|
||||
$(this).data( 'thisWidth', thisWidth );
|
||||
var wrapperWidth = $(this).data( 'wrapperWidth' ) ? $(this).data( 'wrapperWidth' ) : 0;
|
||||
wrapperWidth = Math.max( wrapper.get(0).scrollWidth, wrapperWidth );
|
||||
wrapper.width( wrapperWidth );
|
||||
$(this).data( 'wrapperWidth', wrapperWidth );
|
||||
$(this).dialog( { 'width': wrapper.width() } );
|
||||
wrapper.css( 'left', parseInt( wrapper.css( 'left' ) ) - ( wrapper.width() - oldWidth ) / 2 );
|
||||
}
|
||||
$(this).css( 'white-space', oldWS );
|
||||
oldHidden.each( function() {
|
||||
$(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
|
||||
*/
|
||||
setTabindexes: function( $elements ) {
|
||||
// Get the highest tab index
|
||||
var tabIndex = $( document ).lastTabIndex() + 1;
|
||||
$elements.each( function() {
|
||||
$(this).attr( 'tabindex', tabIndex++ );
|
||||
} );
|
||||
.dialog( $.extend( {
|
||||
bgiframe: true,
|
||||
modal: true
|
||||
}, settings ) )
|
||||
.dialog( 'open' );
|
||||
}
|
||||
},
|
||||
// This stuff is just hanging here, perhaps we could come up with a better home for this stuff
|
||||
modules: {},
|
||||
quickDialog: function( body, settings ) {
|
||||
$( '<div />' )
|
||||
.text( body )
|
||||
.appendTo( $( 'body' ) )
|
||||
.dialog( $.extend( {
|
||||
bgiframe: true,
|
||||
modal: true
|
||||
}, settings ) )
|
||||
.dialog( 'open' );
|
||||
}
|
||||
|
||||
}; } ) ( jQuery );
|
||||
};
|
||||
|
||||
}( jQuery, mediaWiki ) );
|
||||
|
|
|
@ -1,357 +1,373 @@
|
|||
/* Highlight module for wikiEditor */
|
||||
|
||||
( function( $ ) { $.wikiEditor.modules.highlight = {
|
||||
( function ( $ ) {
|
||||
|
||||
/**
|
||||
* Core Requirements
|
||||
*/
|
||||
'req': [ 'iframe' ],
|
||||
/**
|
||||
* Configuration
|
||||
*/
|
||||
'cfg': {
|
||||
'styleVersion': 3
|
||||
},
|
||||
/**
|
||||
* Internally used event handlers
|
||||
*/
|
||||
'evt': {
|
||||
'delayedChange': function( context, event ) {
|
||||
if ( event.data.scope == 'realchange' ) {
|
||||
$.wikiEditor.modules.highlight = {
|
||||
|
||||
/**
|
||||
* Core Requirements
|
||||
*/
|
||||
req: [ 'iframe' ],
|
||||
|
||||
/**
|
||||
* Configuration
|
||||
*/
|
||||
cfg: {
|
||||
styleVersion: 3
|
||||
},
|
||||
|
||||
/**
|
||||
* Internally used event handlers
|
||||
*/
|
||||
evt: {
|
||||
delayedChange: function ( context, event ) {
|
||||
if ( event.data.scope == 'realchange' ) {
|
||||
$.wikiEditor.modules.highlight.fn.scan( context );
|
||||
$.wikiEditor.modules.highlight.fn.mark( context, event.data.scope );
|
||||
}
|
||||
},
|
||||
ready: function ( context, event ) {
|
||||
$.wikiEditor.modules.highlight.fn.scan( context );
|
||||
$.wikiEditor.modules.highlight.fn.mark( context, event.data.scope );
|
||||
$.wikiEditor.modules.highlight.fn.mark( context, 'ready' );
|
||||
}
|
||||
},
|
||||
'ready': function( context, event ) {
|
||||
$.wikiEditor.modules.highlight.fn.scan( context );
|
||||
$.wikiEditor.modules.highlight.fn.mark( context, 'ready' );
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Internally used functions
|
||||
*/
|
||||
'fn': {
|
||||
|
||||
/**
|
||||
* Creates a highlight module within a wikiEditor
|
||||
*
|
||||
* @param config Configuration object to create module from
|
||||
* Internally used functions
|
||||
*/
|
||||
'create': function( context, config ) {
|
||||
context.modules.highlight.markersStr = '';
|
||||
},
|
||||
/**
|
||||
* Scans text division for tokens
|
||||
*
|
||||
* @param division
|
||||
*/
|
||||
'scan': function( context, division ) {
|
||||
// Remove all existing tokens
|
||||
var tokenArray = context.modules.highlight.tokenArray = [];
|
||||
// Scan text for new tokens
|
||||
var text = context.fn.getContents();
|
||||
// Perform a scan for each module which provides any expressions to scan for
|
||||
// FIXME: This traverses the entire string once for every regex. Investigate
|
||||
// whether |-concatenating regexes then traversing once is faster.
|
||||
for ( var module in context.modules ) {
|
||||
if ( module in $.wikiEditor.modules && 'exp' in $.wikiEditor.modules[module] ) {
|
||||
for ( var exp in $.wikiEditor.modules[module].exp ) {
|
||||
// Prepare configuration
|
||||
var regex = $.wikiEditor.modules[module].exp[exp].regex;
|
||||
var label = $.wikiEditor.modules[module].exp[exp].label;
|
||||
var markAfter = $.wikiEditor.modules[module].exp[exp].markAfter || false;
|
||||
// Search for tokens
|
||||
var offset = 0, left, right, match;
|
||||
while ( ( match = text.substr( offset ).match( regex ) ) != null ) {
|
||||
right = ( left = offset + match.index ) + match[0].length;
|
||||
tokenArray[tokenArray.length] = {
|
||||
'offset': markAfter ? right : left,
|
||||
'label': label,
|
||||
'tokenStart': left,
|
||||
'match': match
|
||||
};
|
||||
// Move to the right of this match
|
||||
offset = right;
|
||||
fn: {
|
||||
/**
|
||||
* Creates a highlight module within a wikiEditor
|
||||
*
|
||||
* @param config Configuration object to create module from
|
||||
*/
|
||||
create: function ( context, config ) {
|
||||
context.modules.highlight.markersStr = '';
|
||||
},
|
||||
/**
|
||||
* Scans text division for tokens
|
||||
*
|
||||
* @param division
|
||||
*/
|
||||
scan: function ( context, division ) {
|
||||
var tokenArray, text, module, exp,
|
||||
left, right, match;
|
||||
/*jshint eqnull: true */
|
||||
|
||||
// Remove all existing tokens
|
||||
tokenArray = context.modules.highlight.tokenArray = [];
|
||||
// Scan text for new tokens
|
||||
text = context.fn.getContents();
|
||||
// Perform a scan for each module which provides any expressions to scan for
|
||||
// FIXME: This traverses the entire string once for every regex. Investigate
|
||||
// whether |-concatenating regexes then traversing once is faster.
|
||||
for ( module in context.modules ) {
|
||||
if ( module in $.wikiEditor.modules && 'exp' in $.wikiEditor.modules[module] ) {
|
||||
for ( exp in $.wikiEditor.modules[module].exp ) {
|
||||
// Prepare configuration
|
||||
var regex = $.wikiEditor.modules[module].exp[exp].regex;
|
||||
var label = $.wikiEditor.modules[module].exp[exp].label;
|
||||
var markAfter = $.wikiEditor.modules[module].exp[exp].markAfter || false;
|
||||
// Search for tokens
|
||||
var offset = 0;
|
||||
while ( ( match = text.substr( offset ).match( regex ) ) != null ) {
|
||||
right = ( left = offset + match.index ) + match[0].length;
|
||||
tokenArray[tokenArray.length] = {
|
||||
offset: markAfter ? right : left,
|
||||
label: label,
|
||||
tokenStart: left,
|
||||
match: match
|
||||
};
|
||||
// Move to the right of this match
|
||||
offset = right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort by start
|
||||
tokenArray.sort( function( a, b ) { return a.tokenStart - b.tokenStart; } );
|
||||
// Let the world know, a scan just happened!
|
||||
context.fn.trigger( 'scan' );
|
||||
},
|
||||
/**
|
||||
* Marks up text with HTML
|
||||
*
|
||||
* @param division
|
||||
* @param tokens
|
||||
*/
|
||||
// FIXME: What do division and tokens do?
|
||||
// TODO: Document the scan() and mark() APIs somewhere
|
||||
'mark': function( context, division, tokens ) {
|
||||
// Reset markers
|
||||
var markers = [];
|
||||
// Sort by start
|
||||
tokenArray.sort( function ( a, b ) {
|
||||
return a.tokenStart - b.tokenStart;
|
||||
} );
|
||||
// Let the world know, a scan just happened!
|
||||
context.fn.trigger( 'scan' );
|
||||
},
|
||||
|
||||
// Recycle markers that will be skipped in this run
|
||||
if ( context.modules.highlight.markers && division != '' ) {
|
||||
for ( var i = 0; i < context.modules.highlight.markers.length; i++ ) {
|
||||
if ( context.modules.highlight.markers[i].skipDivision == division ) {
|
||||
markers.push( context.modules.highlight.markers[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
context.modules.highlight.markers = markers;
|
||||
/**
|
||||
* Marks up text with HTML
|
||||
*
|
||||
* @param division
|
||||
* @param tokens
|
||||
*/
|
||||
// FIXME: What do division and tokens do?
|
||||
// TODO: Document the scan() and mark() APIs somewhere
|
||||
mark: function ( context, division, tokens ) {
|
||||
var i, subtracted, oldLength, j, o;
|
||||
|
||||
// Get all markers
|
||||
context.fn.trigger( 'mark' );
|
||||
markers.sort( function( a, b ) { return a.start - b.start || a.end - b.end; } );
|
||||
// Reset markers
|
||||
var markers = [];
|
||||
|
||||
// Serialize the markers array to a string and compare it with the one stored in the previous run - if they're
|
||||
// equal, there's no markers to change
|
||||
var markersStr = '';
|
||||
for ( var i = 0; i < markers.length; i++ ) {
|
||||
markersStr += markers[i].start + ',' + markers[i].end + ',' + markers[i].type + ',';
|
||||
}
|
||||
if ( context.modules.highlight.markersStr == markersStr ) {
|
||||
// No change, bail out
|
||||
return;
|
||||
}
|
||||
context.modules.highlight.markersStr = markersStr;
|
||||
|
||||
// Traverse the iframe DOM, inserting markers where they're needed - store visited markers here so we know which
|
||||
// markers should be removed
|
||||
var visited = [], v = 0;
|
||||
for ( var i = 0; i < markers.length; i++ ) {
|
||||
if ( typeof markers[i].skipDivision !== 'undefined' && ( division == markers[i].skipDivision ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We want to isolate each marker, so we may need to split textNodes if a marker starts or ends halfway one.
|
||||
var start = markers[i].start;
|
||||
var s = context.fn.getOffset( start );
|
||||
if ( !s ) {
|
||||
// This shouldn't happen
|
||||
continue;
|
||||
}
|
||||
var startNode = s.node;
|
||||
|
||||
// Don't wrap leading BRs, produces undesirable results
|
||||
// FIXME: It's also possible that the offset is a bit high because getOffset() has incremented .length to
|
||||
// fake the newline caused by startNode being in a P. In this case, prevent the textnode splitting below
|
||||
// from making startNode an empty textnode, IE barfs on that
|
||||
while ( startNode.nodeName == 'BR' || s.offset == startNode.nodeValue.length ) {
|
||||
start++;
|
||||
s = context.fn.getOffset( start );
|
||||
startNode = s.node;
|
||||
}
|
||||
|
||||
// The next marker starts somewhere in this textNode or at this BR
|
||||
if ( s.offset > 0 && s.node.nodeName == '#text' ) {
|
||||
// Split off the prefix - this leaves the prefix in the current node and puts the rest in a new node
|
||||
// which is our start node
|
||||
var newStartNode = startNode.splitText( s.offset < s.node.nodeValue.length ?
|
||||
s.offset : s.node.nodeValue.length - 1
|
||||
);
|
||||
var oldStartNode = startNode;
|
||||
startNode = newStartNode;
|
||||
// Update offset objects. We don't need purgeOffsets(), simply manipulating the existing offset objects
|
||||
// will suffice
|
||||
// FIXME: This manipulates context.offsets directly, which is ugly, but the performance improvement vs.
|
||||
// purgeOffsets() is worth it - this code doesn't set lastTextNode to newStartNode for offset objects
|
||||
// with lastTextNode == oldStartNode, but that doesn't really matter
|
||||
var subtracted = s.offset;
|
||||
var oldLength = s.length;
|
||||
|
||||
var j, o;
|
||||
// Update offset objects referring to oldStartNode
|
||||
for ( j = start - subtracted; j < start; j++ ) {
|
||||
if ( j in context.offsets ) {
|
||||
o = context.offsets[j];
|
||||
o.node = oldStartNode;
|
||||
o.length = subtracted;
|
||||
}
|
||||
}
|
||||
// Update offset objects referring to newStartNode
|
||||
for ( j = start; j < start - subtracted + oldLength; j++ ) {
|
||||
if ( j in context.offsets ) {
|
||||
o = context.offsets[j];
|
||||
o.node = newStartNode;
|
||||
o.offset -= subtracted;
|
||||
o.length -= subtracted;
|
||||
o.lastTextNode = oldStartNode;
|
||||
// Recycle markers that will be skipped in this run
|
||||
if ( context.modules.highlight.markers && division !== '' ) {
|
||||
for ( i = 0; i < context.modules.highlight.markers.length; i++ ) {
|
||||
if ( context.modules.highlight.markers[i].skipDivision == division ) {
|
||||
markers.push( context.modules.highlight.markers[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
var end = markers[i].end;
|
||||
// To avoid ending up at the first char of the next node, we grab the offset for end - 1 and add one to the
|
||||
// offset
|
||||
var e = context.fn.getOffset( end - 1 );
|
||||
if ( !e ) {
|
||||
// This shouldn't happen
|
||||
continue;
|
||||
context.modules.highlight.markers = markers;
|
||||
|
||||
// Get all markers
|
||||
context.fn.trigger( 'mark' );
|
||||
markers.sort( function ( a, b ) {
|
||||
return a.start - b.start || a.end - b.end;
|
||||
} );
|
||||
|
||||
// Serialize the markers array to a string and compare it with the one stored in the previous run - if they're
|
||||
// equal, there's no markers to change
|
||||
var markersStr = '';
|
||||
for ( i = 0; i < markers.length; i++ ) {
|
||||
markersStr += markers[i].start + ',' + markers[i].end + ',' + markers[i].type + ',';
|
||||
}
|
||||
var endNode = e.node;
|
||||
if ( e.offset + 1 < e.length - 1 && endNode.nodeName == '#text' ) {
|
||||
// Split off the suffix. This puts the suffix in a new node and leaves the rest in endNode
|
||||
var oldEndNode = endNode;
|
||||
var newEndNode = endNode.splitText( e.offset + 1 );
|
||||
// Update offset objects
|
||||
var subtracted = e.offset + 1;
|
||||
var oldLength = e.length;
|
||||
var j, o;
|
||||
// Update offset objects referring to oldEndNode
|
||||
for ( j = end - subtracted; j < end; j++ ) {
|
||||
if ( j in context.offsets ) {
|
||||
o = context.offsets[j];
|
||||
o.node = oldEndNode;
|
||||
o.length = subtracted;
|
||||
if ( context.modules.highlight.markersStr == markersStr ) {
|
||||
// No change, bail out
|
||||
return;
|
||||
}
|
||||
context.modules.highlight.markersStr = markersStr;
|
||||
|
||||
// Traverse the iframe DOM, inserting markers where they're needed - store visited markers here so we know which
|
||||
// markers should be removed
|
||||
var visited = [], v = 0;
|
||||
for ( i = 0; i < markers.length; i++ ) {
|
||||
if ( typeof markers[i].skipDivision !== 'undefined' && ( division == markers[i].skipDivision ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We want to isolate each marker, so we may need to split textNodes if a marker starts or ends halfway one.
|
||||
var start = markers[i].start;
|
||||
var s = context.fn.getOffset( start );
|
||||
if ( !s ) {
|
||||
// This shouldn't happen
|
||||
continue;
|
||||
}
|
||||
var startNode = s.node;
|
||||
|
||||
// Don't wrap leading BRs, produces undesirable results
|
||||
// FIXME: It's also possible that the offset is a bit high because getOffset() has incremented .length to
|
||||
// fake the newline caused by startNode being in a P. In this case, prevent the textnode splitting below
|
||||
// from making startNode an empty textnode, IE barfs on that
|
||||
while ( startNode.nodeName === 'BR' || s.offset === startNode.nodeValue.length ) {
|
||||
start++;
|
||||
s = context.fn.getOffset( start );
|
||||
startNode = s.node;
|
||||
}
|
||||
|
||||
// The next marker starts somewhere in this textNode or at this BR
|
||||
if ( s.offset > 0 && s.node.nodeName == '#text' ) {
|
||||
// Split off the prefix - this leaves the prefix in the current node and puts the rest in a new node
|
||||
// which is our start node
|
||||
var newStartNode = startNode.splitText( s.offset < s.node.nodeValue.length ?
|
||||
s.offset : s.node.nodeValue.length - 1
|
||||
);
|
||||
var oldStartNode = startNode;
|
||||
startNode = newStartNode;
|
||||
// Update offset objects. We don't need purgeOffsets(), simply manipulating the existing offset objects
|
||||
// will suffice
|
||||
// FIXME: This manipulates context.offsets directly, which is ugly, but the performance improvement vs.
|
||||
// purgeOffsets() is worth it - this code doesn't set lastTextNode to newStartNode for offset objects
|
||||
// with lastTextNode == oldStartNode, but that doesn't really matter
|
||||
subtracted = s.offset;
|
||||
oldLength = s.length;
|
||||
|
||||
// Update offset objects referring to oldStartNode
|
||||
for ( j = start - subtracted; j < start; j++ ) {
|
||||
if ( j in context.offsets ) {
|
||||
o = context.offsets[j];
|
||||
o.node = oldStartNode;
|
||||
o.length = subtracted;
|
||||
}
|
||||
}
|
||||
// Update offset objects referring to newStartNode
|
||||
for ( j = start; j < start - subtracted + oldLength; j++ ) {
|
||||
if ( j in context.offsets ) {
|
||||
o = context.offsets[j];
|
||||
o.node = newStartNode;
|
||||
o.offset -= subtracted;
|
||||
o.length -= subtracted;
|
||||
o.lastTextNode = oldStartNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
// We have to insert this one, as it might not exist: we didn't call getOffset( end )
|
||||
context.offsets[end] = {
|
||||
'node': newEndNode,
|
||||
'offset': 0,
|
||||
'length': oldLength - subtracted,
|
||||
'lastTextNode': oldEndNode
|
||||
};
|
||||
// Update offset objects referring to newEndNode
|
||||
for ( j = end + 1; j < end - subtracted + oldLength; j++ ) {
|
||||
if ( j in context.offsets ) {
|
||||
o = context.offsets[j];
|
||||
o.node = newEndNode;
|
||||
o.offset -= subtracted;
|
||||
o.length -= subtracted;
|
||||
o.lastTextNode = oldEndNode;
|
||||
var end = markers[i].end;
|
||||
// To avoid ending up at the first char of the next node, we grab the offset for end - 1 and add one to the
|
||||
// offset
|
||||
var e = context.fn.getOffset( end - 1 );
|
||||
if ( !e ) {
|
||||
// This shouldn't happen
|
||||
continue;
|
||||
}
|
||||
var endNode = e.node;
|
||||
if ( e.offset + 1 < e.length - 1 && endNode.nodeName == '#text' ) {
|
||||
// Split off the suffix. This puts the suffix in a new node and leaves the rest in endNode
|
||||
var oldEndNode = endNode;
|
||||
var newEndNode = endNode.splitText( e.offset + 1 );
|
||||
// Update offset objects
|
||||
subtracted = e.offset + 1;
|
||||
oldLength = e.length;
|
||||
|
||||
// Update offset objects referring to oldEndNode
|
||||
for ( j = end - subtracted; j < end; j++ ) {
|
||||
if ( j in context.offsets ) {
|
||||
o = context.offsets[j];
|
||||
o.node = oldEndNode;
|
||||
o.length = subtracted;
|
||||
}
|
||||
}
|
||||
// We have to insert this one, as it might not exist: we didn't call getOffset( end )
|
||||
context.offsets[end] = {
|
||||
'node': newEndNode,
|
||||
'offset': 0,
|
||||
'length': oldLength - subtracted,
|
||||
'lastTextNode': oldEndNode
|
||||
};
|
||||
// Update offset objects referring to newEndNode
|
||||
for ( j = end + 1; j < end - subtracted + oldLength; j++ ) {
|
||||
if ( j in context.offsets ) {
|
||||
o = context.offsets[j];
|
||||
o.node = newEndNode;
|
||||
o.offset -= subtracted;
|
||||
o.length -= subtracted;
|
||||
o.lastTextNode = oldEndNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't wrap trailing BRs, doing that causes weird issues
|
||||
if ( endNode.nodeName == 'BR' ) {
|
||||
endNode = e.lastTextNode;
|
||||
}
|
||||
// If startNode and endNode have different parents, we need to pull endNode and all textnodes in between
|
||||
// into startNode's parent and replace </p><p> with <br>
|
||||
if ( startNode.parentNode != endNode.parentNode ) {
|
||||
var startP = $( startNode ).closest( 'p' ).get( 0 );
|
||||
var t = new context.fn.rawTraverser( startNode, startP, context.$content.get( 0 ), false );
|
||||
var afterStart = startNode.nextSibling;
|
||||
var lastP = startP;
|
||||
var nextT = t.next();
|
||||
while ( nextT && t.node != endNode ) {
|
||||
t = nextT;
|
||||
nextT = t.next();
|
||||
// If t.node has a different parent, merge t.node.parentNode with startNode.parentNode
|
||||
if ( t.node.parentNode != startNode.parentNode ) {
|
||||
var oldParent = t.node.parentNode;
|
||||
if ( afterStart ) {
|
||||
if ( lastP != t.inP ) {
|
||||
// We're entering a new <p>, insert a <br>
|
||||
startNode.parentNode.insertBefore(
|
||||
startNode.ownerDocument.createElement( 'br' ),
|
||||
afterStart
|
||||
);
|
||||
}
|
||||
// A <p> with just a <br> in it is an empty line, so let's not bother with unwrapping it
|
||||
if ( !( oldParent.childNodes.length == 1 && oldParent.firstChild.nodeName == 'BR' ) ) {
|
||||
// Move all children of oldParent into startNode's parent
|
||||
while ( oldParent.firstChild ) {
|
||||
startNode.parentNode.insertBefore( oldParent.firstChild, afterStart );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( lastP != t.inP ) {
|
||||
// We're entering a new <p>, insert a <br>
|
||||
startNode.parentNode.appendChild(
|
||||
startNode.ownerDocument.createElement( 'br' )
|
||||
);
|
||||
}
|
||||
// A <p> with just a <br> in it is an empty line, so let's not bother with unwrapping it
|
||||
if ( !( oldParent.childNodes.length == 1 && oldParent.firstChild.nodeName == 'BR' ) ) {
|
||||
// Move all children of oldParent into startNode's parent
|
||||
while ( oldParent.firstChild ) {
|
||||
startNode.parentNode.appendChild( oldParent.firstChild );
|
||||
// Don't wrap trailing BRs, doing that causes weird issues
|
||||
if ( endNode.nodeName == 'BR' ) {
|
||||
endNode = e.lastTextNode;
|
||||
}
|
||||
// If startNode and endNode have different parents, we need to pull endNode and all textnodes in between
|
||||
// into startNode's parent and replace </p><p> with <br>
|
||||
if ( startNode.parentNode !== endNode.parentNode ) {
|
||||
var startP = $( startNode ).closest( 'p' ).get( 0 );
|
||||
var t = new context.fn.rawTraverser( startNode, startP, context.$content.get( 0 ), false );
|
||||
var afterStart = startNode.nextSibling;
|
||||
var lastP = startP;
|
||||
var nextT = t.next();
|
||||
while ( nextT && t.node !== endNode ) {
|
||||
t = nextT;
|
||||
nextT = t.next();
|
||||
// If t.node has a different parent, merge t.node.parentNode with startNode.parentNode
|
||||
if ( t.node.parentNode !== startNode.parentNode ) {
|
||||
var oldParent = t.node.parentNode;
|
||||
if ( afterStart ) {
|
||||
if ( lastP !== t.inP ) {
|
||||
// We're entering a new <p>, insert a <br>
|
||||
startNode.parentNode.insertBefore(
|
||||
startNode.ownerDocument.createElement( 'br' ),
|
||||
afterStart
|
||||
);
|
||||
}
|
||||
// A <p> with just a <br> in it is an empty line, so let's not bother with unwrapping it
|
||||
if ( !( oldParent.childNodes.length == 1 && oldParent.firstChild.nodeName == 'BR' ) ) {
|
||||
// Move all children of oldParent into startNode's parent
|
||||
while ( oldParent.firstChild ) {
|
||||
startNode.parentNode.insertBefore( oldParent.firstChild, afterStart );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( lastP !== t.inP ) {
|
||||
// We're entering a new <p>, insert a <br>
|
||||
startNode.parentNode.appendChild(
|
||||
startNode.ownerDocument.createElement( 'br' )
|
||||
);
|
||||
}
|
||||
// A <p> with just a <br> in it is an empty line, so let's not bother with unwrapping it
|
||||
if ( !( oldParent.childNodes.length == 1 && oldParent.firstChild.nodeName == 'BR' ) ) {
|
||||
// Move all children of oldParent into startNode's parent
|
||||
while ( oldParent.firstChild ) {
|
||||
startNode.parentNode.appendChild( oldParent.firstChild );
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove oldParent, which is now empty
|
||||
oldParent.parentNode.removeChild( oldParent );
|
||||
}
|
||||
// Remove oldParent, which is now empty
|
||||
oldParent.parentNode.removeChild( oldParent );
|
||||
lastP = t.inP;
|
||||
}
|
||||
lastP = t.inP;
|
||||
// Moving nodes around like this invalidates offset objects
|
||||
// TODO: Update offset objects ourselves for performance. Requires rewriting this code block to be
|
||||
// offset-based rather than traverser-based
|
||||
}
|
||||
// Moving nodes around like this invalidates offset objects
|
||||
// TODO: Update offset objects ourselves for performance. Requires rewriting this code block to be
|
||||
// offset-based rather than traverser-based
|
||||
}
|
||||
// Now wrap everything between startNode and endNode (may be equal).
|
||||
var ca1 = startNode, ca2 = endNode;
|
||||
if ( ca1 && ca2 && ca1.parentNode ) {
|
||||
var anchor = markers[i].getAnchor( ca1, ca2 );
|
||||
if ( !anchor ) {
|
||||
var commonAncestor = ca1.parentNode;
|
||||
if ( markers[i].anchor == 'wrap') {
|
||||
// We have to store things like .parentNode and .nextSibling because appendChild() changes these
|
||||
var newNode = ca1.ownerDocument.createElement( 'span' );
|
||||
var nextNode = ca2.nextSibling;
|
||||
// Append all nodes between ca1 and ca2 (inclusive) to newNode
|
||||
var n = ca1;
|
||||
while ( n != nextNode ) {
|
||||
var ns = n.nextSibling;
|
||||
newNode.appendChild( n );
|
||||
n = ns;
|
||||
// Now wrap everything between startNode and endNode (may be equal).
|
||||
var ca1 = startNode, ca2 = endNode;
|
||||
if ( ca1 && ca2 && ca1.parentNode ) {
|
||||
var anchor = markers[i].getAnchor( ca1, ca2 );
|
||||
if ( !anchor ) {
|
||||
var commonAncestor = ca1.parentNode;
|
||||
if ( markers[i].anchor == 'wrap') {
|
||||
// We have to store things like .parentNode and .nextSibling because appendChild() changes these
|
||||
var newNode = ca1.ownerDocument.createElement( 'span' );
|
||||
var nextNode = ca2.nextSibling;
|
||||
// Append all nodes between ca1 and ca2 (inclusive) to newNode
|
||||
var n = ca1;
|
||||
while ( n !== nextNode ) {
|
||||
var ns = n.nextSibling;
|
||||
newNode.appendChild( n );
|
||||
n = ns;
|
||||
}
|
||||
// Insert newNode in the right place
|
||||
if ( nextNode ) {
|
||||
commonAncestor.insertBefore( newNode, nextNode );
|
||||
} else {
|
||||
commonAncestor.appendChild( newNode );
|
||||
}
|
||||
anchor = newNode;
|
||||
} else if ( markers[i].anchor == 'tag' ) {
|
||||
anchor = commonAncestor;
|
||||
}
|
||||
// Insert newNode in the right place
|
||||
if ( nextNode ) {
|
||||
commonAncestor.insertBefore( newNode, nextNode );
|
||||
} else {
|
||||
commonAncestor.appendChild( newNode );
|
||||
}
|
||||
anchor = newNode;
|
||||
} else if ( markers[i].anchor == 'tag' ) {
|
||||
anchor = commonAncestor;
|
||||
}
|
||||
$( anchor ).data( 'marker', markers[i] ).addClass( 'wikiEditor-highlight' );
|
||||
// Allow the module adding this marker to manipulate it
|
||||
markers[i].afterWrap( anchor, markers[i] );
|
||||
$( anchor ).data( 'marker', markers[i] ).addClass( 'wikiEditor-highlight' );
|
||||
// Allow the module adding this marker to manipulate it
|
||||
markers[i].afterWrap( anchor, markers[i] );
|
||||
|
||||
} else {
|
||||
// Update the marker object
|
||||
$( anchor ).data( 'marker', markers[i] );
|
||||
if ( typeof markers[i].onSkip == 'function' ) {
|
||||
markers[i].onSkip( anchor );
|
||||
}
|
||||
}
|
||||
visited[v++] = anchor;
|
||||
}
|
||||
}
|
||||
// Remove markers that were previously inserted but weren't passed to this function - visited[] contains the
|
||||
// visited elements in order and find() and each() preserve order
|
||||
j = 0;
|
||||
context.$content.find( '.wikiEditor-highlight' ).each( function () {
|
||||
if ( visited[j] == this ) {
|
||||
// This marker is legit, leave it in
|
||||
j++;
|
||||
return true;
|
||||
}
|
||||
// Remove this marker
|
||||
var marker = $(this).data( 'marker' );
|
||||
if ( marker && typeof marker.skipDivision !== 'undefined' && ( division === marker.skipDivision ) ) {
|
||||
// Don't remove these either
|
||||
return true;
|
||||
}
|
||||
if ( marker && typeof marker.beforeUnwrap === 'function' )
|
||||
marker.beforeUnwrap( this );
|
||||
if ( ( marker && marker.anchor === 'tag' ) || $(this).is( 'p' ) ) {
|
||||
// Remove all classes
|
||||
$(this).removeAttr( 'class' );
|
||||
} else {
|
||||
// Update the marker object
|
||||
$( anchor ).data( 'marker', markers[i] );
|
||||
if ( typeof markers[i].onSkip == 'function' ) {
|
||||
markers[i].onSkip( anchor );
|
||||
}
|
||||
// Assume anchor == 'wrap'
|
||||
$(this).replaceWith( this.childNodes );
|
||||
}
|
||||
visited[v++] = anchor;
|
||||
}
|
||||
context.fn.purgeOffsets();
|
||||
});
|
||||
|
||||
}
|
||||
// Remove markers that were previously inserted but weren't passed to this function - visited[] contains the
|
||||
// visited elements in order and find() and each() preserve order
|
||||
var j = 0;
|
||||
context.$content.find( '.wikiEditor-highlight' ).each( function() {
|
||||
if ( visited[j] == this ) {
|
||||
// This marker is legit, leave it in
|
||||
j++;
|
||||
return true;
|
||||
}
|
||||
// Remove this marker
|
||||
var marker = $(this).data( 'marker' );
|
||||
if ( marker && typeof marker.skipDivision != 'undefined' && ( division == marker.skipDivision ) ) {
|
||||
// Don't remove these either
|
||||
return true;
|
||||
}
|
||||
if ( marker && typeof marker.beforeUnwrap == 'function' )
|
||||
marker.beforeUnwrap( this );
|
||||
if ( ( marker && marker.anchor == 'tag' ) || $(this).is( 'p' ) ) {
|
||||
// Remove all classes
|
||||
$(this).removeAttr( 'class' );
|
||||
} else {
|
||||
// Assume anchor == 'wrap'
|
||||
$(this).replaceWith( this.childNodes );
|
||||
}
|
||||
context.fn.purgeOffsets();
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}; })( jQuery );
|
||||
}( jQuery ) );
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
* This plugin provides a way to build a wiki-text editing user interface around a textarea.
|
||||
*
|
||||
* @example To intialize without any modules:
|
||||
* $( 'div#edittoolbar' ).wikiEditor();
|
||||
* $( 'div#edittoolbar' ).wikiEditor();
|
||||
*
|
||||
* @example To initialize with one or more modules, or to add modules after it's already been initialized:
|
||||
* $( 'textarea#wpTextbox1' ).wikiEditor( 'addModule', 'toolbar', { ... config ... } );
|
||||
* $( 'textarea#wpTextbox1' ).wikiEditor( 'addModule', 'toolbar', { ... config ... } );
|
||||
*
|
||||
*/
|
||||
( function( $ ) {
|
||||
( function ( $ ) {
|
||||
|
||||
/**
|
||||
* Global static object for wikiEditor that provides generally useful functionality to all modules and contexts.
|
||||
|
@ -19,63 +19,68 @@ $.wikiEditor = {
|
|||
* module name. The existance of a module in this object only indicates the module is available. To check if a
|
||||
* module is in use by a specific context check the context.modules object.
|
||||
*/
|
||||
'modules': {},
|
||||
modules: {},
|
||||
|
||||
/**
|
||||
* A context can be extended, such as adding iframe support, on a per-wikiEditor instance basis.
|
||||
*/
|
||||
'extensions': {},
|
||||
extensions: {},
|
||||
|
||||
/**
|
||||
* In some cases like with the iframe's HTML file, it's convienent to have a lookup table of all instances of the
|
||||
* WikiEditor. Each context contains an instance field which contains a key that corrosponds to a reference to the
|
||||
* textarea which the WikiEditor was build around. This way, by passing a simple integer you can provide a way back
|
||||
* to a specific context.
|
||||
*/
|
||||
'instances': [],
|
||||
instances: [],
|
||||
|
||||
/**
|
||||
* For each browser name, an array of conditions that must be met are supplied in [operaton, value]-form where
|
||||
* operation is a string containing a JavaScript compatible binary operator and value is either a number to be
|
||||
* compared with $.browser.versionNumber or a string to be compared with $.browser.version. If a browser is not
|
||||
* specifically mentioned, we just assume things will work.
|
||||
*/
|
||||
'browsers': {
|
||||
browsers: {
|
||||
// Left-to-right languages
|
||||
'ltr': {
|
||||
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 - this may be a different situation with the new iframe-based solution
|
||||
'opera': [['>=', 9.6]],
|
||||
opera: [['>=', 9.6]],
|
||||
// jQuery minimums
|
||||
'safari': [['>=', 3]],
|
||||
'chrome': [['>=', 3]],
|
||||
'netscape': [['>=', 9]],
|
||||
'blackberry': false,
|
||||
'ipod': false,
|
||||
'iphone': false
|
||||
safari: [['>=', 3]],
|
||||
chrome: [['>=', 3]],
|
||||
netscape: [['>=', 9]],
|
||||
blackberry: false,
|
||||
ipod: false,
|
||||
iphone: false
|
||||
},
|
||||
// Right-to-left languages
|
||||
'rtl': {
|
||||
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 - this may be a different situation with the new iframe-based solution
|
||||
'opera': [['>=', 9.6]],
|
||||
opera: [['>=', 9.6]],
|
||||
// jQuery minimums
|
||||
'safari': [['>=', 3]],
|
||||
'chrome': [['>=', 3]],
|
||||
'netscape': [['>=', 9]],
|
||||
'blackberry': false,
|
||||
'ipod': false,
|
||||
'iphone': false
|
||||
safari: [['>=', 3]],
|
||||
chrome: [['>=', 3]],
|
||||
netscape: [['>=', 9]],
|
||||
blackberry: false,
|
||||
ipod: false,
|
||||
iphone: false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Path to images - this is a bit messy, and it would need to change if this code (and images) gets moved into the
|
||||
* core - or anywhere for that matter...
|
||||
*/
|
||||
'imgPath' : mw.config.get( 'wgExtensionAssetsPath' ) + '/WikiEditor/modules/images/',
|
||||
imgPath : mw.config.get( 'wgExtensionAssetsPath' ) + '/WikiEditor/modules/images/',
|
||||
|
||||
/**
|
||||
* Checks the current browser against the browsers object to determine if the browser has been black-listed or not.
|
||||
* Because these rules are often very complex, the object contains configurable operators and can check against
|
||||
|
@ -88,7 +93,7 @@ $.wikiEditor = {
|
|||
* "open-web" way to go.
|
||||
* @param module Module object, defaults to $.wikiEditor
|
||||
*/
|
||||
'isSupported': function( module ) {
|
||||
isSupported: function ( module ) {
|
||||
// Fallback to the wikiEditor browser map if no special map is provided in the module
|
||||
var mod = module && 'browsers' in module ? module : $.wikiEditor;
|
||||
// Check for and make use of cached value and early opportunities to bail
|
||||
|
@ -99,21 +104,23 @@ $.wikiEditor = {
|
|||
// Run a browser support test and then cache and return the result
|
||||
return mod.supported = $.client.test( mod.browsers );
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if a module has a specific requirement
|
||||
* @param module Module object
|
||||
* @param requirement String identifying requirement
|
||||
*/
|
||||
'isRequired': function( module, requirement ) {
|
||||
if ( typeof module['req'] !== 'undefined' ) {
|
||||
for ( var req in module['req'] ) {
|
||||
if ( module['req'][req] == requirement ) {
|
||||
isRequired: function ( module, requirement ) {
|
||||
if ( typeof module.req !== 'undefined' ) {
|
||||
for ( var req in module.req ) {
|
||||
if ( module.req[req] == requirement ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Provides a way to extract messages from objects. Wraps the mediaWiki.msg() function, which
|
||||
* may eventually become a wrapper for some kind of core MW functionality.
|
||||
|
@ -124,7 +131,7 @@ $.wikiEditor = {
|
|||
* would return the raw text 'that', while passing property as 'foo' would return the internationalized message
|
||||
* with the key 'bar'.
|
||||
*/
|
||||
'autoMsg': function( object, property ) {
|
||||
autoMsg: function ( object, property ) {
|
||||
// Accept array of possible properties, of which the first one found will be used
|
||||
if ( typeof property == 'object' ) {
|
||||
for ( var i in property ) {
|
||||
|
@ -147,6 +154,7 @@ $.wikiEditor = {
|
|||
return '';
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Provides a way to extract a property of an object in a certain language, falling back on the property keyed as
|
||||
* 'default' or 'default-rtl'. If such key doesn't exist, the object itself is considered the actual value, which
|
||||
|
@ -156,10 +164,11 @@ $.wikiEditor = {
|
|||
* @param object Object to extract property from
|
||||
* @param lang Language code, defaults to wgUserLanguage
|
||||
*/
|
||||
'autoLang': function( object, lang ) {
|
||||
autoLang: function ( object, lang ) {
|
||||
var defaultKey = $( 'body' ).hasClass( 'rtl' ) ? 'default-rtl' : 'default';
|
||||
return object[lang || mw.config.get( 'wgUserLanguage' )] || object[defaultKey] || object['default'] || object;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -168,7 +177,7 @@ $.wikiEditor = {
|
|||
* @param path Default icon path, defaults to $.wikiEditor.imgPath
|
||||
* @param lang Language code, defaults to wgUserLanguage
|
||||
*/
|
||||
'autoIcon': function( icon, path, lang ) {
|
||||
autoIcon: function ( icon, path, lang ) {
|
||||
var src = $.wikiEditor.autoLang( icon, lang );
|
||||
path = path || $.wikiEditor.imgPath;
|
||||
// Prepend path if src is not absolute
|
||||
|
@ -177,6 +186,7 @@ $.wikiEditor = {
|
|||
}
|
||||
return src + '?' + mw.loader.version( 'jquery.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.
|
||||
|
@ -185,7 +195,7 @@ $.wikiEditor = {
|
|||
* @param path Icon path, see autoIcon()
|
||||
* @param lang Language code, defaults to wgUserLanguage
|
||||
*/
|
||||
'autoIconOrOffset': function( icon, offset, path, lang ) {
|
||||
autoIconOrOffset: function ( icon, offset, path, lang ) {
|
||||
lang = lang || mw.config.get( 'wgUserLanguage' );
|
||||
if ( typeof offset == 'object' && lang in offset ) {
|
||||
return offset[lang];
|
||||
|
@ -200,7 +210,7 @@ $.wikiEditor = {
|
|||
/**
|
||||
* jQuery plugin that provides a way to initialize a wikiEditor instance on a textarea.
|
||||
*/
|
||||
$.fn.wikiEditor = function() {
|
||||
$.fn.wikiEditor = function () {
|
||||
|
||||
// Skip any further work when running in browsers that are unsupported
|
||||
if ( !$.wikiEditor.isSupported() ) {
|
||||
|
@ -263,21 +273,22 @@ if ( !context || typeof context == 'undefined' ) {
|
|||
* @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 modules = {};
|
||||
'addModule': function ( context, data ) {
|
||||
var module, call,
|
||||
modules = {};
|
||||
if ( typeof data == 'string' ) {
|
||||
modules[data] = {};
|
||||
} else if ( typeof data == 'object' ) {
|
||||
modules = data;
|
||||
}
|
||||
for ( var module in modules ) {
|
||||
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 ( var call in $.wikiEditor.modules[module].api ) {
|
||||
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];
|
||||
|
@ -313,7 +324,7 @@ if ( !context || typeof context == 'undefined' ) {
|
|||
/**
|
||||
* Executes core event filters as well as event handlers provided by modules.
|
||||
*/
|
||||
'trigger': function( name, event ) {
|
||||
trigger: function ( name, event ) {
|
||||
// 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' };
|
||||
|
@ -339,9 +350,9 @@ if ( !context || typeof context == 'undefined' ) {
|
|||
name in $.wikiEditor.modules[module].evt
|
||||
) {
|
||||
var ret = $.wikiEditor.modules[module].evt[name]( context, event );
|
||||
if (ret != null) {
|
||||
if (ret !== null) {
|
||||
//if 1 returns false, the end result is false
|
||||
if( returnFromModules == null ) {
|
||||
if( returnFromModules === null ) {
|
||||
returnFromModules = ret;
|
||||
} else {
|
||||
returnFromModules = returnFromModules && ret;
|
||||
|
@ -349,45 +360,47 @@ if ( !context || typeof context == 'undefined' ) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if ( returnFromModules != null ) {
|
||||
if ( returnFromModules !== null ) {
|
||||
return returnFromModules;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a button to the UI
|
||||
*/
|
||||
'addButton': function( options ) {
|
||||
addButton: function ( options ) {
|
||||
// Ensure that buttons and tabs are visible
|
||||
context.$controls.show();
|
||||
context.$buttons.show();
|
||||
return $( '<button />' )
|
||||
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 ) {
|
||||
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></div>' )
|
||||
return $( '<div>' )
|
||||
.attr( 'rel', 'wikiEditor-ui-view-' + options.name )
|
||||
.addClass( context.view == options.name ? 'current' : null )
|
||||
.append( $( '<a></a>' )
|
||||
.append( $( '<a>' )
|
||||
.attr( 'href', '#' )
|
||||
.mousedown( function() {
|
||||
.mousedown( function () {
|
||||
// No dragging!
|
||||
return false;
|
||||
} )
|
||||
.click( function( event ) {
|
||||
.click( function ( event ) {
|
||||
context.$ui.find( '.wikiEditor-ui-view' ).hide();
|
||||
context.$ui.find( '.' + $(this).parent().attr( 'rel' ) ).show();
|
||||
context.$tabs.find( 'div' ).removeClass( 'current' );
|
||||
|
@ -404,21 +417,22 @@ if ( !context || typeof context == 'undefined' ) {
|
|||
.appendTo( context.$tabs );
|
||||
}
|
||||
// Automatically add the previously not-needed wikitext tab
|
||||
if ( !context.$tabs.children().size() ) {
|
||||
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></div>' )
|
||||
return $( '<div>' )
|
||||
.addClass( 'wikiEditor-ui-view wikiEditor-ui-view-' + options.name )
|
||||
.hide()
|
||||
.appendTo( context.$ui );
|
||||
},
|
||||
|
||||
/**
|
||||
* Save scrollTop and cursor position for IE
|
||||
*/
|
||||
'saveCursorAndScrollTop': function() {
|
||||
saveCursorAndScrollTop: function () {
|
||||
if ( $.client.profile().name === 'msie' ) {
|
||||
var IHateIE = {
|
||||
'scrollTop' : context.$textarea.scrollTop(),
|
||||
|
@ -427,10 +441,11 @@ if ( !context || typeof context == 'undefined' ) {
|
|||
context.$textarea.data( 'IHateIE', IHateIE );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Restore scrollTo and cursor position for IE
|
||||
*/
|
||||
'restoreCursorAndScrollTop': function() {
|
||||
restoreCursorAndScrollTop: function () {
|
||||
if ( $.client.profile().name === 'msie' ) {
|
||||
var IHateIE = context.$textarea.data( 'IHateIE' );
|
||||
if ( IHateIE ) {
|
||||
|
@ -440,19 +455,21 @@ if ( !context || typeof context == 'undefined' ) {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Save text selection for IE
|
||||
*/
|
||||
'saveSelection': function() {
|
||||
saveSelection: function () {
|
||||
if ( $.client.profile().name === 'msie' ) {
|
||||
context.$textarea.focus();
|
||||
context.savedSelection = document.selection.createRange();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Restore text selection for IE
|
||||
*/
|
||||
'restoreSelection': function() {
|
||||
restoreSelection: function () {
|
||||
if ( $.client.profile().name === 'msie' && context.savedSelection !== null ) {
|
||||
context.$textarea.focus();
|
||||
context.savedSelection.select();
|
||||
|
@ -471,7 +488,7 @@ if ( !context || typeof context == 'undefined' ) {
|
|||
|
||||
// Assemble a temporary div to place over the wikiEditor while it's being constructed
|
||||
/* Disabling our loading div for now
|
||||
var $loader = $( '<div></div>' )
|
||||
var $loader = $( '<div>' )
|
||||
.addClass( 'wikiEditor-ui-loading' )
|
||||
.append( $( '<span>' + mediaWiki.msg( 'wikieditor-loading' ) + '</span>' )
|
||||
.css( 'marginTop', context.$textarea.height() / 2 ) );
|
||||
|
@ -482,36 +499,38 @@ if ( !context || typeof context == 'undefined' ) {
|
|||
.after( $loader )
|
||||
.add( $loader )
|
||||
*/
|
||||
.wrapAll( $( '<div></div>' ).addClass( 'wikiEditor-ui' ) )
|
||||
.wrapAll( $( '<div></div>' ).addClass( 'wikiEditor-ui-view wikiEditor-ui-view-wikitext' ) )
|
||||
.wrapAll( $( '<div></div>' ).addClass( 'wikiEditor-ui-left' ) )
|
||||
.wrapAll( $( '<div></div>' ).addClass( 'wikiEditor-ui-bottom' ) )
|
||||
.wrapAll( $( '<div></div>' ).addClass( 'wikiEditor-ui-text' ) );
|
||||
.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' ) );
|
||||
// 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></div>' ).addClass( 'wikiEditor-ui-controls' )
|
||||
.append( $( '<div></div>' ).addClass( 'wikiEditor-ui-tabs' ).hide() )
|
||||
.append( $( '<div></div>' ).addClass( 'wikiEditor-ui-buttons' ) )
|
||||
$( '<div>' ).addClass( 'wikiEditor-ui-controls' )
|
||||
.append( $( '<div>' ).addClass( 'wikiEditor-ui-tabs' ).hide() )
|
||||
.append( $( '<div>' ).addClass( 'wikiEditor-ui-buttons' ) )
|
||||
)
|
||||
.before( $( '<div style="clear:both;"></div>' ) );
|
||||
.before( $( '<div style="clear: both;"></div>' ) );
|
||||
// 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 style="clear:both;"></div>' ) );
|
||||
context.$ui.after( $( '<div style="clear: both;"></div>' ) );
|
||||
// Attach a right container
|
||||
context.$wikitext.append( $( '<div></div>' ).addClass( 'wikiEditor-ui-right' ) );
|
||||
context.$wikitext.append( $( '<div>' ).addClass( 'wikiEditor-ui-right' ) );
|
||||
// Attach a top container to the left pane
|
||||
context.$wikitext.find( '.wikiEditor-ui-left' ).prepend( $( '<div></div>' ).addClass( 'wikiEditor-ui-top' ) );
|
||||
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 ); } );
|
||||
$( window ).resize( function ( event ) {
|
||||
context.fn.trigger( 'resize', event );
|
||||
} );
|
||||
}
|
||||
|
||||
/* API Execution */
|
||||
|
@ -520,9 +539,9 @@ if ( !context || typeof context == 'undefined' ) {
|
|||
var args = $.makeArray( arguments );
|
||||
|
||||
// Dynamically setup core extensions for modules that are required
|
||||
if ( args[0] == 'addModule' && typeof args[1] != 'undefined' ) {
|
||||
if ( args[0] == 'addModule' && typeof args[1] !== 'undefined' ) {
|
||||
var modules = args[1];
|
||||
if ( typeof modules != "object" ) {
|
||||
if ( typeof modules !== "object" ) {
|
||||
modules = {};
|
||||
modules[args[1]] = '';
|
||||
}
|
||||
|
@ -536,7 +555,7 @@ if ( args[0] == 'addModule' && typeof args[1] != 'undefined' ) {
|
|||
$.inArray( e, context.extensions ) === -1
|
||||
) {
|
||||
context.extensions[context.extensions.length] = e;
|
||||
$.wikiEditor.extensions[e]( context );
|
||||
$.wikiEditor.extensions[e]( context );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -549,11 +568,13 @@ 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] );
|
||||
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 );
|
||||
|
||||
}; } )( jQuery );
|
||||
};
|
||||
|
||||
}( jQuery ) );
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* CSS for WikiEditor Preview jQuery plugin
|
||||
*/
|
||||
|
||||
|
@ -6,21 +6,26 @@
|
|||
padding: 1em;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.wikiEditor-preview-loading span {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.wikiEditor-preview-spinner {
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.wikiEditor-preview-contents {
|
||||
padding: 1em;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/* FIXME: This only works for the first wikiEditor on the page! */
|
||||
#wikiEditor-0-preview-dialog .wikiEditor-ui-loading {
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ui-dialog .ui-dialog-buttonpane {
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,28 @@
|
|||
/* Preview module for wikiEditor */
|
||||
( function( $ ) { $.wikiEditor.modules.preview = {
|
||||
( function ( $, mw ) {
|
||||
|
||||
$.wikiEditor.modules.preview = {
|
||||
|
||||
/**
|
||||
* Compatability map
|
||||
*/
|
||||
'browsers': {
|
||||
browsers: {
|
||||
// Left-to-right languages
|
||||
'ltr': {
|
||||
'msie': [['>=', 7]],
|
||||
'firefox': [['>=', 3]],
|
||||
'opera': [['>=', 9.6]],
|
||||
'safari': [['>=', 4]]
|
||||
ltr: {
|
||||
msie: [['>=', 7]],
|
||||
firefox: [['>=', 3]],
|
||||
opera: [['>=', 9.6]],
|
||||
safari: [['>=', 4]]
|
||||
},
|
||||
// Right-to-left languages
|
||||
'rtl': {
|
||||
'msie': [['>=', 8]],
|
||||
'firefox': [['>=', 3]],
|
||||
'opera': [['>=', 9.6]],
|
||||
'safari': [['>=', 4]]
|
||||
rtl: {
|
||||
msie: [['>=', 8]],
|
||||
firefox: [['>=', 3]],
|
||||
opera: [['>=', 9.6]],
|
||||
safari: [['>=', 4]]
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Internally used functions
|
||||
*/
|
||||
|
@ -29,7 +32,7 @@ fn: {
|
|||
* @param context Context object of editor to create module in
|
||||
* @param config Configuration object to create module from
|
||||
*/
|
||||
create: function( context, config ) {
|
||||
create: function ( context, config ) {
|
||||
if ( 'initialized' in context.modules.preview ) {
|
||||
return;
|
||||
}
|
||||
|
@ -41,11 +44,11 @@ fn: {
|
|||
context.modules.preview.$preview = context.fn.addView( {
|
||||
'name': 'preview',
|
||||
'titleMsg': 'wikieditor-preview-tab',
|
||||
'init': function( context ) {
|
||||
'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 ) {
|
||||
if ( context.modules.preview.previewText === wikitext ) {
|
||||
return;
|
||||
}
|
||||
context.modules.preview.$preview.find( '.wikiEditor-preview-contents' ).empty();
|
||||
|
@ -53,14 +56,14 @@ fn: {
|
|||
$.post(
|
||||
mw.util.wikiScript( 'api' ),
|
||||
{
|
||||
'action': 'parse',
|
||||
'title': mw.config.get( 'wgPageName' ),
|
||||
'text': wikitext,
|
||||
'prop': 'text',
|
||||
'pst': '',
|
||||
'format': 'json'
|
||||
format: 'json',
|
||||
action: 'parse',
|
||||
title: mw.config.get( 'wgPageName' ),
|
||||
text: wikitext,
|
||||
prop: 'text',
|
||||
pst: ''
|
||||
},
|
||||
function( data ) {
|
||||
function ( data ) {
|
||||
if (
|
||||
typeof data.parse == 'undefined' ||
|
||||
typeof data.parse.text == 'undefined' ||
|
||||
|
@ -72,7 +75,7 @@ fn: {
|
|||
context.modules.preview.$preview.find( '.wikiEditor-preview-loading' ).hide();
|
||||
context.modules.preview.$preview.find( '.wikiEditor-preview-contents' )
|
||||
.html( data.parse.text['*'] )
|
||||
.find( 'a:not([href^=#])' ).click( function() { return false; } );
|
||||
.find( 'a:not([href^=#])' ).click( false );
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
@ -82,7 +85,7 @@ fn: {
|
|||
context.$changesTab = context.fn.addView( {
|
||||
'name': 'changes',
|
||||
'titleMsg': 'wikieditor-preview-changes-tab',
|
||||
'init': function( context ) {
|
||||
'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
|
||||
|
@ -94,28 +97,28 @@ fn: {
|
|||
|
||||
// Call the API. First PST the input, then diff it
|
||||
var postdata = {
|
||||
'action': 'parse',
|
||||
'onlypst': '',
|
||||
'text': wikitext,
|
||||
'format': 'json'
|
||||
format: 'json',
|
||||
action: 'parse',
|
||||
onlypst: '',
|
||||
text: wikitext
|
||||
};
|
||||
|
||||
$.post( mw.util.wikiScript( 'api' ), postdata, function( data ) {
|
||||
$.post( mw.util.wikiScript( 'api' ), postdata, function ( data ) {
|
||||
try {
|
||||
var postdata2 = {
|
||||
'action': 'query',
|
||||
'indexpageids': '',
|
||||
'prop': 'revisions',
|
||||
'titles': mw.config.get( 'wgPageName' ),
|
||||
'rvdifftotext': data.parse.text['*'],
|
||||
'rvprop': '',
|
||||
'format': 'json'
|
||||
format: 'json',
|
||||
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;
|
||||
var section = $( '[name="wpSection"]' ).val();
|
||||
if ( section !== '' )
|
||||
postdata2.rvsection = section;
|
||||
|
||||
$.post( mw.util.wikiScript( 'api' ), postdata2, function( data ) {
|
||||
$.post( mw.util.wikiScript( 'api' ), postdata2, function ( data ) {
|
||||
// Add diff CSS
|
||||
mw.loader.load( 'mediawiki.action.history.diff' );
|
||||
try {
|
||||
|
@ -129,17 +132,17 @@ fn: {
|
|||
} catch ( e ) { } // "blah is undefined" error, ignore
|
||||
}, 'json'
|
||||
);
|
||||
} catch( e ) { } // "blah is undefined" error, ignore
|
||||
} catch ( e ) { } // "blah is undefined" error, ignore
|
||||
}, 'json' );
|
||||
}
|
||||
} );
|
||||
|
||||
var loadingMsg = mediaWiki.msg( 'wikieditor-preview-loading' );
|
||||
var loadingMsg = mw.msg( 'wikieditor-preview-loading' );
|
||||
context.modules.preview.$preview
|
||||
.add( context.$changesTab )
|
||||
.append( $( '<div />' )
|
||||
.append( $( '<div>' )
|
||||
.addClass( 'wikiEditor-preview-loading' )
|
||||
.append( $( '<img />' )
|
||||
.append( $( '<img>' )
|
||||
.addClass( 'wikiEditor-preview-spinner' )
|
||||
.attr( {
|
||||
'src': $.wikiEditor.imgPath + 'dialogs/loading.gif',
|
||||
|
@ -149,16 +152,18 @@ fn: {
|
|||
} )
|
||||
)
|
||||
.append(
|
||||
$( '<span></span>' ).text( loadingMsg )
|
||||
$( '<span>' ).text( loadingMsg )
|
||||
)
|
||||
)
|
||||
.append( $( '<div />' )
|
||||
.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>' );
|
||||
.html( '<table class="diff"><col class="diff-marker"/><col class="diff-content"/>' +
|
||||
'<col class="diff-marker"/><col class="diff-content"/><tbody/></table>' );
|
||||
}
|
||||
}
|
||||
|
||||
}; } )( jQuery );
|
||||
};
|
||||
|
||||
}( jQuery, mediaWiki ) );
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* CSS for WikiEditor Preview Dialog jQuery plugin
|
||||
*/
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
|||
overflow: hidden;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* FIXME: This only works for the first wikiEditor on the page! */
|
||||
#wikiEditor-0-preview-dialog .wikiEditor-ui-loading span {
|
||||
display: block;
|
||||
|
@ -24,12 +25,15 @@
|
|||
text-indent: -9999px;
|
||||
margin: 50px auto;
|
||||
}
|
||||
|
||||
.ui-dialog .ui-dialog-buttonpane {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.wikiEditor-preview-dialog-contents {
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
|
||||
.wikiEditor-preview-dialog-contents #firstHeading {
|
||||
font-size: 2.1em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
/* Publish module for wikiEditor */
|
||||
( function( $ ) { $.wikiEditor.modules.publish = {
|
||||
( function ( $ ) {
|
||||
|
||||
$.wikiEditor.modules.publish = {
|
||||
|
||||
/**
|
||||
* Compatability map
|
||||
*/
|
||||
'browsers': {
|
||||
browsers: {
|
||||
// Left-to-right languages
|
||||
'ltr': {
|
||||
'msie': [['>=', 7]],
|
||||
'firefox': [['>=', 3]],
|
||||
'opera': [['>=', 9.6]],
|
||||
'safari': [['>=', 4]]
|
||||
ltr: {
|
||||
msie: [['>=', 7]],
|
||||
firefox: [['>=', 3]],
|
||||
opera: [['>=', 9.6]],
|
||||
safari: [['>=', 4]]
|
||||
},
|
||||
// Right-to-left languages
|
||||
'rtl': {
|
||||
'msie': [['>=', 8]],
|
||||
'firefox': [['>=', 3]],
|
||||
'opera': [['>=', 9.6]],
|
||||
'safari': [['>=', 4]]
|
||||
rtl: {
|
||||
msie: [['>=', 8]],
|
||||
firefox: [['>=', 3]],
|
||||
opera: [['>=', 9.6]],
|
||||
safari: [['>=', 4]]
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
@ -29,7 +31,7 @@ fn: {
|
|||
* @param context Context object of editor to create module in
|
||||
* @param config Configuration object to create module from
|
||||
*/
|
||||
create: function( context, config ) {
|
||||
create: function ( context, config ) {
|
||||
// Build the dialog behind the Publish button
|
||||
var dialogID = 'wikiEditor-' + context.instance + '-dialog';
|
||||
$.wikiEditor.modules.dialogs.fn.create(
|
||||
|
@ -61,8 +63,10 @@ fn: {
|
|||
</div>\
|
||||
</form>\
|
||||
</div>',
|
||||
init: function() {
|
||||
$(this).find( '[rel]' ).each( function() {
|
||||
init: function () {
|
||||
var i;
|
||||
|
||||
$(this).find( '[rel]' ).each( function () {
|
||||
$(this).text( mediaWiki.msg( $(this).attr( 'rel' ) ) );
|
||||
});
|
||||
|
||||
|
@ -72,8 +76,8 @@ fn: {
|
|||
// TODO: internationalize by splitting on other characters that end statements
|
||||
var copyWarnStatements = copyWarnHTML.split( '. ' );
|
||||
var newCopyWarnHTML = '<ul>';
|
||||
for ( var i = 0; i < copyWarnStatements.length; i++ ) {
|
||||
if ( copyWarnStatements[i] != '' ) {
|
||||
for ( i = 0; i < copyWarnStatements.length; i++ ) {
|
||||
if ( copyWarnStatements[i] !== '' ) {
|
||||
var copyWarnStatement = $.trim( copyWarnStatements[i] ).replace( /\.*$/, '' );
|
||||
newCopyWarnHTML += '<li>' + copyWarnStatement + '.</li>';
|
||||
}
|
||||
|
@ -85,42 +89,42 @@ fn: {
|
|||
);
|
||||
/* END OF REALLY DIRTY HACK */
|
||||
|
||||
if ( $( '#wpMinoredit' ).size() == 0 )
|
||||
if ( $( '#wpMinoredit' ).length === 0 )
|
||||
$( '#wikiEditor-' + context.instance + '-dialog-minor' ).hide();
|
||||
else if ( $( '#wpMinoredit' ).is( ':checked' ) )
|
||||
$( '#wikiEditor-' + context.instance + '-dialog-minor' )
|
||||
.attr( 'checked', 'checked' );
|
||||
if ( $( '#wpWatchthis' ).size() == 0 )
|
||||
.prop( 'checked', true );
|
||||
if ( $( '#wpWatchthis' ).length === 0 )
|
||||
$( '#wikiEditor-' + context.instance + '-dialog-watch' ).hide();
|
||||
else if ( $( '#wpWatchthis' ).is( ':checked' ) )
|
||||
$( '#wikiEditor-' + context.instance + '-dialog-watch' )
|
||||
.attr( 'checked', 'checked' );
|
||||
.prop( 'checked', true );
|
||||
|
||||
$(this).find( 'form' ).submit( function( e ) {
|
||||
$(this).find( 'form' ).submit( function ( e ) {
|
||||
$(this).closest( '.ui-dialog' ).find( 'button:first' ).click();
|
||||
e.preventDefault();
|
||||
});
|
||||
},
|
||||
dialog: {
|
||||
buttons: {
|
||||
'wikieditor-publish-dialog-publish': function() {
|
||||
'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' ).attr( 'checked', minorChecked );
|
||||
$( '#wpWatchthis' ).attr( 'checked', watchChecked );
|
||||
$( '#wpMinoredit' ).prop( 'checked', minorChecked );
|
||||
$( '#wpWatchthis' ).prop( 'checked', watchChecked );
|
||||
$( '#wpSummary' ).val( $( '#wikiEditor-' + context.instance +
|
||||
'-dialog-summary' ).val() );
|
||||
$( '#editform' ).submit();
|
||||
},
|
||||
'wikieditor-publish-dialog-goback': function() {
|
||||
'wikieditor-publish-dialog-goback': function () {
|
||||
$(this).dialog( 'close' );
|
||||
}
|
||||
},
|
||||
open: function() {
|
||||
open: function () {
|
||||
$( '#wikiEditor-' + context.instance + '-dialog-summary' ).focus();
|
||||
},
|
||||
width: 500
|
||||
|
@ -129,18 +133,22 @@ fn: {
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
context.fn.addButton( {
|
||||
'captionMsg': 'wikieditor-publish-button-publish',
|
||||
'action': function() {
|
||||
'action': function () {
|
||||
$( '#' + dialogID ).dialog( 'open' );
|
||||
return false;
|
||||
}
|
||||
} );
|
||||
|
||||
context.fn.addButton( {
|
||||
'captionMsg': 'wikieditor-publish-button-cancel',
|
||||
'action': function() { }
|
||||
'action': function () { }
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
}; } )( jQuery );
|
||||
};
|
||||
|
||||
}( jQuery ) );
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc {
|
||||
border-left: solid silver 1px;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
@ -22,6 +24,7 @@
|
|||
list-style-type: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tab-toc {
|
||||
/* Should match the toolbar */
|
||||
/* @embed */
|
||||
|
@ -36,13 +39,16 @@
|
|||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tab-toc a {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
@ -51,35 +57,44 @@
|
|||
list-style: none;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul li div {
|
||||
display: block;
|
||||
font-size: 0.9em;
|
||||
cursor: pointer;
|
||||
color: #0645ad;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul li div {
|
||||
padding: 0.125em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul ul li div {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul ul ul li div {
|
||||
padding-left: 3em;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul ul ul ul li div {
|
||||
padding-left: 4em;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul ul ul ul ul li div {
|
||||
padding-left: 5em;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul ul ul ul ul ul li div {
|
||||
padding-left: 6em;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul li div.current {
|
||||
background-color: #FAFAFA;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul li div.section-0 {
|
||||
font-size: 1em;
|
||||
padding-top: 0.5em;
|
||||
|
@ -91,13 +106,14 @@
|
|||
overflow-y: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: 100%;
|
||||
margin-bottom: 0 !important;
|
||||
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc ul ul {
|
||||
float: none;
|
||||
height: auto;
|
||||
|
@ -109,15 +125,18 @@
|
|||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc-collapse-open {
|
||||
/* @embed */
|
||||
background: #f3f3f3 url(images/toc/close.png) 4px 50% no-repeat;
|
||||
border-left: 1px solid #DDDDDD;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc-collapse-closed {
|
||||
/* @embed */
|
||||
background: #f3f3f3 url(images/toc/open.png) 4px 50% no-repeat;
|
||||
}
|
||||
|
||||
/* Resizing Changes */
|
||||
.wikiEditor-ui-toc-resize-vertical,
|
||||
.ui-resizable-w {
|
||||
|
@ -128,13 +147,16 @@
|
|||
height: 100%;
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
.wikiEditor-ui .wikiEditor-ui-right {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-right .ui-resizable-w {
|
||||
left: 0px !important;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-right .wikiEditor-ui-toc-resize-grip {
|
||||
width: 5px;
|
||||
height: 12px;
|
||||
|
@ -147,11 +169,13 @@
|
|||
background: url(images/toc/grip.png) 50% 50% no-repeat;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toolbar .tab-toc {
|
||||
float: right;
|
||||
margin: 3px 16px 3px 3px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-toc-expandControl {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
|
@ -164,14 +188,17 @@
|
|||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-text textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.wikiEditor-ui-text textarea:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Self Clearing for the wikiText view */
|
||||
.wikiEditor-ui-view-wikiText {
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,7 +182,7 @@ fn: {
|
|||
$.wikiEditor.modules.toc.cfg.rtl = $( 'body' ).is( '.rtl' );
|
||||
$.wikiEditor.modules.toc.cfg.flexProperty = $.wikiEditor.modules.toc.cfg.rtl ? 'marginLeft' : 'marginRight';
|
||||
var height = context.$ui.find( '.wikiEditor-ui-left' ).height();
|
||||
context.modules.toc.$toc = $( '<div />' )
|
||||
context.modules.toc.$toc = $( '<div>' )
|
||||
.addClass( 'wikiEditor-ui-toc' )
|
||||
.data( 'context', context )
|
||||
.data( 'positionMode', 'regular' )
|
||||
|
@ -195,7 +195,7 @@ fn: {
|
|||
$.wikiEditor.modules.toc.fn.redraw( context, $.wikiEditor.modules.toc.cfg.defaultWidth );
|
||||
},
|
||||
redraw: function( context, fixedWidth ) {
|
||||
var fixedWidth = parseFloat( fixedWidth );
|
||||
fixedWidth = parseFloat( fixedWidth );
|
||||
if( context.modules.toc.$toc.data( 'positionMode' ) == 'regular' ) {
|
||||
context.$ui.find( '.wikiEditor-ui-right' )
|
||||
.css( 'width', fixedWidth + 'px' );
|
||||
|
@ -214,8 +214,9 @@ fn: {
|
|||
switchLayout: function( context ) {
|
||||
var width,
|
||||
height = context.$ui.find( '.wikiEditor-ui-right' ).height();
|
||||
if( context.modules.toc.$toc.data( 'positionMode' ) == 'regular'
|
||||
&& !context.modules.toc.$toc.data( 'collapsed' ) ) {
|
||||
if ( context.modules.toc.$toc.data( 'positionMode' ) == 'regular'
|
||||
&& !context.modules.toc.$toc.data( 'collapsed' )
|
||||
) {
|
||||
// store position mode
|
||||
context.modules.toc.$toc.data( 'positionMode', 'goofy' );
|
||||
// store the width of the TOC, to ensure we dont allow it to be larger than this when switching back
|
||||
|
@ -423,8 +424,12 @@ fn: {
|
|||
* @param {Object} outline Array of objects with level fields
|
||||
*/
|
||||
function buildStructure( outline, offset, level ) {
|
||||
if ( offset == undefined ) offset = 0;
|
||||
if ( level == undefined ) level = 1;
|
||||
if ( offset === undefined ) {
|
||||
offset = 0;
|
||||
}
|
||||
if ( level === undefined ) {
|
||||
level = 1;
|
||||
}
|
||||
var sections = [];
|
||||
for ( var i = offset; i < outline.length; i++ ) {
|
||||
if ( outline[i].nLevel == level ) {
|
||||
|
@ -445,9 +450,9 @@ fn: {
|
|||
* @param {Object} structure Structured outline
|
||||
*/
|
||||
function buildList( structure ) {
|
||||
var list = $( '<ul />' );
|
||||
var list = $( '<ul>' );
|
||||
for ( var i = 0; i < structure.length; i++ ) {
|
||||
var div = $( '<div />' )
|
||||
var div = $( '<div>' )
|
||||
.addClass( 'section-' + structure[i].index )
|
||||
.data( 'index', structure[i].index )
|
||||
.mousedown( function() {
|
||||
|
@ -457,7 +462,7 @@ fn: {
|
|||
.click( function( event ) {
|
||||
var wrapper = context.$content.find(
|
||||
'.wikiEditor-toc-section-' + $( this ).data( 'index' ) );
|
||||
if ( wrapper.size() == 0 )
|
||||
if ( wrapper.length === 0 )
|
||||
wrapper = context.$content;
|
||||
context.fn.scrollToTop( wrapper, true );
|
||||
context.$textarea.textSelection( 'setSelection', {
|
||||
|
@ -471,16 +476,16 @@ fn: {
|
|||
//$.wikiEditor.modules.toc.fn.unhighlight( context );
|
||||
$( this ).addClass( 'current' );
|
||||
//$( this ).removeClass( 'current' );
|
||||
setTimeout( function() { $.wikiEditor.modules.toc.fn.unhighlight( context ) }, 1000 );
|
||||
setTimeout( function() { $.wikiEditor.modules.toc.fn.unhighlight( context ); }, 1000 );
|
||||
|
||||
if ( typeof $.trackAction != 'undefined' )
|
||||
$.trackAction( 'ntoc.heading' );
|
||||
event.preventDefault();
|
||||
} )
|
||||
.text( structure[i].text );
|
||||
if ( structure[i].text == '' )
|
||||
if ( structure[i].text === '' )
|
||||
div.html( ' ' );
|
||||
var item = $( '<li />' ).append( div );
|
||||
var item = $( '<li>' ).append( div );
|
||||
if ( structure[i].sections !== undefined ) {
|
||||
item.append( buildList( structure[i].sections ) );
|
||||
}
|
||||
|
@ -493,11 +498,11 @@ fn: {
|
|||
*
|
||||
*/
|
||||
function buildCollapseControls( ) {
|
||||
var $collapseControl = $( '<div />' ), $expandControl = $( '<div />' );
|
||||
var $collapseControl = $( '<div>' ), $expandControl = $( '<div>' );
|
||||
$collapseControl
|
||||
.addClass( 'tab' )
|
||||
.addClass( 'tab-toc' )
|
||||
.append( '<a href="#" />' )
|
||||
.append( '<a href="#"></a>' )
|
||||
.mousedown( function( e ) {
|
||||
// No dragging!
|
||||
e.preventDefault();
|
||||
|
@ -513,7 +518,7 @@ fn: {
|
|||
.text( mediaWiki.msg( 'wikieditor-toc-hide' ) );
|
||||
$expandControl
|
||||
.addClass( 'wikiEditor-ui-toc-expandControl' )
|
||||
.append( '<a href="#" />' )
|
||||
.append( '<a href="#"></a>' )
|
||||
.mousedown( function( e ) {
|
||||
// No dragging!
|
||||
e.preventDefault();
|
||||
|
@ -546,7 +551,7 @@ fn: {
|
|||
start: function( e, ui ) {
|
||||
var $this = $( this );
|
||||
// Toss a transparent cover over our iframe
|
||||
$( '<div />' )
|
||||
$( '<div>' )
|
||||
.addClass( 'wikiEditor-ui-resize-mask' )
|
||||
.css( {
|
||||
'position': 'absolute',
|
||||
|
@ -636,8 +641,12 @@ fn: {
|
|||
// Recursively build the structure and add special item for
|
||||
// section 0, if needed
|
||||
var structure = buildStructure( outline );
|
||||
if ( $( 'input[name=wpSection]' ).val() == '' ) {
|
||||
structure.unshift( { 'text': mw.config.get( 'wgPageName' ).replace( /_/g, ' ' ), 'level': 1, 'index': 0 } );
|
||||
if ( $( 'input[name="wpSection"]' ).val() === '' ) {
|
||||
structure.unshift( {
|
||||
'text': mw.config.get( 'wgPageName' ).replace( /_/g, ' ' ),
|
||||
'level': 1,
|
||||
'index': 0
|
||||
} );
|
||||
}
|
||||
context.modules.toc.$toc.html( buildList( structure ) );
|
||||
|
||||
|
@ -645,18 +654,20 @@ fn: {
|
|||
buildResizeControls();
|
||||
buildCollapseControls();
|
||||
}
|
||||
context.modules.toc.$toc.find( 'div' ).autoEllipsis(
|
||||
{ 'position': 'right', 'tooltip': true, 'restoreText': true }
|
||||
);
|
||||
context.modules.toc.$toc.find( 'div' ).autoEllipsis( {
|
||||
'position': 'right',
|
||||
'tooltip': true,
|
||||
'restoreText': true
|
||||
} );
|
||||
}
|
||||
},
|
||||
improveUI: function() {
|
||||
/*
|
||||
* Extending resizable to allow west resizing without altering the left position attribute
|
||||
*/
|
||||
$.ui.plugin.add( "resizable", "preventPositionLeftChange", {
|
||||
$.ui.plugin.add( 'resizable', 'preventPositionLeftChange', {
|
||||
resize: function( event, ui ) {
|
||||
$( this ).data( "resizable" ).position.left = 0;
|
||||
$( this ).data( 'resizable' ).position.left = 0;
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* CSS for WikiEditor Toolbar jQuery plugin
|
||||
*/
|
||||
|
||||
|
|
Loading…
Reference in a new issue