MediaWiki:Gadget-morebits.js: Difference between revisions
Content deleted Content added
Amorymeltzer (talk | contribs) Repo at 27733512: swallow fake triage success; triage: Don't assume we're triaging the current page; Fix bug inverting whether we need to query protection status |
Amorymeltzer (talk | contribs) Repo at c63b1ede: add Morebits.taskManager; remove getChecked/getUnchecked from HTMLFormElement prototype"; date.monthHeader: Pass level through parseInt, allow 0 for non-wikitext returns; preview: Add parameter to render section title; Add ability to create a new section on a page; remove getChecked/getUnchecked from HTMLFormElement prototype |
||
Line 1,599:
/**
* Creates a
* @param {number} [level=2] - Header level (default 2). Pass 0 for
* just the text with no wikitext markers (==)
* @returns {string}
*/
monthHeader: function(level) {
// Default to 2, but allow for 0 or stringy numbers
level = parseInt(level, 10);
level = isNaN(level) ? 2 : level;
var header = Array(level + 1).join('='); // String.prototype.repeat not supported in IE 11
if (header.length) { // wikitext-formatted header
return header + ' ' + text + ' ' + header;
}
return text; // Just the string
}
Line 1,963 ⟶ 1,973:
* prepend([onSuccess], [onFailure]): Adds the text provided via setPrependText() to the start
* of the page. Does not require calling load() first.
*
* newSection([onSuccess], [onFailure]): Creates a new section with the text provided via setNewSectionText()
* and section title via setNewSetionTitle(). Does not require calling load() first.
*
* move([onSuccess], [onFailure]): Moves a page to another title
Line 1,983 ⟶ 1,996:
*
* setPrependText(prependText) sets the text that will be prepended to the page when prepend() is called
*
* setNewSectionText(newSectionText) sets the text that will be added in a new section when newSection() is called
*
* setNewSectionTitle(newSectionTitle) sets the title for the new section when newSection() is called
*
* setCallbackParameters(callbackParameters)
Line 2,029 ⟶ 2,046:
* ctx.saveApi.post() -> ctx.loadApi.post.success() -> ctx.fnSaveSuccess()
*
* Append to a page (similar for prepend and newSection):
* .append() -> ctx.loadApi.post() -> ctx.loadApi.post.success() ->
* ctx.fnLoadSuccess() -> ctx.fnAutoSave() -> .save() ->
Line 2,037 ⟶ 2,054:
* 1. All functions following Morebits.wiki.api.post() are invoked asynchronously
* from the jQuery AJAX library.
* 2. The sequence for append/prepend/newSection could be slightly shortened, but it would require
* significant duplication of code for little benefit.
*/
Line 2,073 ⟶ 2,090:
appendText: null, // can't reuse pageText for this because pageText is needed to follow a redirect
prependText: null, // can't reuse pageText for this because pageText is needed to follow a redirect
newSectionText: null,
newSectionTitle: null,
createOption: null,
minorEdit: false,
Line 2,234 ⟶ 2,253:
}
if (!ctx.editSummary) {
// new section mode allows (nay, encourages) using the
// title as the edit summary, but the query needs
// editSummary to be undefined or '', not null
if (ctx.editMode === 'new' && ctx.newSectionTitle) {
ctx.editSummary = '';
} else {
ctx.statusElement.error('Internal error: edit summary not set before save!');
ctx.onSaveFailure(this);
return;
}
}
Line 2,295 ⟶ 2,321:
}
query.prependtext = ctx.prependText; // use mode to prepend to current page contents
break;
case 'new':
if (!ctx.newSectionText) { // API doesn't allow empty new section text
ctx.statusElement.error('Internal error: new section text not set before save!');
ctx.onSaveFailure(this);
return;
}
query.section = 'new';
query.text = ctx.newSectionText; // add a new section to current page
query.sectiontitle = ctx.newSectionTitle || ctx.editSummary; // done by the API, but non-'' values would get treated as text
break;
case 'revert':
Line 2,352 ⟶ 2,388:
this.prepend = function(onSuccess, onFailure) {
ctx.editMode = 'prepend';
if (fnCanUseMwUserToken('edit')) {
this.save(onSuccess, onFailure);
} else {
ctx.onSaveSuccess = onSuccess;
ctx.onSaveFailure = onFailure || emptyFunction;
this.load(fnAutoSave, ctx.onSaveFailure);
}
};
/**
* Creates a new section with the text provided by setNewSectionText()
* and section title from setNewSectionTitle()
* If editSummary is provided, that will be used instead of the
* autogenerated "->Title (new section" edit summary
* Does not require calling load() first
* @param {Function} [onSuccess] - callback function which is called when the method has succeeded (optional)
* @param {Function} [onFailure] - callback function which is called when the method fails (optional)
*/
this.newSection = function(onSuccess, onFailure) {
ctx.editMode = 'new';
if (fnCanUseMwUserToken('edit')) {
Line 2,388 ⟶ 2,445:
ctx.editMode = 'prepend';
ctx.prependText = prependText;
};
/** @param {string} newSectionText - text that will be added in a new section on the page when newSection() is called */
this.setNewSectionText = function(newSectionText) {
ctx.editMode = 'new';
ctx.newSectionText = newSectionText;
};
/**
* @param {string} newSectionTitle - title for the new section created when newSection() is called
* If missing, ctx.editSummary will be used. Issues may occur if a substituted template is used
*/
this.setNewSectionTitle = function(newSectionTitle) {
ctx.editMode = 'new';
ctx.newSectionTitle = newSectionTitle;
};
Line 2,393 ⟶ 2,465:
// Edit-related setter methods:
/**
* @param {string} summary - text of the edit summary that will be used when save() is called
* Unnecessary if editMode is 'new' and newSectionTitle is provided
*/
this.setEditSummary = function(summary) {
ctx.editSummary = summary;
Line 2,993 ⟶ 3,068:
* HTML, or whether we need to ask the server for more info (e.g. protection expiry).
*
*
* deletePage, and undeletePage. Can't use for protect since it always
* needs to request protection status.
*
* @param {string} [action=edit] The action being undertaken, e.g.
Line 3,007 ⟶ 3,080:
// API-based redirect resolution only works for action=query and
// action=edit in append/prepend/new modes
if (ctx.followRedirect) {
if (!ctx.followCrossNsRedirect) {
return false; // must load the page to check for cross namespace redirects
}
if (action !== 'edit' || (ctx.editMode
return false;
}
Line 3,061 ⟶ 3,133:
};
// callback from loadSuccess() for append(), prepend(), and
var fnAutoSave = function(pageobj) {
pageobj.save(ctx.onSaveSuccess, ctx.onSaveFailure);
Line 3,182 ⟶ 3,254:
// callback from saveApi.post()
var fnSaveSuccess = function() {
ctx.editMode = 'all'; // cancel append/prepend/newSection/revert modes
var xml = ctx.saveApi.getXML();
Line 3,232 ⟶ 3,304:
ctx.statusElement.info('Edit conflict detected, reapplying edit');
if (fnCanUseMwUserToken('edit')) {
ctx.saveApi.post(); // necessarily append, prepend, or
} else {
ctx.loadApi.post(); // reload the page and reapply the edit
Line 3,281 ⟶ 3,353:
}
ctx.editMode = 'all'; // cancel append/prepend/newSection/revert modes
if (ctx.onSaveFailure) {
ctx.onSaveFailure(this); // invoke callback
Line 3,836 ⟶ 3,908:
* @param {string} wikitext - wikitext to render; most things should work, including subst: and ~~~~
* @param {string} [pageTitle] - optional parameter for the page this should be rendered as being on, if omitted it is taken as the current page
* @param {string} [sectionTitle] - if provided, render the text as a new section using this as the title
*/
this.beginRender = function(wikitext, pageTitle, sectionTitle) {
$(previewbox).show();
Line 3,852 ⟶ 3,925:
disablelimitreport: true
};
if (sectionTitle) {
query.section = 'new';
query.sectiontitle = sectionTitle;
}
var renderApi = new Morebits.wiki.api('loading...', query, fnRenderSuccess, new Morebits.status('Preview'));
renderApi.post();
Line 4,724 ⟶ 4,801:
};
/** ********** Morebits.taskManager ****************
*
* Given a set of asynchronous functions to run along with their dependencies,
* Morebits.taskManager figures out an efficient sequence of running them so
* that multiple functions that don't depend on each other are triggered
* simultaneously. Where dependencies exist, it ensures that the dependency
* functions finish running before the dependent function runs. The values
* resolved by the dependencies are made available to the dependant as arguments.
*/
Morebits.taskManager = function() {
this.taskDependencyMap = new Map();
this.deferreds = new Map();
this.allDeferreds = []; // Hack: IE doesn't support Map.prototype.values
/**
* Register a task along with its dependencies (tasks which should have finished
* execution before we can begin this one). Each task is a function that must return
* a promise. The function will get the values resolved by the dependency functions
* as arguments.
* @param {function} func - a task
* @param {function[]} deps - its dependencies
*/
this.add = function(func, deps) {
this.taskDependencyMap.set(func, deps);
var deferred = $.Deferred();
this.deferreds.set(func, deferred);
this.allDeferreds.push(deferred);
};
/**
* Run all the tasks. Multiple tasks may be run at once.
*/
this.execute = function() {
var self = this; // proxy for `this` for use inside functions where `this` is something else
this.taskDependencyMap.forEach(function(deps, task) {
var dependencyPromisesArray = deps.map(function(dep) {
return self.deferreds.get(dep);
});
$.when.apply(null, dependencyPromisesArray).then(function() {
task.apply(null, arguments).then(function() {
self.deferreds.get(task).resolve.apply(null, arguments);
});
});
});
return $.when.apply(null, this.allDeferreds); // resolved when everything is done!
};
};
/**
|