User:Alexis Jazz/Inline-editor.js

/* Extremely minimalist editor for small edits like fixing typos. Triple click the paragraph and (if nothing goes wrong) its elements become editable and buttons appear to publish/cancel. Todo: Edit summary field/minor edit checkbox Translations (import from MediaWiki) Maybe check for duplicate paragraphs? Show diff function? Known/suspected limitations: Cannot introduce new elements, only intended for plain text editing Cannot alter link targets, references, markup, etc Can only alter text that exists within a 	If you enter wikitext it'll probably save the wikitext but you'd continue to see the unparsed wikitext until you reload the page Possible bugs if you introduce new elements anyway Won't work if templates or tags are used that transclude text that doesn't exist in the wikitext. For example, generates supertext "[1]" which breaks this script. As is very common, the script has been made to ignore references. If the whole textContent of an element isn't unique in wikitext it might replace the wrong instance (Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo) //This script is public domain, irrevocably released as WTFPL Version 2[www.wtfpl.net/about/] by its author, Alexis Jazz. /*globals $:false,mw:false*/ window.AJQE={}; var AJQE=window.AJQE; AJQE.msg = { fail: 'failed to load inline editor', save: 'Publish changes', cancel: 'Cancel', savefailregexp: 'failed to save changes (not found in wikitext)', savefailapi: 'failed to save changes (API error: $ARG)', //do not translate "$ARG" summary: 'inline-editor]', success: 'Your edit was saved.' }; AJQE.findTarget=function(target,wikitext,int){ if ( target.detail != 3 ) { return; }	if ( $('.AJIE')[0] ) { //only allow one editor instance at a time return; }	if ( ! wikitext ) { AJQE.api.get( {action: 'query', prop: 'revisions', format: 'json', titles: mw.config.get('wgPageName'), rvlimit: 1, rvprop: 'timestamp|content|ids', rvslots: '*',		} ).then( function ( data ) {			AJQE.pageData=data;			if ( data.query && data.query.pages && data.query.pages[ Object.keys(data.query.pages)[0] ] && data.query.pages[ Object.keys(data.query.pages)[0] ].revisions && data.query.pages[ Object.keys(data.query.pages)[0] ].revisions[0] ) {				AJQE.pageRevisionCurrentText = data.query.pages[ Object.keys(data.query.pages)[0] ].revisions[0].slots.main['*'];				AJQE.revid=data.query.pages[ Object.keys(data.query.pages)[0] ].revisions[0].revid;				AJQE.findTarget(target,AJQE.pageRevisionCurrentText);			}		}); return; }	AJQE.target=target.target; AJQE.innerHTML=AJQE.target.innerHTML; //used to restore content upon cancel AJQE.regexArr='(.*)'; for(int=0;int<4;int++){ if ( AJQE.target.tagName != 'P' ) { AJQE.target = AJQE.target.parentElement; }	}	if ( AJQE.target.tagName != 'P' ) { //we want to work on a paragraph as a single element may not have enough unique content to locate in wikitext return; } else { AJQE.target.classList.add('AJIE'); }	for(int=0;int<AJQE.target.childNodes.length;int++){	//we can't make textnodes editable, so we make them into spans if (AJQE.target.childNodes[int].nodeName == '#text' ) { AJQE.newSpan=document.createElement('span'); AJQE.newSpan.innerText=AJQE.target.childNodes[int].textContent; $('.AJIE')[0].childNodes[int].replaceWith(AJQE.newSpan); }	}	AJQE.int2=2; for(int=0;int<AJQE.target.childNodes.length;int++){ if ( ! AJQE.target.childNodes[int].classList.contains('reference') && getComputedStyle(AJQE.target.childNodes[int]).display == 'inline' ) { AJQE.target.childNodes[int].contentEditable='true'; //make every element of the paragraph editable. Do NOT make the editable as that would (more often) allow introduction of new elements (by pressing ) which will trip things up			AJQE.regexArr+=mw.util.escapeRegExp(AJQE.target.childNodes[int].textContent)+'(.*)'; AJQE.int2++; }	}	AJQE.checkRegEx=new RegExp(AJQE.regexArr); AJQE.checkWikitextMatch=AJQE.pageRevisionCurrentText.match(AJQE.checkRegEx); if ( AJQE.checkWikitextMatch ) { AJQE.saveBtn=document.createElement('input'); AJQE.saveBtn.type='submit'; AJQE.saveBtn.id='AJQEsaveBtn'; AJQE.saveBtn.classList='cdx-button cdx-button--action-progressive cdx-button--weight-primary'; AJQE.saveBtn.style.display='inline-block'; //prevents the button from being inserted in wikitext AJQE.saveBtn.value=AJQE.msg.save; AJQE.target.append(AJQE.saveBtn); $('#AJQEsaveBtn').on('click',AJQE.saveEdit); AJQE.cancelBtn=document.createElement('input'); AJQE.cancelBtn.type='submit'; AJQE.cancelBtn.id='AJQEcancelBtn'; AJQE.cancelBtn.classList='cdx-button cdx-button--action-destructive'; AJQE.cancelBtn.style.display='inline-block'; //prevents the button from being inserted in wikitext AJQE.cancelBtn.style.margin='0 1em 0 1em'; AJQE.cancelBtn.value=AJQE.msg.cancel; AJQE.target.append(AJQE.cancelBtn); $('#AJQEcancelBtn').on('click',AJQE.cancelEdit); AJQE.target.childNodes[0].focus; } else { mw.notify(AJQE.msg.savefailregexp,{type:'error'}); } }; AJQE.saveEdit=function(int){ AJQE.regexReplacement='$1'; AJQE.int2=2; for(int=0;int<AJQE.target.childNodes.length;int++){ if ( ! AJQE.target.childNodes[int].classList.contains('reference') && getComputedStyle(AJQE.target.childNodes[int]).display == 'inline' ) { AJQE.regexReplacement+=AJQE.target.childNodes[int].textContent+'$'+AJQE.int2; AJQE.int2++; }	}	AJQE.newWikitext=AJQE.pageRevisionCurrentText.replace(AJQE.checkRegEx,AJQE.regexReplacement); if ( AJQE.newWikitext == AJQE.pageRevisionCurrentText ) { mw.notify(AJQE.msg.savefailregexp,{type:'error'}); return; }	AJQE.params = {format: 'json', assert:'user', action: 'edit', title: mw.config.get('wgPageName'), baserevid: AJQE.revid, watchlist: 'nochange', text: AJQE.newWikitext, summary: AJQE.msg.summary}; AJQE.api.postWithEditToken( AJQE.params ).then( function ( data ) {		mw.notify(AJQE.msg.success);		AJQE.removeEditor;	}, function ( code, data ) {		AJQE.removeEditor;		mw.notify(AJQE.msg.savefailapi.replace('$ARG',code),{type:'error'});	}); }; AJQE.removeEditor = function(int) { for(int=0;int<AJQE.target.childNodes.length;int++){ if ( ! AJQE.target.childNodes[int].classList.contains('reference') && getComputedStyle(AJQE.target.childNodes[int]).display == 'inline' ) { AJQE.target.childNodes[int].contentEditable='false'; }	}	$('#AJQEsaveBtn,#AJQEcancelBtn').remove; AJQE.target.classList.remove('AJIE'); }; AJQE.cancelEdit = function { $('.AJIE')[0].innerHTML = AJQE.innerHTML; $('.AJIE').removeClass('AJIE'); }; if ( mw.config.get('wgIsProbablyEditable') ) { mw.loader.using(['mediawiki.api','mediawiki.util'], function{		AJQE.api = new mw.Api;		$('#mw-content-text').on('click',AJQE.findTarget);	}); } //