לדלג לתוכן

משתמש:מ. רובין/ניסוי.js

מתוך חב"דפדיה, אנציקלופדיה חב"דית חופשית

הערה: לאחר הפרסום, ייתכן שיהיה צורך לנקות את זיכרון המטמון (cache) של הדפדפן כדי להבחין בשינויים.

  • פיירפוקס / ספארי: להחזיק את המקש Shift בעת לחיצה על טעינה מחדש (Reload) או ללחוץ על צירוף המקשים Ctrl-F5 או Ctrl-R (במחשב מק: ⌘-R).
  • גוגל כרום: ללחוץ על צירוף המקשים Ctrl-Shift-R (במחשב מק: ⌘-Shift-R).
  • אדג': להחזיק את המקש Ctrl בעת לחיצה על רענן (Refresh) או ללחוץ על צירוף המקשים Ctrl-F5.
*/
if ( mw.config.get( 'wgNamespaceNumber' ) === 0 ) $(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="/wiki/'+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="/wiki/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,
	linkToEscaped = ' -linksto:"'+mw.config.get('wgPageName').replace('"', '\\"')+'"';
	
	return api.get( {
		action: 'query',
		generator: 'search',
		gsrnamespace: 0,
		gsrsearch: searchRegex + linkToEscaped,
		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();
	}
}
});