Permalink
Browse files

Merge branch 'master' of https://github.com/azatoth/twinkle into vi

Conflicts:
	modules/friendlytag.js
	modules/twinklebatchdelete.js
	modules/twinklebatchundelete.js
	modules/twinkleimage.js
	modules/twinklespeedy.js
	modules/twinklewarn.js
	modules/twinklexfd.js
  • Loading branch information...
1ec5 committed Jul 22, 2014
2 parents 2ad87f2 + ad45b14 commit e334e95d84c2135dd6154b04f4b9fa79cd7e6fe0
@@ -9,26 +9,38 @@ See [Wikipedia:Twinkle][] on the English Wikipedia for more information.
[AzaToth][] is the original author and maintainer of the tool, as well as the `morebits.js` library.
Layout of this repository
-------------------------
* `moment.js`: A copy of the [moment.js][] JavaScript library, version 2.4.0. As of July 2014, it is only used by the ARV module.
* `morebits.js`: The central library used by Twinkle and many other scripts. Contains code to interact with the MediaWiki API, display forms and dialogs, generate status logs, and do various other useful things. The vast majority of code in here is not Twinkle-specific.
* `morebits.css`: Styling to accompany `morebits.js`. The portlet styles relating to the Modern skin are Twinkle-specific and should arguably be in a `twinkle.css` file.
* `sync.pl`: A Perl script to update on-wiki gadgets, or update the repository based on on-wiki changes. See below for full documentation.
* `twinkle.js`: General Twinkle-specific code, mostly related to preferences and exposing Twinkle in the UI. Significantly, it contains the default set of preferences of Twinkle.
* `modules`: Contains the individual Twinkle modules. Descriptions for these can be found in header comments or in the [Twinkle documentation][]. The module `twinkleconfig.js` powers the [Twinkle preferences panel][WP:TWPREFS].
Other files not mentioned here are probably obsolete.
Updating scripts on Wikipedia
-----------------------------
To generate the concatenated Twinkle script, use the following `bash` command:
There are two ways to upload Twinkle scripts to Wikipedia or another destination.
awk 'FNR==1{print ""}{print}' twinkle.header.js modules/*.js twinkle.footer.js > alltwinkle.js
### Manual concatenation
Then you will be able to upload `alltwinkle.js` to [MediaWiki:Gadget-Twinkle.js][]. This does not include `morebits.js` and `morebits.css`; these have to be uploaded separately.
To generate a concatenated Twinkle script, use the following `bash` command:
If `morebits.js` and/or `morebits.css` need to be updated, they should be synched to these places:
awk 'FNR==1{print ""}{print}' twinkle.js modules/*.js > alltwinkle.js
* _morebits.js_ at [MediaWiki:Gadget-morebits.js][] and [User:AzaToth/morebits.js][]
* _morebits.css_ at [MediaWiki:Gadget-morebits.css][] and [User:AzaToth/morebits.css][]
Then you will be able to upload `alltwinkle.js` to [MediaWiki:Gadget-Twinkle.js][]. The concatenation does not include `morebits.js` and `morebits.css`; these have to be uploaded separately.
[MediaWiki:Gadgets-definition][] should contain the following line:
If `morebits.js` and/or `morebits.css` need to be updated, they should be synched to [MediaWiki:Gadget-morebits.js][] and [MediaWiki:Gadget-morebits.css][].
[MediaWiki:Gadgets-definition][] would then contain the following line:
* Twinkle[ResourceLoader|dependencies=jquery.ui.dialog,jquery.tipsy]|morebits.js|morebits.css|Twinkle.js
Synchronization (for developers)
--------------------------------
### Synchronization using `sync.pl`
There is a synchronization script called `sync.pl`, which can be used to pull and push files to Wikipedia.
@@ -46,15 +58,15 @@ where `base` is the wiki path to prefix the files for `pull` and `push`.
Notice that your working directory **must** be clean; if not, either `stash` or `commit` your changes.
To `pull` user Foobar's changes, do:
To `pull` user Foobar's changes (i.e. `User:Foobar/morebits.js`), do:
./sync.pl --base User:Foobar --pull morebits.js
To `push` your changes to Foobar's wiki page, do:
./sync.pl --base User:Foobar --push morebits.js
There is also an `deploy` command to deploy the new files live.
There is also a `deploy` command to deploy all Twinkle files live.
./sync.pl --deploy twinkle.js
make deploy
@@ -68,14 +80,17 @@ While old legacy code has many different and incoherent styles, it has been deci
The [jQuery Core Style Guideline][jq_style] is what we will hereafter use as our style guideline.
Needless to say, there are exceptions. The main sticking point is spacing around parentheses. Older Twinkle code looks like `if ( condition ) {`, but newer code tends to use `if (condition) {`. The best convention here is to follow the style of surrounding code.
[Wikipedia:Twinkle]: https://en.wikipedia.org/wiki/Wikipedia:Twinkle
[AzaToth]: https://en.wikipedia.org/wiki/User:AzaToth
[moment.js]: http://momentjs.com/
[Twinkle documentation]: https://en.wikipedia.org/wiki/Wikipedia:Twinkle/doc
[WP:TWPREFS]: https://en.wikipedia.org/wiki/WP:TWPREFS
[MediaWiki:Gadget-Twinkle.js]: https://en.wikipedia.org/wiki/MediaWiki:Gadget-Twinkle.js
[User:AzaToth/twinkle.js]: https://en.wikipedia.org/wiki/User:AzaToth/twinkle.js
[MediaWiki:Gadget-morebits.js]: https://en.wikipedia.org/wiki/MediaWiki:Gadget-morebits.js
[User:AzaToth/morebits.js]: https://en.wikipedia.org/wiki/User:AzaToth/morebits.js
[MediaWiki:Gadget-morebits.css]: https://en.wikipedia.org/wiki/MediaWiki:Gadget-morebits.css
[User:AzaToth/morebits.css]: https://en.wikipedia.org/wiki/User:AzaToth/morebits.css
[MediaWiki:Gadgets-definition]: https://en.wikipedia.org/wiki/MediaWiki:Gadgets-definition
[Git::Repository]: http://search.cpan.org/perldoc?Git%3A%3ARepository
[MediaWiki::Bot]: http://search.cpan.org/perldoc?MediaWiki%3A%3ABot
@@ -328,6 +328,7 @@ Twinkle.tag.updateSortOrder = function(e) {
{ label: "{{notability|Companies}}: notability guidelines for companies and organizations", value: "Companies" },
{ label: "{{notability|Events}}: notability guideline for events", value: "Events" },
{ label: "{{notability|Films}}: notability guideline for films", value: "Films" },
{ label: "{{notability|Places}}: notability guideline for places", value: "Places" },
{ label: "{{notability|Music}}: notability guideline for music", value: "Music" },
{ label: "{{notability|Neologisms}}: notability guideline for neologisms", value: "Neologisms" },
{ label: "{{notability|Numbers}}: notability guideline for numbers", value: "Numbers" },
@@ -1132,6 +1133,13 @@ Twinkle.tag.callbacks = {
if (params.translationNotify) {
pageobj.lookupCreator(function(innerPageobj) {
var initialContrib = innerPageobj.getCreator();
// Disallow warning yourself
if (initialContrib === mw.config.get('wgUserName')) {
innerPageobj.getStatusElement().warn("Bạn (" + initialContrib + ") đã tạo trang này; bỏ qua thông báo");
return;
}
var userTalkPage = new Morebits.wiki.page('Thảo luận Thành viên:' + initialContrib,
'Notifying initial contributor (' + initialContrib + ')');
var notifytext = "\n\n== Your article [[" + Morebits.pageNameNorm + "]]==\n" +
@@ -22,7 +22,7 @@ Twinkle.batchdelete = function twinklebatchdelete() {
Twinkle.batchdelete.unlinkCache = {};
Twinkle.batchdelete.callback = function twinklebatchdeleteCallback() {
var Window = new Morebits.simpleWindow( 800, 400 );
var Window = new Morebits.simpleWindow( 600, 400 );
Window.setTitle( "Xóa hàng loạt" );
Window.setScriptName( "Twinkle" );
Window.addFooterLink( "Trợ giúp Twinkle", "WP:TW/DOC#batchdelete" );
@@ -52,9 +52,10 @@ Twinkle.batchdelete.callback = function twinklebatchdeleteCallback() {
]
} );
form.append( {
type: 'textarea',
type: 'input',
name: 'reason',
label: 'Reason: '
label: 'Reason: ',
size: 60
} );
var query;
@@ -103,17 +104,19 @@ Twinkle.batchdelete.callback = function twinklebatchdeleteCallback() {
'gapnamespace': gapnamespace ,
'gapprefix': gapprefix,
'gaplimit' : Twinkle.getPref('batchMax'), // the max for sysops
'prop' : ['categories', 'revisions' ],
'rvprop': [ 'size' ]
'prop' : 'revisions|info',
'inprop': 'protection',
'rvprop': 'size'
};
} else {
query = {
'action': 'query',
'generator': 'links',
'titles': mw.config.get( 'wgPageName' ),
'gpllimit' : Twinkle.getPref('batchMax'), // the max for sysops
'prop': [ 'categories', 'revisions' ],
'rvprop': [ 'size' ]
'prop': 'revisions|info',
'inprop': 'protection',
'rvprop': 'size'
};
}
@@ -124,27 +127,61 @@ Twinkle.batchdelete.callback = function twinklebatchdeleteCallback() {
Window.display();
var statelem = new Morebits.status("Grabbing list of pages");
var wikipedia_api = new Morebits.wiki.api( 'loading...', query, function( self ) {
var xmlDoc = self.responseXML;
var snapshot = xmlDoc.evaluate('//page[@ns != "6" and not(@missing)]', xmlDoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null ); // 6 = File: namespace
var wikipedia_api = new Morebits.wiki.api( 'loading...', query, function( apiobj ) {
var xml = apiobj.responseXML;
var $pages = $(xml).find('page').filter(':not([missing])');
var list = [];
for ( var i = 0; i < snapshot.snapshotLength; ++i ) {
var object = snapshot.snapshotItem(i);
var page = xmlDoc.evaluate( '@title', object, null, XPathResult.STRING_TYPE, null ).stringValue;
var size = xmlDoc.evaluate( 'revisions/rev/@size', object, null, XPathResult.NUMBER_TYPE, null ).numberValue;
var disputed = xmlDoc.evaluate( 'boolean(categories/cl[@title="Category:Contested candidates for speedy deletion"])', object, null, XPathResult.BOOLEAN_TYPE, null ).booleanValue;
list.push( {label:page + ' (' + size + ' bytes)' + ( disputed ? ' (DISPUTED CSD)' : '' ), value:page, checked:!disputed });
}
self.params.form.append( {
$pages.each(function(index, page) {
var $page = $(page);
var title = $page.attr('title');
var isRedir = $page.attr('redirect') === "";
var $editprot = $page.find('pr[type="edit"][level="sysop"]');
var protected = $editprot.length > 0;
var size = $page.find('rev').attr('size');
var metadata = [];
if (isRedir) {
metadata.push("redirect");
}
if (protected) {
metadata.push("fully protected" +
($editprot.attr('expiry') === 'infinity' ? ' indefinitely' : (', expires ' + $editprot.attr('expiry'))));
}
metadata.push(size + " bytes");
list.push({
label: title + (metadata.length ? (' (' + metadata.join('; ') + ')') : ''),
value: title,
checked: true,
style: (protected ? 'color:red' : '')
});
});
apiobj.params.form.append({ type: 'header', label: 'Pages to delete' });
apiobj.params.form.append({
type: 'button',
label: "Select All",
event: function(e) {
$(Morebits.quickForm.getElements(e.target.form, "pages")).prop('checked', true);
}
});
apiobj.params.form.append({
type: 'button',
label: "Deselect All",
event: function(e) {
$(Morebits.quickForm.getElements(e.target.form, "pages")).prop('checked', false);
}
});
apiobj.params.form.append( {
type: 'checkbox',
name: 'pages',
list: list
} );
self.params.form.append( { type:'submit' } );
apiobj.params.form.append( { type:'submit' } );
var result = apiobj.params.form.render();
apiobj.params.Window.setContent( result );
var result = self.params.form.render();
self.params.Window.setContent( result );
Morebits.checkboxShiftClickSupport(Morebits.quickForm.getElements(result, 'pages'));
}, statelem );
wikipedia_api.params = { form:form, Window:Window };
@@ -158,12 +195,20 @@ Twinkle.batchdelete.callback.evaluate = function twinklebatchdeleteCallbackEvalu
Morebits.wiki.actionCompleted.notice = 'Status';
Morebits.wiki.actionCompleted.postfix = 'batch deletion is now complete';
var numProtected = $(Morebits.quickForm.getElements(event.target, 'pages')).filter(function(index, element) {
return element.checked && element.nextElementSibling.style.color === 'red';
}).length;
if (numProtected > 0 && !confirm("You are about to delete " + numProtected + " fully protected page(s). Are you sure?")) {
return;
}
var pages = event.target.getChecked( 'pages' );
var reason = event.target.reason.value;
var delete_page = event.target.delete_page.checked;
var unlink_page = event.target.unlink_page.checked;
var delete_redirects = event.target.delete_redirects.checked;
if( ! reason ) {
alert("You need to give a reason, you cabal crony!");
return;
}
Morebits.simpleWindow.setButtonsEnabled( false );
@@ -185,13 +230,54 @@ Twinkle.batchdelete.callback.evaluate = function twinklebatchdeleteCallbackEvalu
Twinkle.batchdelete.currentUnlinkCounter += pages.length;
for( var i = 0; i < pages.length; ++i ) {
var page = pages[i];
var query = {
'action': 'query',
'titles': page
};
var wikipedia_api = new Morebits.wiki.api( 'Checking if page ' + page + ' exists', query, Twinkle.batchdelete.callbacks.main );
wikipedia_api.params = { page:page, reason:reason, unlink_page:unlink_page, delete_page:delete_page, delete_redirects:delete_redirects };
wikipedia_api.post();
var params = { page:page, reason:reason };
var query, wikipedia_api;
if( unlink_page ) {
query = {
'action': 'query',
'list': 'backlinks',
'blfilterredir': 'nonredirects',
'blnamespace': [0, 100], // main space and portal space only
'bltitle': page,
'bllimit': Morebits.userIsInGroup( 'sysop' ) ? 5000 : 500 // 500 is max for normal users, 5000 for bots and sysops
};
wikipedia_api = new Morebits.wiki.api( 'Grabbing backlinks', query, Twinkle.batchdelete.callbacks.unlinkBacklinksMain );
wikipedia_api.params = params;
wikipedia_api.post();
} else {
--Twinkle.batchdelete.currentUnlinkCounter;
}
if( delete_page ) {
if (delete_redirects)
{
query = {
'action': 'query',
'list': 'backlinks',
'blfilterredir': 'redirects',
'bltitle': page,
'bllimit': Morebits.userIsInGroup( 'sysop' ) ? 5000 : 500 // 500 is max for normal users, 5000 for bots and sysops
};
wikipedia_api = new Morebits.wiki.api( 'Grabbing redirects', query, Twinkle.batchdelete.callbacks.deleteRedirectsMain );
wikipedia_api.params = params;
wikipedia_api.post();
}
var wikipedia_page = new Morebits.wiki.page( page, 'Deleting page ' + page );
wikipedia_page.setEditSummary(reason + Twinkle.getPref('deletionSummaryAd'));
wikipedia_page.suppressProtectWarning();
wikipedia_page.deletePage(function( apiobj ) {
--Twinkle.batchdelete.currentDeleteCounter;
var link = document.createElement( 'a' );
var innerPage = apiobj.parent.getPageName();
link.setAttribute( 'href', mw.util.getUrl( innerPage ) );
link.setAttribute( 'title', innerPage );
link.appendChild( document.createTextNode( innerPage ) );
apiobj.getStatusElement().info( [ 'completed (' , link , ')' ] );
} );
} else {
--Twinkle.batchdelete.currentDeleteCounter;
}
}
}
}
@@ -201,64 +287,6 @@ Twinkle.batchdelete.callback.evaluate = function twinklebatchdeleteCallbackEvalu
};
Twinkle.batchdelete.callbacks = {
main: function( self ) {
var xmlDoc = self.responseXML;
var normal = xmlDoc.evaluate( '//normalized/n/@to', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;
if( normal ) {
self.params.page = normal;
}
var exists = xmlDoc.evaluate( 'boolean(//pages/page[not(@missing)])', xmlDoc, null, XPathResult.BOOLEAN_TYPE, null ).booleanValue;
if( ! exists ) {
self.statelem.error( "It seems that the page doesn't exist, perhaps it has already been deleted" );
return;
}
var query, wikipedia_api;
if( self.params.unlink_page ) {
query = {
'action': 'query',
'list': 'backlinks',
'blfilterredir': 'nonredirects',
'blnamespace': [0, 100], // main space and portal space only
'bltitle': self.params.page,
'bllimit': Morebits.userIsInGroup( 'sysop' ) ? 5000 : 500 // 500 is max for normal users, 5000 for bots and sysops
};
wikipedia_api = new Morebits.wiki.api( 'Grabbing backlinks', query, Twinkle.batchdelete.callbacks.unlinkBacklinksMain );
wikipedia_api.params = self.params;
wikipedia_api.post();
} else {
--Twinkle.batchdelete.currentUnlinkCounter;
}
if( self.params.delete_page ) {
if (self.params.delete_redirects)
{
query = {
'action': 'query',
'list': 'backlinks',
'blfilterredir': 'redirects',
'bltitle': self.params.page,
'bllimit': Morebits.userIsInGroup( 'sysop' ) ? 5000 : 500 // 500 is max for normal users, 5000 for bots and sysops
};
wikipedia_api = new Morebits.wiki.api( 'Grabbing redirects', query, Twinkle.batchdelete.callbacks.deleteRedirectsMain );
wikipedia_api.params = self.params;
wikipedia_api.post();
}
var wikipedia_page = new Morebits.wiki.page( self.params.page, 'Đang xóa trang ' + self.params.page );
wikipedia_page.setEditSummary(self.params.reason + Twinkle.getPref('deletionSummaryAd'));
wikipedia_page.deletePage(function( apiobj ) {
--Twinkle.batchdelete.currentDeleteCounter;
var link = document.createElement( 'a' );
link.setAttribute( 'href', mw.util.getUrl(self.params.page) );
link.setAttribute( 'title', self.params.page );
link.appendChild( document.createTextNode( self.params.page ) );
apiobj.statelem.info( [ 'completed (' , link , ')' ] );
} );
} else {
--Twinkle.batchdelete.currentDeleteCounter;
}
},
deleteRedirectsMain: function( self ) {
var xmlDoc = self.responseXML;
var snapshot = xmlDoc.evaluate('//backlinks/bl/@title', xmlDoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );
Oops, something went wrong.

0 comments on commit e334e95

Please sign in to comment.