User:SD0001/QuickEdit.js

/** Quick Edit **/

// Edit sections of a page without leaving the article // Forked from User:BrandonXLF/QuickEdit by User:BrandonXLF

/* globals mw, $, OO */

/** * To-do: * * [x] make enter key in edit summary save the edit * [x] handle badtoken errors * [x] popups should be enabled on links in previews * [ ] syntax highlightening * [ ] charinsert integration * [ ] toolbar integrations ? * [ ] novel keyboard shortcuts * */

$.when(	$.ready,	mw.loader.using(['oojs-ui-core', 'mediawiki.api']) ).then(function {	var mobile = mw.config.get('skin') === 'minerva';	if (mobile) {		mw.util.addCSS('.mw-editsection{white-space:nowrap}.content .collapsible-heading .-quickedit-section{visibility:hidden}.content .collapsible-heading.open-block .-quickedit-section{visibility:visible}');	}	$(document.body).on('click', function (e) { var el = $(e.target); if (!el.hasClass('-quickedit-editlink') || el.hasClass('-quickedit-loading')) { return; }

e.preventDefault; e.stopImmediatePropagation;

var dots = 0; var interval; if (!mobile) { interval = setInterval(function {				dots = (dots + 1) % 3;				el.attr('data-dots', dots);			}, 200); el.addClass('-quickedit-loading'); mw.util.addCSS('.-quickedit-hide{display:none!important}.-quickedit-loading, .-quickedit-heading{color:rgba(0, 0, 0, 0.4)}[data-dots]:after{white-space:pre}[data-dots="0"]:after{content:". "}[data-dots="1"]:after{content:".. "}[data-dots="2"]:after{content:"..."}'); }		$('.-quickedit-hide').removeClass('-quickedit-hide'); $('.-quickedit-heading').removeClass('-quickedit-heading'); $('#-quickedit-editor').remove;

var targ = el.siblings('.-quickedit-target').last;

var title = decodeURIComponent(			mw.util.getParamValue('title', targ.attr('href')) ||			(new RegExp('.*' + mw.config.get('wgArticlePath').replace(/\$1/, '([^?]+)'))).exec(targ.attr('href'))[1]		); var secid = /[\?&]v?e?section=T?-?(\d*)/.exec(targ.attr('href'))[1];

var level = 0;

$.get(mw.config.get('wgScript'), {			title: title,			section: secid,			action: 'raw'		}).then(function (full) {			$.post(mw.config.get('wgScriptPath') + '/api.php', { action: 'query', prop: 'revisions', rvprop: 'timestamp', titles: title, curtimestamp: 'true', format: 'json' }).done(function (base) { var start = base.curtimestamp; for (var id in base.query.pages) { base = base.query.pages[id].revisions[0].timestamp; }				full = full.replace(/\s+$/, '');

var saving = false; var expanded = false; var heading = el.closest('h1, h2, h3, h4, h5, h6'); var part = full.split(/(?:^|\n)(=+.+=+)/, 3).join(''); var post = full.replace(part, ''); full.replace(/^(=+)(.+)(=+)\n?/, function (m, a, b) {					level = Math.min(a.length, b.length);					sname = b;					return m;				}); if (!$.contains(document.getElementsByClassName('mw-parser-output')[0], heading[0])) { heading = $('.mw-parser-output').children.first; }				// var partsect = heading.nextUntil('#toc, h2:has(*), h3, h4, h5, h6').addClass('-quickedit-hide');

var fullsectString; switch (level) { case 6: fullsectString = 'h1, h2:has(*), h3, h4, h5, h6'; break; case 5: fullsectString = 'h1, h2:has(*), h3, h4, h5'; break; case 4: fullsectString = 'h1, h2:has(*), h3, h4'; break; case 3: fullsectString = 'h1, h2:has(*), h3'; break; case 2: fullsectString = 'h1, h2:has(*), #toc'; break; default: fullsectString = 'h1'; break; }				var fullsect = heading.nextUntil(fullsectString);

if (heading.is('h1, h2, h3, h4, h5, h6')) { heading.addClass('-quickedit-heading'); } else { heading.addClass('-quickedit-hide'); }				var textarea = new OO.ui.MultilineTextInputWidget({					rows: 1,					maxRows: 20,					autosize: true,					value: part,				}); var summary = new OO.ui.TextInputWidget({					value: heading.is('h1, h2, h3, h4, h5, h6') ? '/* ' + heading.find('.mw-headline').text + ' */ ' : ''				}); var minor = new OO.ui.CheckboxInputWidget; var save = new OO.ui.ButtonInputWidget({					label: 'Save',					title: 'Save your changes',					flags: ['primary', 'progressive']				}); var preview = new OO.ui.ButtonInputWidget({					label: 'Preview',					title: 'Preview the new wikitext'				}); var compare = new OO.ui.ButtonInputWidget({					label: 'Difference',					title: 'View the difference between the current revision and your revision'				}); var cancel = new OO.ui.ButtonInputWidget({					useInputTag: true,					label: 'Cancel',					title: 'Close the edit form and discard changes',					flags: ['secondary', 'destructive']				}); var more = new OO.ui.ButtonInputWidget({					label: '+',					title: 'Edit the entire section (including subsections)'				}); textarea.$element.find('textarea').css('border-radius', '0');

save.on('click', handleSave); summary.$element.on('keydown', function (e) {					if (e.keyCode === 13) {						handleSave;					}				});

function handleSave { var savetxt = (expanded ? textarea.getValue : textarea.getValue + post).replace(/\s+$/, '') + '\n\n'; if (saving) return; saving = true; save.setLabel('Saving...'); compare.setDisabled(true); preview.setDisabled(true); cancel.setDisabled(true); more.setDisabled(true); new mw.Api.postWithEditToken({						action: 'edit',						format: 'json',						title: title,						section: secid,						summary: summary.getValue,						text: savetxt,						minor: minor.isSelected ? true : undefined,						notminor: minor.isSelected ? undefined : true,						starttimestamp: start,						basetimestamp: base					}).then(function {						$.get(mw.config.get('wgScriptPath') + '/api.php', { action: 'parse', page: mw.config.get('wgPageName'), prop: 'text|categorieshtml', format: 'json' }).done(function (r) { $('#-quickedit-editor, .-quickedit-section').remove; $('.mw-parser-output').replaceWith(r.parse.text['*']); mw.hook('wikipage.content').fire($('#mw-content-text')); $('.catlinks').replaceWith(r.parse.categorieshtml['*']); mw.hook('wikipage.categories').fire($('.catlinks')); saving = false; });					}, function (err) {						if (err === 'editconflict') {							mw.notify('An edit conflict has occured. Please merge your changes with the conflicting changes.', { type: 'error', tag: '-quickedit-' });							$.get(mw.config.get('wgScript'), { title: title, section: secid, action: 'raw' }).done(function (newtxt) { $.post(mw.config.get('wgScriptPath') + '/api.php', {									action: 'query',									prop: 'revisions',									rvprop: 'timestamp',									titles: title,									curtimestamp: 'true',									format: 'json'								}).done(function (newbase) {									start = newbase.curtimestamp;									for (var id in newbase.query.pages) {										base = newbase.query.pages[id].revisions[0].timestamp;									}								});

function syncSize { var t1 = textarea.adjustSize.$element.find('textarea').first; var t2 = textarea2.adjustSize.$element.find('textarea').first; var rows = Math.max(t1.attr('rows'), t2.attr('rows')); var height = Math.max(t1.height, t2.height); t1.attr('rows', rows).height(height); t2.attr('rows', rows).height(height); }								compare.setDisabled(false); preview.setDisabled(false); cancel.setDisabled(false); more.$element.remove; saving = false; expanded = true; oldtxt = (expanded ? textarea.getValue : textarea.getValue + post).replace(/\s+$/, ''); newtxt = newtxt.replace(/\s+$/, ''); var textarea2 = new OO.ui.MultilineTextInputWidget({									rows: 1,									maxRows: 20,									autosize: true,									value: oldtxt,								}); textarea.setValue(newtxt); textarea.on('change', syncSize); textarea2.on('change', syncSize); save.setLabel('Save'); textarea.$element.closest('td').empty.append($(' ' : ' No differences. ');								});							}).fail(function { mw.notify('An error occurred while getting the new revision, perhaps the section was deleted. Try reloading the page.', {									type: 'error',									tag: '-quickedit-'								}); });							return;						}						if (err) {							compare.setDisabled(false);							preview.setDisabled(false);							cancel.setDisabled(false);							more.setDisabled(expanded);							mw.notify(err, { type: 'error', tag: '-quickedit-' });							saving = false;							save.setLabel('Save');							return;						}					}); }				preview.on('click', function {					$('#-quickedit-editor .previewtable').css({ margin: '0.5em 0', border: '1px solid #a2a9b1' });					$('#-quickedit-editor .preview').html('Loading...');					$.post(mw.config.get('wgScriptPath') + '/api.php', { action: 'parse', format: 'json', title: title, prop: 'text', pst: 'true', disablelimitreport: 'true', disableeditsection: 'true', sectionpreview: 'true', disabletoc: 'true', text: textarea.getValue.replace(/\s+$/, '') + '\n\n' }).done(function (r) { $('#-quickedit-editor .preview').html(r.parse.text['*'] + ' '); mw.hook('wikipage.content').fire($('#-quickedit-editor .preview')); });				});				compare.on('click', function {					$('#-quickedit-editor .previewtable').css({ margin: '0.5em 0', border: '1px solid #a2a9b1' });					$('#-quickedit-editor .preview').html('Loading...');					mw.loader.load('mediawiki.diff.styles');					$.post(mw.config.get('wgScriptPath') + '/api.php', { action: 'compare', format: 'json', fromslots: 'main', 'fromtext-main': part + (expanded ? post : ''), fromtitle: title, frompst: 'true', toslots: 'main', 'totext-main': textarea.getValue.replace(/\s+$/, '') + '\n\n', totitle: title, topst: 'true' }).done(function (r) { $('#-quickedit-editor .preview').html(r.compare['*'] ? ' ' : ' No differences.  '); });				});				cancel.on('click', function {					$('#-quickedit-editor').remove;					fullsect.removeClass('-quickedit-hide');					$('.-quickedit-heading').removeClass('-quickedit-heading');				}); more.on('click', function {					expanded = true;					textarea.setValue(textarea.getValue + post);					fullsect.addClass('-quickedit-hide');					more.setDisabled(true);				}); if (!mobile) { el.removeClass('-quickedit-loading').removeAttr('data-dots'); clearInterval(interval); el.html('quick edit'); }				heading.after($(' ')					.append($(' ') );			});

}).fail(function { if (!mobile) { el.removeClass('-quickedit-loading').removeAttr('data-dots'); clearInterval(interval); el.html('quick edit'); }			mw.notify('An error occurred while getting section wikitext, perhaps it was deleted. Try reloading the page.', {				type: 'error',				tag: '-quickedit-'			}); });	});

mw.hook('wikipage.content').add(function {		$('.mw-editsection').each(function  { $('[href*="title="][href*="section="]', this).last .after((mobile ? '' : ' | ') + '' + (mobile ? ' Q' : 'quick edit') + '') .addClass('-quickedit-target'); });	}); });