Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/*
* Copyright © 2009, Daniel Friesen
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the script nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL FRIESEN ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL FRIESEN BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* <nowiki>
*/
(function($) {
'use strict';
var config = mw.config.get([
'stylepath',
'wgAction',
'wgArticleId',
'wgNamespaceNumber',
'wgPageName',
'wgTitle'
]);
if (
// If the script has already loaded..
window.ArchiveToolLoaded ||
(
// ...or if we're in a subject namespace...
config.wgNamespaceNumber % 2 === 0 ||
// ...or Special namespace...
config.wgNamespaceNumber === -1
) &&
// ...and not in Forum namespace...
config.wgNamespaceNumber !== 110 ||
// ...or not viewing or purging,
config.wgAction !== 'view' &&
config.wgAction !== 'purge'
) {
// ...there's no need to run further
return;
}
window.ArchiveToolLoaded = true;
var ArchiveTool = {
config: $.extend(true, {
archiveListTemplate: window.archiveListTemplate || 'ArchiveList',
archivePageTemplate: window.archivePageTemplate || 'ArchivePage',
archiveSubpage: 'Archive',
userLang: true
}, window.ArchiveToolConfig),
hook: function(i18n) {
$.when(
i18n.loadMessages('ArchiveTool'),
mw.loader.using('mediawiki.api')
).then(this.init.bind(this));
},
init: function(i18n) {
this.i18n = i18n;
if (!this.config.userLang) {
i18n.useContentLang();
}
this.api = new mw.Api();
$('<li>', {
id: 'control_archive',
click: this.click.bind(this)
}).append(
$('<a>', {
id: 'ca-archive',
rel: 'nofollow',
text: i18n.msg('button').plain()
})
).appendTo('.page-header__contribution-buttons .wds-list, .page-header__actions .wds-list');
},
click: function() {
var regexEscape = $.escapeRE ?
// Legacy Fandom
$.escapeRE :
mw.RegExp ?
// MediaWiki 1.26+
mw.RegExp.escape :
// MediaWiki 1.34+
mw.util.escapeRegExp;
this.regex = new RegExp(
'\\{\\{' +
regexEscape(this.config.archiveListTemplate) +
'\\}\\}'
);
this.$container = $('.WikiaArticle, #content')
.first()
.addClass('archiving')
.empty();
this.$loading = $('<span>', {
'class': 'ajax mw-ajax-loader'
});
this.$loading.appendTo(this.$container);
this.api.get({
action: 'query',
prop: 'revisions',
titles: config.wgPageName,
rvprop: 'timestamp|content',
rvslots: 'main'
}).done(this.cbRevisions.bind(this));
},
cbRevisions: function(q) {
this.$loading.hide();
var rev = q.query.pages[config.wgArticleId].revisions[0],
content = rev['*'] ? rev['*'] : rev.slots.main['*'],
lines = content.split('\n'),
$table = $('<table>', {
mousedown: this.tableClick.bind(this),
mouseup: this.tableUnclick.bind(this)
}).append(
$('<thead>').append(
$('<tr>').append(
$('<th>', {
text: this.i18n.msg('lines').plain()
}),
$('<th>', {
title: this.i18n.msg('sections').plain(),
text: '{…}'
})
)
)
).appendTo(this.$container),
$body = $('<tbody>').appendTo($table),
sections = [];
lines.forEach(function(line, i) {
$body.append(
$('<tr>', {
'class': this.regex.test(line) ? 'noarchive' : '',
'line': line
}).append(
$('<td>', {
'class': 'line',
'text': line
}).append(' ')
)
);
if (i === 0 || /^=.+?=/.test(line)) {
if (i !== 0) {
var last = sections[sections.length - 1];
last.end = i - 1;
last.length = i - last.start;
}
sections.push({
start: i
});
}
}, this);
var last = sections[sections.length - 1];
last.end = lines.length - 1;
last.length = lines.length - last.start;
sections.forEach(function(section) {
var tr = $body.children().eq(section.start);
$('<td>', {
'class': 'section',
'rowspan': section.length
}).appendTo(tr);
});
this.$body = $body;
$('<div>', {
'class': 'buttons'
}).append(
$('<a>', {
'class': 'wds-button secondary',
'click': this.clickSelect.bind(this),
'text': this.i18n.msg('select').plain()
}),
' ',
$('<a>', {
'class': 'wds-button secondary',
'click': this.clickDeselect.bind(this),
'text': this.i18n.msg('deselect').plain()
}),
' ',
$('<a>', {
'class': 'wds-button',
'click': this.archive.bind(this),
'text': this.i18n.msg('save').plain()
}),
' ',
$('<a>', {
'class': 'wds-button',
'click': this.clickAbort.bind(this),
'text': this.i18n.msg('abort').plain()
})
).prependTo(this.$container)
.clone(true)
.appendTo(this.$container);
this.clicked = false;
$('body').mouseup(this.bodyUnclick.bind(this));
},
clickAbort: function() {
this.$loading.hide();
location.href = mw.util.getUrl(config.wgPageName);
},
clickSelect: function(e) {
e.preventDefault();
this.$body.children('tr').addClass('archive');
},
clickDeselect: function(e) {
e.preventDefault();
this.$body.children('tr').removeClass('archive');
},
tableClick: function(e) {
e.preventDefault();
var $li = $(e.target).closest('tr');
if (!$li.length) {
return;
}
var $section = $(e.target).closest('.section');
if ($section.length) {
var slist = $li.nextAll(
':lt(' +
(parseInt($section.attr('rowspan'), 10) - 1) +
')'
).andSelf();
slist.toggleClass('archive', Boolean(slist.filter(function() {
return !$(this).hasClass('archive');
}).length));
return;
}
this.clicked = true;
this.add = !$li.hasClass('archive');
$li.toggleClass('archive', Boolean(this.add));
},
tableUnclick: function(e) {
if (!this.clicked) {
return;
}
var $li = $(e.target).closest('tr');
if (!$li.length) {
return;
}
$li.toggleClass('archive', Boolean(this.add));
},
bodyUnclick: function() {
this.clicked = false;
},
archive: function() {
var talkLines = [];
var archiveLines = [];
this.$body.children().each(function() {
var $this = $(this),
arr = $this.hasClass('noarchive') ||
!$this.hasClass('archive') ?
talkLines :
archiveLines;
arr.push($this.attr('line'));
});
if (!this.regex.test(talkLines[0])) {
talkLines = [
'{{' + this.config.archiveListTemplate + '}}', ''
].concat(talkLines);
}
archiveLines = [
'{{' + this.config.archivePageTemplate + '}}', ''
].concat(archiveLines);
this.$container.empty();
this.$loading.show();
this.talkContent = talkLines.join('\n');
this.archiveContent = archiveLines.join('\n');
this.run();
},
run: function() {
this.archiveNo = 1;
this.$m = $('<p>', {
text: this.i18n.msg('finding').plain()
}).appendTo(this.$container);
this.api.get({
action: 'query',
list: 'allpages',
apnamespace: config.wgNamespaceNumber,
apprefix: config.wgTitle + '/' + this.config.archiveSubpage,
aplimit: 'max',
apdir: 'ascending'
}).done(this.cbRun.bind(this));
},
cbRun: function(q) {
$.each(q.query.allpages, (function(_, value) {
var qt = parseInt(
value.title.substr(
config.wgPageName.length +
('/' + this.config.archiveSubpage).length
),
10
);
if (qt >= this.archiveNo) {
this.archiveNo = qt + 1;
}
}).bind(this));
this.archiveTitle = config.wgPageName + '/' +
this.config.archiveSubpage + ' ' +
this.archiveNo;
this.$m.append(
this.i18n.msg('done-using', this.archiveNo).escape()
);
this.saveArchive();
},
saveArchive: function() {
this.$m = $('<p>', {
text: this.i18n.msg('saving').plain()
}).appendTo(this.$container);
this.api.postWithEditToken({
action: 'edit',
title: this.archiveTitle,
text: this.archiveContent,
summary: this.i18n
.inContentLang()
.msg('summary-from', config.wgPageName)
.plain(),
minor: true,
createonly: true
}).done(this.cbSaveArchive.bind(this))
.fail(this.cbFailSave.bind(this));
},
cbSaveArchive: function(q) {
if (q.error && q.error.code === 'articleexists') {
this.$m.append(this.i18n.msg('failed').escape());
this.$container.append(
$('<p>', {
text: this.i18n.msg('exists').plain()
})
);
return this.abort();
}
this.$m.append(this.i18n.msg('done').escape());
this.saveTalk();
},
cbFailSaveArchive: function(code) {
if (code === 'articleexists') {
this.$m.append(this.i18n.msg('failed').escape());
this.$container.append(
$('<p>', {
text: this.i18n.msg('exists').plain()
})
);
this.abort();
}
},
saveTalk: function() {
this.$m = $('<p>', {
text: this.i18n.msg('updating').plain()
}).appendTo(this.$container);
this.api.postWithEditToken({
action: 'edit',
title: config.wgPageName,
text: this.talkContent,
summary: this.i18n
.inContentLang()
.msg('summary-to', this.archiveTitle)
.plain(),
minor: true
}).done(this.cbSaveTalk.bind(this))
.fail(this.cbFailSaveTalk.bind(this));
},
cbSaveTalk: function(q) {
if (q.edit.result === 'Success') {
this.$m.append(this.i18n.msg('done').escape());
this.$loading.hide();
location.href = mw.util.getUrl(config.wgPageName, {
action: 'purge'
});
} else {
this.$m.append(this.i18n.msg('failed').escape());
this.$container.append(
$('<p>', {
text: this.i18n.msg('failed-delete').plain()
})
);
this.abort();
}
},
cbFailSaveTalk: function() {
this.$m.append(this.i18n.msg('failed').escape());
this.$container.append(
$('<p>', {
text: this.i18n.msg('failed-delete').plain()
})
);
this.abort();
},
abort: function() {
this.$loading.hide();
this.$container.append(
$('<p>', {
text: this.i18n.msg('aborting').plain()
}),
$('<p>', {
html: this.i18n.msg('refresh', config.wgPageName).parse()
})
);
}
};
mw.hook('dev.i18n').add(ArchiveTool.hook.bind(ArchiveTool));
importArticles({
type: 'script',
article: 'u:dev:MediaWiki:I18n-js/code.js'
}, {
type: 'style',
article: 'u:dev:MediaWiki:ArchiveTool.css'
});
})(jQuery);
// </nowiki>