מעדיעוויקי:Gadget-quickLinker.js

ווערסיע פון 19:49, 1 מערץ 2023 דורך תנא קמא (שמועס | ביישטייערונגען) (רעדאגירונגען דורך תנא קמא (שמועס) צוריקגעשטעלט צו דער לעצטער ווערסיע פון צמא לדעת)

אַכטונג: נאכן היטן, ברויכט איר אפשר נאך אויסקרויזן דעם בראוזער'ס זאַפאַס צו זען די ענדערונגען.

  • פייערפוקס/סאפארי: האלט אראפ שיפט בשעת'ן דרוקן Reload, אדער דרוקט Ctrl-F5 אדער Ctrl-R (אויף א מאקינטאש ⌘-R)
  • גוגל כראם: דרוקט Ctrl-Shift-R (אויף א מאקינטאש ⌘-Shift-R)
  • אינטערנעט עקספלארער: האלט אראפ Ctrl בשעת'ן קליקן Refresh, אדער דרוקט Ctrl-F5
  • אפערע: גייט צו מעניו → שטעלונגען ( אפערע → פרעפערנצן אויף א מעק) און דערנאך צו פריוואטקייט & און זיכערהייט → רוימען בראוזער דאטא → בילדער און טעקעס אין זאפאס
/*
This is script for quickly adding links to article from related articles. It is especially useful for orphan articles (invoked automatically), stub articles (invoked automatically) and new articles which usually have less links compared to long existing articles.

Author: [[:he:User:ערן]]
*/
if (mw.config.get('wgContentNamespaces').includes(mw.config.get('wgNamespaceNumber'))) $(function(){
var titleNoBrackets = /(.+?)( \(|$)/.exec(mw.config.get('wgTitle')), allowedSuffix, allowedPrefix;
if (titleNoBrackets) titleNoBrackets = titleNoBrackets[1];
else return;

// allowedSuffix and allowedPrefix to have strict match for valid words (BOOK => BOOKs and not BOOKmark). default is non strict (which works better for long title)
switch ( mw.config.get('wgContentLanguage') ) {
	case 'he':
		allowedSuffix = '(?=ים|ות|[^א-ת])';
		allowedPrefix = '(?:[כלבמשהו]|[^א-ת])';
		break;
	default:
		allowedSuffix = 's?[^a-z]';
		allowedPrefix = '';
}

switch (mw.config.get('wgUserLanguage') ) {
	case 'he':
		mw.messages.set({
			'qlinker-edit' : 'עריכה מהירה',
			'qlinker-cancel' : 'ביטול',
			'linkify-summary': 'הוספת קישור ל[[$1]]',
			'qlinker-save-success': 'שמירת $1 בוצעה בהצלחה!',
			'qlinker-save-continue': 'שמירה',
			'qlinker-skip': 'דילוג דף',
			'qlinker-skip-match': 'דילוג מופע',
			'qlinker-safe-search': 'חיפוש בטוח',
			'qlinker-invoke': 'הוספת בזק של קישורים',
			'qlinker-sidelink': 'הוספת קישורים',
			'qlinker-no-results': 'לא נמצאו תוצאות',
			'qlinker-confirm-masslink': 'לדף זה יש כבר הרבה קישורים, ונדרשת זהירות בהוספת הקישורים. האם נחוצים קישורים נוספים?'
		});
	break;
	default:
		mw.messages.set({
			'qlinker-edit' : 'Quick edit',
			'qlinker-cancel' : 'Cancel',
			'linkify-summary': 'Adding link to [[$1]]',
			'qlinker-save-success': '$1 has been saved successfully!',
			'qlinker-save-continue': 'Save',
			'qlinker-skip': 'Skip page',
			'qlinker-skip-match': 'Skip match',
			'qlinker-safe-search': 'Safe search',
			'qlinker-invoke': 'Quickly add links',
			'qlinker-sidelink': 'Add links',
			'qlinker-no-results': 'No results found',
			'qlinker-confirm-masslink': 'This page already has many links. Are you sure?'
		});	
	break;
}


function createQuickEditorDialog(searchRes, safeMode){
	function QuickEditorDialog( config ) {
	  this.contextRgx = new RegExp('(.*[^\\[])(' + mw.util.escapeRegExp(titleNoBrackets) +')((?![^\\[\\{]*[\\]\\}]).*)', 'ig');
	  this.contextRgxLink = new RegExp('(.*\\[\\[)([^\\]]+?)\\|(' + mw.util.escapeRegExp(titleNoBrackets) +')(\\]\\].*)', 'ig');
	  this.pageI = -1;
	  this.matchI = 0;
	  this.searchData = null;
	  this.curPage = null;
	  this.safeMode = safeMode;
	  this.skipsCounter = 0;
	  this.starttimestamp = null;
	  this.timestamp = null;
	  QuickEditorDialog.super.call( this, config );
	}
	OO.inheritClass( QuickEditorDialog, OO.ui.ProcessDialog ); 

	// Specify a name for .addWindows()
	QuickEditorDialog.static.name = 'QuickEditorDialog';
	// Specify a title statically (or, alternatively, with data passed to the opening() method). 
	QuickEditorDialog.static.title = mw.msg('qlinker-edit');

	QuickEditorDialog.static.actions = [
	  { action: 'saveContinue', label: mw.msg('qlinker-save-continue'), flags: [ 'other', 'progressive' ], icon: 'link' },
	  { action: 'skipOne', label: mw.msg('qlinker-skip'), flags: [ 'other', 'progressive' ], icon: 'next' },
	  { action: 'skipMatch', label: mw.msg('qlinker-skip-match'), flags: [ 'other', 'progressive' ], icon: 'arrowNext' },
	  { action: 'safeSearch', label: mw.msg('qlinker-safe-search'), flags: [ 'other' ], icon: 'search' },
	  { label: mw.msg('qlinker-cancel'), flags: 'safe' }
	];

	// Customize the initialize() function: This is where to add content to the dialog body and set up event handlers. 
	QuickEditorDialog.prototype.initialize = function () {
	  // Call the parent method
	  QuickEditorDialog.super.prototype.initialize.call( this );
	  // Create and append a layout and some content.
	  this.content = new OO.ui.PanelLayout( { padded: true, expanded: true } );
	  this.$body.append( this.content.$element );
	};
	  
	QuickEditorDialog.prototype.getBodyHeight = function () {
	  return 400;
	};

	QuickEditorDialog.prototype.getSetupProcess = function ( data ) {
	  data = data || {};
	  return QuickEditorDialog.super.prototype.getSetupProcess.call( this, data )
	  .next( function () {
		// Set up contents based on data
	    this.searchData = data.searchData.query;
	    this.starttimestamp = data.searchData.curtimestamp;
		this.nextPage();
	  }, this );
	};

	// Use the getActionProcess() method to specify a process to handle the 
	// actions (for the 'save' action, in this example).
	QuickEditorDialog.prototype.getActionProcess = function ( action ) {
	  var dialog = this;
	  switch ( action ) {
		case 'skipOne':
			return new OO.ui.Process( function () {
			  dialog.skipsCounter++;
			  dialog.nextPage();
			}, this );
		case 'skipMatch':
			return new OO.ui.Process( function () {
			  dialog.skipsCounter++;
			  dialog.nextMatch();
			}, this );
		case 'saveContinue':
			return new OO.ui.Process( function () {
			  dialog.savePage();
			}, this );
		case 'safeSearch':
			return new OO.ui.Process( function () {
			  dialog.close();
			  protectedSearchQuery(true);
			}, this );
	  }

	  // Fallback to parent handler.
	  return QuickEditorDialog.super.prototype.getActionProcess.call( this, action );
	};

	QuickEditorDialog.prototype.savePage = function ( ) {
		if (this.curPage)
		{
			var api = new mw.Api(), pagename = this.curPage;
			api.postWithToken('csrf', {
				action: 'edit',
				title: this.curPage,
				summary: mw.msg('linkify-summary', mw.config.get('wgTitle')),
				minor: 1,
				basetimestamp: this.timestamp,
				starttimestamp: this.starttimestamp,
				text: this.text,
				tags: 'quick linker'
			}).done(function(d) {
				if (d && d.edit && d.edit.result == 'Success')	mw.notify(mw.msg('qlinker-save-success', pagename));
			});
		}
		var self = this;
		if(this.safeMode) setTimeout(function(){ self.nextPage(); }, 5000/(self.skipsCounter+1));
		else self.nextPage();
	};

	QuickEditorDialog.prototype.nextMatch = function ( ) {
		var m, contextPre, contextPost, contextInner, contextInnerOld, newContext, context;
		this.matchI++;
		if (this.searchData.pageids.length <= this.pageI) {
			return this.nextPage();
		}

		var page = this.searchData.pages[this.searchData.pageids[this.pageI]],
		pagecontent = page.revisions[0]['*'];
		if (page.title == mw.config.get('wgTitle')) {
			return this.nextPage();
		}

		if (m = this.contextRgx.exec(pagecontent)) {
			contextPost = m[3];
			contextInner = (m[2] == mw.config.get('wgTitle')) ? '[['+mw.config.get('wgTitle')+']]' : '[['+mw.config.get('wgTitle')+'|' + m[2] + ']]';
			contextInnerOld = '';
		}
		else if (m = this.contextRgxLink.exec(pagecontent)) {
			if(m[2].endsWith(')')) 
			{
				m = null; // other existing meaning
			}
			else 
			{
				contextPost = m[3] == mw.config.get('wgTitle')? m[4] : '|' + m[3] + m[4];
				contextInner = mw.config.get('wgTitle');
				contextInnerOld = '<s>' + m[2] + (m[3] == mw.config.get('wgTitle')? '|' : '') + '</s>';
			}
		}

		if (!m) return this.nextPage();

		context = m[0];
	 	contextPre = m[1];
		newContext = contextPre+contextInner+contextPost;
		this.content.$element.html('<h1><a href="/'+encodeURI(page.title)+'" target="_blank">'+page.title+'</a></h1><p>'+contextPre+contextInnerOld+'<b>'+contextInner+'</b>'+contextPost+'</p>');
		this.curPage = page.title;
		this.text = pagecontent.replace(context, newContext);
		this.timestamp = page.revisions[0].timestamp;
	
	};

	QuickEditorDialog.prototype.nextPage = function ( ) {
		var m, contextPre, contextPost, contextInner, contextInnerOld, newContext;
		this.pageI++;
		this.matchI = 0;
		if (this.searchData.pageids.length <= this.pageI)
		{
			if(this.curPage === null) {
				this.content.$element.html('<h1><a target="_blank" href="/Special:Search/'+encodeURI('"' + titleNoBrackets +'" -linksto:"'+mw.config.get('wgPageName') + '"')+'">'+mw.msg('qlinker-no-results')+'</a></h1>');
				this.actions.setAbilities( {
					saveContinue: false, skipOne: false
				} );
			} else {
				this.close();
			}
			return;
		}

		this.nextMatch();
	}

	// Make the window.
	var qlinkerEditor = new QuickEditorDialog( {
	  size: 'medium'
	} );

	// Create and append a window manager, which will open and close the window. 
	var windowManager = new OO.ui.WindowManager();
	$( 'body' ).append( windowManager.$element );

	// Add the window to the window manager using the addWindows() method.
	windowManager.addWindows( [ qlinkerEditor ] );

	// Open the window!
	windowManager.openWindow( qlinkerEditor,  { searchData: searchRes } );
}

function createAddLinksButton(){
	var addLinksWizard = $(mw.util.addPortletLink(
					'p-tb',
					'#',
					mw.msg('qlinker-sidelink'),
					't-quicklinker',
					mw.msg('qlinker-invoke'),
					null,
					'#t-whatlinkshere'
	));
	
	addLinksWizard.click(function(e){
		protectedSearchQuery(false);
		e.preventDefault();
	});
	return addLinksWizard;
}
function protectedSearchQuery(safeSearch)
{
	var api = new mw.Api();
	api.get( {
		action: 'query',
		prop: 'linkshere',
		lhlimit: 500,
		titles: mw.config.get('wgPageName'),
		indexpageids: 1
	}).done(function(d) {
		var isValid = true, safeMode = false;
		if(d.query && d.query.pages && d.query.pages[d.query.pageids[0]] && d.query.pages[d.query.pageids[0]].linkshere && d.query.pages[d.query.pageids[0]].linkshere.length > 100)
		{
			isValid = confirm(mw.msg('qlinker-confirm-masslink'));
			safeMode = true;
		}
		if (!isValid) return;
		searchLinksApi(safeSearch).done(function(q){
			if (q.error) mw.notify(q.error.info);
			if (!q.query || !q.query.pageids || q.query.pageids.length<=1) {
				mw.notify(mw.msg('qlinker-no-results'));
				return;
			}
			mw.loader.using(['oojs-ui-windows', 'oojs-ui.styles.icons-movement', 'oojs-ui.styles.icons-editing-core'], function() {	createQuickEditorDialog(q, safeMode) } );
		});
	})
}

function searchLinksApi(protectPrefixSuffix) {
	var api = new mw.Api(),
	searchRegexPreSufFix =  'insource:/' + allowedPrefix + mw.util.escapeRegExp(titleNoBrackets) + allowedSuffix +'/',
	searchRegexNonSafe =  'insource:/' + mw.util.escapeRegExp(titleNoBrackets) +'/',
	searchRegex = protectPrefixSuffix? searchRegexPreSufFix : searchRegexNonSafe;
	return api.get( {
		action: 'query',
		generator: 'search',
		gsrnamespace: 0,
		gsrsearch: searchRegex + ' -linksto:'+mw.config.get('wgPageName'),
		gsrlimit: 50,
		prop: 'revisions',
		rvprop: 'content|timestamp',
		indexpageids: 1,
		curtimestamp: 1
	});
}
if ($('.dmbox').length === 0) { // Don't show the tool at Disambiguation pages because it is useless
	if ($('.orphanpage, .stub').length>0) {
		searchLinksApi().done(function(d){
			if (d.query && d.query.pageids && d.query.pageids.length>1) createAddLinksButton().css('font-weight', 'bold')
		});
	}
	else {
		createAddLinksButton();
	}
}
});