Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikipediaThe Free Encyclopedia
Search

User:Alexander Davronov/HistoryHelper.js

    From Wikipedia, the free encyclopedia
    <User:Alexander Davronov
    Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes.A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at theappropriate village pump.
    This codewill be executed when previewing this page.
    Thisuser script seems to have a documentation page atUser:Alexander Davronov/HistoryHelper.
    Note: After saving, you have to bypass your browser's cache to see the changes.Google Chrome,Firefox,Microsoft Edge andSafari: Hold down the⇧ Shift key and click theReload toolbar button. For details and instructions about other browsers, seeWikipedia:Bypass your cache.
    // Version       : 2.6.7// Last-modified :  August 07, 2023// Author        : Alexander Davronov// Description   : Toolbar for copying diff entries from revision/contributions//                 pages history on Wikipedia/*********************************************************************************** *********************************************************************************** ** HistoryHelper (Wikipedia script)                                              ** ** Copyright (C) 2021- Alex A. Davronov                                          ** **                                                                               ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR    ** ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,      ** ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE   ** ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER        ** ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING       ** ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER           ** ** DEALINGS IN THE SOFTWARE.                                                     ** *********************************************************************************** ***********************************************************************************/$(function(){"use strict";// -----------------------------------------------------------------------------// #BROWSER POLYFILLS// -----------------------------------------------------------------------------sif(!Object.assign){Object.assign=jQuery.extend;}/** * @param {string} message * @param {string} indent */varInvalidArgumentTypeError=classextendsTypeError{constructor(message,indent){indent=indentinstanceofString?indent:"";message=indent+"Invalid Argument: "+message;super(message);}};// -----------------------------------------------------------------------------// #UTILS// -----------------------------------------------------------------------------/* * Makes clipboard (temporary buffer) managment easier * @example: new ClipboardBuffer().copy('foo') // copies 'foo' string to the clipboard * Borrowed from Collect tracks v.2.js **/letClipboardBuffer=class{staticversion="1.0.0";constructor(container){this.container=container||document.body;this.id="clipboard-area";this.el=this.container.querySelector("#"+this.id);if(!this.el){this.el=document.createElement("textarea");this.container.appendChild(this.el);}this.el.style.position="absolute";this.el.style.top="-9999px";this.el.contentEditable=true;this.el.id=this.id;}copy(text){this.el.value=text;this.el.select();varresult=document.execCommand("copy");this.el.blur();returnresult;}};/** * Toolbar for buttons. * This class is tasked with book keeping of buttons. * It can retrieve buttons to assing listeners for both pointer and keyboard. * element which you can style. * @since 2.6.0 * @example * let toolbar = new Wiki.Toolbar(document.getElementById(`some-panel`)) *     toolbar.addMany([ ...htmlElements or oo.UI.ButtonWidgets ]) */// -----------------------------------------------------------------------------// #WIKI TEXT SYNTAX// -----------------------------------------------------------------------------// Wikipedia Classes NameSpacevarWiki={};/** * @since 2.6.0 */Wiki.Text=classextendsString{staticoptions={}constructor(rawWikitext,options,C){super(rawWikitext)this.C=Object.assign({},C||{});this.options=Object.assign({},this.constructor.options,options||{});}/** * https://www.mediawiki.org/wiki/ResourceLoader/Core_modules#mediawiki.api * https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api * https://www.mediawiki.org/wiki/Special:ApiSandbox#action=parse&text=%7B%7BProject:Sandbox%7D%7D&contentmodel=wikitext * @example render().done((data) => …) * @returns {mw.API} */render(){// Get rendered wikitext with no miscelanious thingsvarapi=newmw.Api();returnapi.post({action:`parse`,format:`json`,text:this,contentmodel:`wikitext`,prop:{langlinks:false,categories:false,categorieshtml:false,links:false,parsetree:false,properties:false},preview:true})}};/** Wikipedia's Template markup as string in the form of {{}} * https://en.wikipedia.org/wiki/Wikipedia:Anatomy_of_a_template * @return {TemplateTag} */Wiki.Text.Tag=class{staticIATE=InvalidArgumentTypeError;/** Basic Tokens */staticB="{{";staticD="|";staticE="}}";/** * @param {String} name - Tag name e.g. diff, oldid2 * @param {params} params - Params of the template: {diff|param1|paramX|….} */constructor(name,params){if(newObject(name).constructor!==String){thrownewthis.constructor.IATE(`Invalid arg: string expected`);}if(!(paramsinstanceofArray)){thrownewthis.constructor.IATE("params have to be an array");}letisParamString;// Replace non-string by "" (empty) stringparams=params.map((param)=>{isParamString=newObject(param)instanceofString;returnisParamString?param.toString():"";});this.name=name;this.params=params;}valueOf(){returnthis.toString();}toString(){// Create `{{name|param0|param1|paramN}}`letB=this.constructor.B;// Tag tokenletD=this.constructor.D;// Tag tokenletE=this.constructor.E;// Tag tokenletval="";val+=B;val+=this.name;for(varparamofthis.params){if(param)val+=D+param;}val+=E;returnval;}};/** * A container for Rows. Renders them into a string via toStirng() * @summary Wikipedia table wikitext wrapper */Wiki.Text.Table=classextendsString{staticIATE=InvalidArgumentTypeError;constructor({cssClasses,rows},options){super();this.options=Object.assign({caption:`Diffs`,},options||{});if(!(rowsinstanceofArray)){thrownewthis.constructor.IATE("rows have to be an array");}this.cssClasses=cssClasses||``;this.rows=rows;}valueOf(){returnthis.toString();}toString(){letrowsStr=this.rows.join("\r\n");letclassAttr=this.cssClasses?`class="${this.cssClasses}"`:``;return`{|${classAttr}\n|+${this.options.caption}\n${rowsStr}\n|}`;}};Wiki.Text.Table.Row=classextendsString{constructor({arr,value},options,C){if(value){thrownewError(`Provide array instead`);}letrows=arr.join(`||`);super(`|-\n|${rows}`);this.C=C||{};}};Wiki.Text.Table.Header=classextendsString{constructor({arr,value},options,C){if(value){thrownewError(`Provide array instead`);}letrows=arr.join(`!!`);super(`!${rows}`);this.C=C||{};}};Wiki.Text.Table.Def=classextendsString{constructor(value){if(newObject(value).value!=null){value=obj.value}super(`${value}`);}};// -----------------------------------------------------------------------------// #Wikidate// -----------------------------------------------------------------------------// @summary I convert Wikidate into Date and help to format itWiki.Date=classextendsDate{constructor(dateStr){letwdate=dateStr.split(`, `);super(wdate.slice(1).concat(wdate[0]).join(`,`));wdate=null;}// DefaultstaticdateFormat={dateStyle:`medium`,timeStyle:"short",hour12:false};// @para {object} dateFormat -  Format object, see MDN: Intl/DateTimeFormatformat(dateFormat){returnIntl.DateTimeFormat(undefined,dateFormat||this.constructor.dateFormat).format(this);}}// -----------------------------------------------------------------------------// #REVISIONS ENTRIES WRAPPER// -----------------------------------------------------------------------------/**  * @summary Container for elements of Entry class  * @class  */Wiki.Revisions=classextendsArray{staticIATE=InvalidArgumentTypeError;/** * @param {Array<Wiki.Entry>} entries * @param {HTMLElement} parentEl * @param {Object} options * @param {Object} C */constructor(entries,parentEl,options,C){super();// Contextthis.C=Object.assign({},C||{});this.options=Object.assign({},options||{});this.parentEl=parentEl;this.el=parentEl;if(entriesinstanceofArray){// throw new this.constructor.IATE(`Array is expected`);// Sieve only Entry-based instancesthis.init(entries);}}/** * @summary Clean up checkboxes left by previous script run * @description Use after revisions.fromEl() call * @param {HTMLElement} rootElement * @returns {Revisions} */staticcheckboxesCleanUp(rootElement){// Clean up previously created checkboxesif(rootElement.querySelector(`input[name="select-diff"]`)){$(rootElement).find(`input[name="select-diff"]`).parent().remove();}returnthis}// checkboxesCleanUp end/** * Helper to map HTMLElement children of revisions into Entries * @param {HTMLElement} rawRevisions - An element whose children are going to be wrapped by Entry * @param {Object} opt - Options for Revisions * @param {Object} C   - Context for Revisions * @param {Wiki.Revisions.Entry} Entry - Entry constructor * @param {Object} Eopt - For Entry    - Options for Entry * @param {Object} EC - Wiki UI native checkbox widget * @returns Revisions */staticfromEl(rawRevisions,opt,C,Entry,Eopt,EC){if(!(rawRevisions&&rawRevisions.constructor==Array&&rawRevisions.length>0)){throwthis.IATE(`${Wiki.HH.NAME}: fromEl() expects an array with elements`);}if(rawRevisions[0].constructor!=HTMLLIElement){throwthis.IATE(`${Wiki.HH.NAME}: fromEl() expects an array of li elements`);}EC=Object.assign({CheckboxInputWidget:OO.ui.CheckboxInputWidget},EC||{});letentries=rawRevisions.map((el)=>newEntry(el,Eopt,EC));// Invoking this(…) make this portablereturnnewthis(entries,rawRevisions,opt,C);}init(entries){for(leti=0;i<entries.length;i++){constentry=entries[i];if(entryinstanceofthis.constructor.Entry){this[i]=entry;entry.parent=this;}}}// Return array of checked entrieschecked(){letchecked=[];for(leti=0;i<this.length;i++){if(this[i].isChecked()){checked.push(this[i]);}}// BUG: This uncessarily registered new controls listeners if called via// built-in Array methodsreturnnewthis.constructor(checked,this.parentEl,this.options,this.C);}};// A single revision entry line containerWiki.Revisions.Entry=classextendsObject{staticIATE=InvalidArgumentTypeError;constructor(el,options,C){super();this.C=Object.assign({},C||{});if(!(elinstanceofHTMLLIElement)){thrownewthis.constructor.IATE(`<li> element expected`);}this.el=el;this.init(el);}init(el){// Revision linklethref=el.querySelector(`.mw-changeslist-links > span:nth-child(2) > a`);if(href==null){console.warn(`${Wiki.HH.NAME}: Entry()..init(): history 'prev' link isn't found, falling back to default values`);this.title="";this.diff="";this.oldid="";}else{// TODO: BUG ON MAIN PAGEleturlParams=newURL(href).searchParams;this.title=urlParams.get(`title`);this.diff=urlParams.get(`amp;diff`)||urlParams.get(`diff`);this.oldid=urlParams.get(`amp;oldid`)||urlParams.get(`oldid`);}// Dateletdate=el.querySelector(`li > a`);if(date&&date.textContent){this.date=newWiki.Date(date.textContent);}this.user=el.querySelector("bdi")&&(el.querySelector("bdi").textContent??"");letcomment=el.querySelector(".comment")??"";// Strip comments from backslashif(comment&&comment.textContent){this.comment=el.querySelector(".comment").textContent.replace(/[\(\→]/g,"");}else{this.comment=``;}}/** * Insert a given el element before entry's first element * @param {HTMLElement} el - element to be inserted before the first child */insertBefore(el){this.el.insertBefore(el,this.el.firstChild);}};/** * @summary Container for elements of EntryCB class * @class * @since 2.6.0 */Wiki.Revisions2=classextendsWiki.Revisions{/** * @param {Array<Wiki.Revisions2.EntryCB>} entries * @param {HTMLElement} parentEl * @param {Object} options * @param {Object} C */constructor(entries,parentEl,options,C){super(entries,parentEl,options,C);this.i=0;}init(entries){/** @property {Boolean} - Whether any checkbox is checked*/this.checkboxes=[];this.checkboxes.parent=this;this.checkboxes.lastClicked=[];for(leti=0;i<entries.length;i++){constentry=entries[i];if(entryinstanceofthis.constructor.Entry){this[i]=entry;// entry.parent = this;entry.parent=this;entry.checkbox.parent=this.checkboxes;this.checkboxes.push(entry.checkbox);}}}isAnyChecked(){returnthis.some(entry=>entry.checkbox.isSelected())}checked(){returnthis.filter(entry=>entry.isChecked());}};/** * The Entry extended with a checkboxk * @class * @since 2.6.0 */Wiki.Revisions2.EntryCB=classextendsWiki.Revisions.Entry{constructor(el,options,C){super(el,options,C);if(this.C.CheckboxInputWidget==null){thrownewthis.constructor.IATE(`CheckboxInputWidget is missing`);}// The value is expected to be assigned by external entitythis.parentthis.init(el);this.initCheckBox();}initCheckBox(){this.checkbox=newthis.C.CheckboxInputWidget({name:`select-diff`,value:this.el.getAttribute(`data-mw-revid`),selected:false,});this.checkbox.$element[0].style.width=`15px`;this.checkbox.$element[0].style.height=`15px`;this.checkbox.$element.mouseleave(function(e){if(e.buttons===1){this.setSelected(!this.isSelected());}}.bind(this.checkbox));this.insertBefore(this.checkbox.$element[0]);}/** * @returns {Boolean} - True if checked */isChecked(){returnthis.checkbox.isSelected();}};Wiki.Contributions=classextendsWiki.Revisions2{};Wiki.Contributions.EntryCB=classextendsWiki.Revisions2.EntryCB{staticIATE=InvalidArgumentTypeError;staticUserName=mw.config.get(`wgRelevantUserName`);constructor(el,options,C){super(el,options,C);if(!(elinstanceofHTMLLIElement)){thrownewthis.constructor.IATE(`<li> element expected`);}letcontext={};// The context here stands for imported objectthis.C=Object.assign(context,C||{});this.options=Object.assign({},options||{});this.el=el;this.init(el);}init(el){// Revision linksletdiffEl=el.querySelector(`a.mw-changeslist-diff`)||el.querySelector(`a.mw-changeslist-history`);if(diffEl==null){thrownewError(`${Wiki.HH.NAME}: can't find diff element on collaboration page.`);}lethref=diffEl.href;if(href==null){thrownewError(`${Wiki.HH.NAME}: Entry()..init(): history 'prev' link isn't found, falling back to default values`)this.title="";this.diff="";}else{leturlParams=newURL(href).searchParams;this.title=urlParams.get(`title`);this.diff=this.el.dataset["mwRevid"];}this.oldid=`prev`;this.user=this.constructor.UserName;// this.user = mw.config.get(`wgRelevantUserName`);// Dateletdate=el.querySelector(`li > a`);if(date&&date.textContent){el.querySelector(`li > a`).textContent;this.date=newWiki.Date(date.textContent);}else{this.date=newWiki.Date(date.textContent);}this.comment=``;letcommentEl=this.el.querySelector(`.comment`);if(commentEl){this.comment=commentEl.textContent.replace(/[\(\→]/g,"")}}};Wiki.Toolbar=classextendsMap{staticIATE=InvalidArgumentTypeError;staticconfig={id:`toolbar-default`}staticbuttons={[`info`]:{type:`Popup`,disabled:true,title:`Click buttons on the right`,label:`COPY AS`,icon:`doubleChevronEnd`,},[`as.diffs`]:{title:`Copy selected as {{diff|…}} wikitext`,id:`as.diffs`,label:`{{diff}}`,icon:`code`,template:`{{tqb|\n%\n}}`},[`as.table`]:{title:`Copy selected as table wikitext`,id:`as.table`,label:`<Table/>`,icon:`table`,template:``},[`as.links`]:{title:`Copy selected as raw [1]..[n] links (can be pasted into summary)`,id:`as.links`,label:`Links`,icon:`wikiText`,template:``},};staticnotice={type:'info',label:'Nothing to preview. Select checkboxes!',title:'Info',inline:true}/** * * @param {HTMLElement} toolbarEl - Container * @param {Array<Object>} buttons - Arrays of buttons widgets. See add() for supported ones * @param {Object} options - * @param {Object} C - Context */constructor(buttons,options,C){super();// Options.this.arguments=arguments;this.arguments[1]=Object.assign({},options||this.constructor.config);this.arguments[2]=Object.assign({},OO.ui,C||{});// Toolbar widgetthis.buttonsGroup=newthis.arguments[2].ButtonGroupWidget({id:this.arguments[1].id});this.$element=this.buttonsGroup.$element;this.$element.css(`z-index`,2);if(buttons){this.addMany(buttons);}}/** * @typedef  {Object} OO.ui.ButtonWidget - * @property {string} id - * @method addItems *//** * Add every button to the group, associate buttons with IDs * @example new Toolbar(); * @param {HTMLElement | OO.ui.ButtonGroupWidget | OO.ui.PopupButtonWidget} el * @returns {Wiki.Toolbar} */add(el){if(el==null){thrownewthis.constructor.IATE(`first argument is expected`);}switch(el.constructor){caseHTMLElement:this.buttonsGroup.$element[0].appendChild(el);el.id&&this.set(el.id,el);break;casethis.arguments[2].ButtonWidget:casethis.arguments[2].PopupButtonWidget:el.$element[0].id&&this.set(el.$element[0].id,el);this.buttonsGroup.addItems([el]);break;break;default:console.warn(`toolbar.add(e): unknown e.constructor.`)}returnthis;}/** * * @param {Array<HTMLElement | OO.ui.ButtonGroupWidget>} elements * @returns */addMany(elements){for(leti=0;i<elements.length;i++){this.add(elements[i]);}returnthis;}toArray(){returnArray.from(this.values())}};/** * The HistoryHelper main class used as nameSpace. * It binds provided UI elements (toolbar/revisions) and binds * Pointer (mouse) and Keyboard strokes to actionsM * (e.g. copy revisions to clipboard) */Wiki.HH=classextendsObject{staticNAME=`HistoryHelper`;staticIATE=InvalidArgumentTypeError;// TODO: Deprecate in favor of preview copy text fieldstaticshortcuts={[`ctrl+alt+d`]:`revisions.as.diffs.to.clipboard`,[`ctrl+alt+c`]:`revisions.as.links.to.clipboard`}staticoptions={fetchLimit:64}/** * Overview of basic HistoryHelper workflows * ##Clipboard workflow * revisions.keyboard -> revisionsTo…(revisions) -> clipboard.copy() * buttons.pointer.click  -> entries.to.markup -> clipboard.copy() * buttons.pointer.hover  -> buttons.popup.showPreview(revisions.as.XYZ) * ##UX workflow * buttons.popup.pointer -> preview.modify() * revisions.pointer -> entries.select * revisions.checkboxes.pointer + keyboard.shift -> entries.select * @param {Wiki.Toolbar}    revisions - Data (revisions container) * @param {Wiki.Revisions}  toolbar   - Input (butttons panel) * @param {ClipboardBuffer} clipboard - Output (clipboard buffer) * @param {Object} options - Configuration object * @param {Object} options.shortcuts - Shortcuts to Action map * @param {Object} C           - Namespace for default class constructors * @param {Object} C.Revisions - Revisions entries container constructor * @param {Object} C.Toolbar   - * @param {Object} C.Clipboard - * @param {Object} C.Text      - WikiText renderer * used to build output strings */constructor(toolbar,revisions,clipboard,options,C){super();this.C={};this.C.Revisions=Wiki.Revisions;this.C.Toolbar=Wiki.Toolbar;// Containersthis.C.Clipboard=ClipboardBuffer;this.C.Text=Wiki.Text;this.C=Object.assign(this.C,(C||{}));this.options=Object.assign({},this.constructor.options,options||{});if(!(toolbarinstanceofthis.C.Toolbar))thrownewthis.constructor.IATE(`toolbar   instance of Toolbar   is expected`);if(!(revisionsinstanceofthis.C.Revisions))thrownewthis.constructor.IATE(`revisions instance of Revisions is expected`);if(!(clipboardinstanceofthis.C.Clipboard))thrownewthis.constructor.IATE(`clipboard instance of Clipboard is expected`);this.toolbar=toolbar;this.revisions=revisions;this.clipboard=clipboard;//#ACTIONS MAP//------------------------------------------// These are intended to be invoked on some user// actions such as click or keypress// These callbacks are called from multiple places// DPRCT: [August 07, 2023] Remove clipboard functionalitythis[`revisions.as.diffs.to.clipboard`]=function(){this.clipboard.copy(this.constructor.revisionsToDIFFS(this.revisions.checked(),undefined,options))}.bind(this);this[`revisions.as.table.to.clipboard`]=function(){this.clipboard.copy(this.constructor.revisionsToTABLE(this.revisions.checked()))}.bind(this);this[`revisions.as.links.to.clipboard`]=function(){this.clipboard.copy(this.constructor.revisionsToLINKS(this.revisions.checked()))}.bind(this);this[`revisions.as.diffs.rendered`]=function(cb){letselected=this.revisions.checked().slice(0,this.options.fetchLimit);letwikitext=this.constructor.revisionsToDIFFS(selected,undefined,options);wikitext?newthis.C.Text(wikitext).render().done(cb):cb({});}.bind(this);this[`revisions.as.table.rendered`]=function(cb){letselected=this.revisions.checked().slice(0,this.options.fetchLimit);letwikitext=this.constructor.revisionsToTABLE(selected);wikitext?newthis.C.Text(wikitext).render().done(cb):cb({});}.bind(this);this[`revisions.as.links.rendered`]=function(cb){letselected=this.revisions.checked().slice(0,this.options.fetchLimit);letwikitext=this.constructor.revisionsToLINKS(selected);wikitext?newthis.C.Text(wikitext).render().done(cb):cb({});}.bind(this);this.buttons=this.toolbar.toArray();this.initButtons();this.initRevisionsListeners();this.initRevisionsSpecialListneners();}// CONSTRUCTOR END// Associate button clicks with actionsinitButtons(){//#POINTER CONTROL - BUTTONS//------------------------------------------for(letbuttonofthis.buttons){button.$element.click(this[`revisions.${button.elementId}.to.clipboard`]);// Show preview of the selected entriesbutton.$element.mouseenter(function(button,e){// Hide all popupsfor(letnextButtonofthis.buttons){nextButton.popup.toggle(false);}button.popup.toggle(true);letd0=button.popup.$lable.isVisible();if(this.revisions.isAnyChecked()){button.popup.$lable.toggle(false);setTimeout(()=>{this[`revisions.${button.elementId}.rendered`]((response)=>{if(response.parse){button.popup.html(`${response.parse.text[`*`]}`)}else{button.popup.html(``);}});},300);}else{button.popup.$lable.toggle(true);}}.bind(this,button));// bindEventEnd}}// Associate keyboard hotkeys with actions// Only works when pointer is in area of a revisions list elementinitRevisionsListeners(){//#KEYBOARD CONTROL//------------------------------------------if(this.options.shortcuts){constctrlKey=`ctrl`;constshiftKey=`shift`;constaltKey=`alt`;this.revisions.parentEl.tabIndex=1;$(this.revisions.parentEl).bind(`keyup`,(e)=>{letpressedKeys=``;pressedKeys+=e.ctrlKey?ctrlKey+`+`:``;pressedKeys+=e.shiftKey?shiftKey+`+`:``;pressedKeys+=e.altKey?altKey+`+`:``;pressedKeys+=e.key;// Match the keystroke into a an action declared aboveletaction=this[this.options.shortcuts[pressedKeys]];if(action)action();});}}// Associate keyboard + pointer hotkeys behavior// Allows selecting checkboxes range by using shift + checkbox clickinitRevisionsSpecialListneners(){//#CHECKBOXES CONTROL//------------------------------------------this.revisions.checkboxes.lastClicked[1]=this.revisions.checkboxes[0];$(this.revisions.el).click((e)=>{// Clear up preview datafor(letbuttonofthis.buttons){button.popup.html(``);}// We need to focuse only on widget's span elementletfocusedCheckbox;if(e.targetinstanceofHTMLInputElement){focusedCheckbox=e.target.parentElement;}if(e.targetinstanceofHTMLSpanElement&&/oo-ui-checkboxInputWidget/.test(e.target.className)){focusedCheckbox=e.target;}/**@type Array<CheckboxInputWidgets> */letcheckboxes=this.revisions.checkboxes;if(checkboxes.lastClicked[1]!==focusedCheckbox){checkboxes.lastClicked[0]=checkboxes.lastClicked[1];checkboxes.lastClicked[1]=focusedCheckbox;}if(e.shiftKey&&checkboxes.lastClicked[0]&&checkboxes.lastClicked[1]){letfrom=checkboxes.findIndex((widget)=>{returncheckboxes.lastClicked[0]===widget.$element[0]});letto=checkboxes.findIndex((widget)=>{returncheckboxes.lastClicked[1]===widget.$element[0]});if(from>to){letmid=to;to=from;from=mid;}from++;for(;from<to;from++){checkboxes[from].setSelected(!checkboxes[from].isSelected())}}});}// Words to higlightstatichighlights=/competen(t|cy)|IR|bitch|illiterate|fuck(er)?|asshole(ery)?|troll|idiot|dumbass|stupid|blank|subhuman|autis[tm]|(edit)? warring|inept/g;/** Convert revisions entries into a Wikitext (diffs) * @since 2.6.0 * @param {Wiki.Revisions} revisions - Array that contains Entry instances * @param {Wiki.Text.Tag} Tag * @returns {String} */staticrevisionsToDIFFS(revisions,Tag,config){Tag=Tag||Wiki.Text.Tag;if(!(revisions)){thrownewthis.IATE(`Revisions are missing`)}if(!revisions.length){return``}letentry,tag,wikitext=``;letcomment;letusers=newSet();// Walk over every entryfor(leti=0;i<revisions.length;i++){entry=revisions[i];if(entry&&newObject(entry.user).constructor==String){if(entry.user!==mw.config.get(`wgUserName`)){users.add(entry.user);}}if(entry&&newObject(entry.date).constructor==Wiki.Date){entry.date=entry.date.format();}tag=newTag(`diff`,[entry.diff,entry.oldid,entry.date,]);// Highlight specified by config words and phrases// Highlight incivilitycomment=entry.comment.replace(this.highlights,`{{highlight|$&}}`);lethighlights=config&&newObject(config.highlights);if(highlights&&highlights.constructor===Array&&highlights.length){for(leti=0,reg;i<highlights.length;i++){reg=highlights[i];comment=comment.replace(reg,`{{highlight|$&}}`);}}comment=comment?`- ''«${comment}»''`:``;wikitext+=`${tag.toString()}${comment}<br/>\n`;}if(users.size){wikitext+=':';wikitext+=newTag(`re`,Array.from(users));}returnwikitext}/** Convert revisions entries into a Wikitext (Special:Diff/… links) * @since 2.6.0 * @param {Wiki.Revisions} revisions - Array that contains Entry instances * @returns {String} */staticrevisionsToLINKS(revisions){if(!(revisions)){thrownewthis.IATE(`Revisions are missing`)}if(!revisions.length){return`No revisions selected`}letentry,wikitext=``;for(leti=0;i<revisions.length;i++){entry=revisions[i];if(entry&&newObject(entry.date).constructor==Wiki.Date){entry.date=entry.date.format();}// Omit prevletdiff=entry.oldid;if(diff=="prev"){diff=entry.diff}wikitext+=`[[Special:Diff/${diff}|[${entry.date}]]]`}returnwikitext}/** Convert revisions entries into a Wikitext (tables ) * @since 2.6.0 * @param {Wiki.Revisions} revisions - Array that contains Entry instances * @param {Wiki.Text.Tag} Tag * @param {Wiki.Text.Table} Table * @returns {String} */staticrevisionsToTABLE(revisions,Tag,Table){if(!(revisions)){thrownewthis.IATE(`Revisions are missing`)}if(!revisions.length){return``}Table=Table||Wiki.Text.Table;Tag=Tag||Wiki.Text.Tag;// Every entry wrapped into a wiki tag// Group of tags into table definitions (colums)letentry;letanchor,anchLink,diff,oldid,user,tags,entries;letdefintions=[];for(leti=0;i<revisions.length;i++){entry=revisions[i];anchLink=`hist-${i}-${entry.diff}`;anchor=newTag(`anchor`,[anchLink]);diff=newTag(`diff`,[entry.oldid,entry.date]);oldid=newTag(`oldid2`,[1,entry.oldid,entry.date]);user=newTag(`u`,[entry.user]);tags=[anchor+`[[#${anchLink}|${i}]]`,diff,oldid,user,entry.comment?`''${entry.comment}''`:``]defintions.push(tags.map(tag=>newTable.Def(tag)));}// Wrap ever column into a row// First row is the headletcolumns;letrows=[newTable.Header({arr:[`#`,`DIFF`,`CURRENT`,`USER`,`SUMMARY`],})];for(leti=0;i<defintions.length;i++){columns=defintions[i];rows.push(newTable.Row({arr:columns}))}letwikitext=newTable({cssClasses:"wikitable sortable",rows:rows,}).toString();returnwikitext;}};//#USER CONFIG//------------------------------------------// Convert legacy (prior  2.6.0) config version into a 2.6.0if(window.HistoryHelper&&window.HistoryHelper.shortcuts){letshortcuts=window.HistoryHelper.shortcuts;// 1/2 For every shortcutfor(constkeyinshortcuts){if(Object.hasOwnProperty.call(shortcuts,key)){constactionName=shortcuts[key];// 2/2 if an old action match, replace by a new oneif(actionName===`copyAsdiffs`){shortcuts[key]=`revisions.as.links.to.clipboard`;console.warn(`${Wiki.HH.NAME}: copyAsdiffs action is deprecated after v2.6.0, update your config`)}}}}letconfig=Object.assign({}// Turn off default shortcuts// ,{ shortcuts: Wiki.HH.shortcuts},,window.HistoryHelper||{});// ---------------------------------------------------------------------------// #MAIN// ---------------------------------------------------------------------------letmain=functionmain(){letcontribPageRe=/Special:Contributions/letisContributionsPage=contribPageRe.test(window.location.href);letisHistoryPage=newURL(window.location).searchParams.get("action")=="history";if(!(isContributionsPage||isHistoryPage)){return}// Initialize toolbar & buttonsletbuttons=Object.values(Wiki.Toolbar.buttons).map((data)=>{let$lable=newOO.ui.MessageWidget(Wiki.Toolbar.notice);$lable.$element.css(`min-width`,`478px`)let$content=$(`<div></div>`)// .append($notice.$element);letpopup=newOO.ui.PopupWidget({width:null,head:true,label:$lable.$element,$content:$content,padded:true,autoClose:true,autoFlip:false});popup.$element.css(`z-index`,32);popup.$element.css(`min-width`,`330px`);popup.$element.css(`min-height`,`127px`);popup.$content=$content;popup.$lable=$lable;popup.html=function(str){returnthis.$content.html(str)}letbutton=newOO.ui.ButtonWidget({...data,content:[popup]});button.popup=popup;returnbutton})//  New toolbarwindow[Wiki.Toolbar.config.id]&&window[Wiki.Toolbar.config.id].remove();lettoolbar=newWiki.Toolbar(buttons);//  Initialize revisions containerletpagehistory=document.getElementById(`pagehistory`)||document.querySelector(`#mw-content-text section.mw-pager-body`);if(!(pagehistory)){thrownewError(`${Wiki.HH.NAME}: can't find revisions html element.        \n\tThis is probably due to Wikipedia changing its HTML ids.        \n\tContact the script author for help:        \n\thttps://en.wikipedia.org/w/index.php?title=User_talk:Alexander_Davronov&action=edit&section=new`);return}//  Remove old checkboxesWiki.Revisions2.checkboxesCleanUp(pagehistory);letclipboard=newClipboardBuffer();// Article or User history page// https://www.mediawiki.org/wiki/Manual:Interface/JavaScript#mw.configif(isHistoryPage){letrawRevisions=Array.from(pagehistory.querySelectorAll(`ul > li`));letrevisions=Wiki.Revisions2.fromEl(rawRevisions,{},{},Wiki.Revisions2.EntryCB);// Adding toolsletrevCompareForm=document.getElementById(`mw-history-compare`);lettoolbarContainerTarget=revCompareForm&&revCompareForm.querySelector(`.mw-history-compareselectedversions`);$(toolbarContainerTarget).append(toolbar.$element);if(toolbar.$element[0]&&!toolbar.$element[0].children.length){thrownewError(`${Wiki.HH.NAME}: Toolbar has no buttons, please fill a bug report!`);}// Init HistoryHelper controls (button press handlers)// over toolbar and revisionsnewWiki.HH(toolbar,revisions,clipboard,config);return}// User contributions pageletisViewing=mw.config.get(`wgAction`)===`view`;if(isViewing){letrawRevisions=Array.from(pagehistory.querySelectorAll(`ul > li`));letrevisions=Wiki.Contributions.fromEl(rawRevisions,{},{},Wiki.Contributions.EntryCB,{user:mw.config.get(`wgRelevantUserName`)});lettoolbarContainerTarget=document.getElementById(`mw-content-text`).firstChild;toolbar.$element.insertAfter(toolbarContainerTarget);newWiki.HH(toolbar,revisions,clipboard,config);return}}mw.loader.using([`oojs-ui.styles.icons-editing-advanced`,`oojs-ui.styles.icons-alerts`],main);// From the End comes The Beginning!// Something ends, something begins!});
    Retrieved from "https://en.wikipedia.org/w/index.php?title=User:Alexander_Davronov/HistoryHelper.js&oldid=1169148101"

    [8]ページ先頭

    ©2009-2025 Movatter.jp