משתמש:Tomer T/בקשות ממפעילים.js

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

  • פיירפוקס / ספארי: להחזיק את המקש Shift בעת לחיצה על טעינה מחדש (Reload) או ללחוץ על צירוף המקשים Ctrl-F5 או Ctrl-R (במחשב מק: ⌘-R).
  • גוגל כרום: ללחוץ על צירוף המקשים Ctrl-Shift-R (במחשב מק: ⌘-Shift-R).
  • אינטרנט אקספלורר / אדג': להחזיק את המקש Ctrl בעת לחיצה על רענן (Refresh) או ללחוץ על צירוף המקשים Ctrl-F5.
  • אופרה: ללחוץ על Ctrl-F5.
// סקריפט שמאפשר לנקות את ויקיפדיה:בקשות ממעפילים מבקשות שטופלו
// בקשות למחיקה יוסרו אם הדף מחוק
// בקשות הגנה יוסרו אם הערך הוגן לאחר מועד הבקשה (או 5 דקות לפני)
// בקשות חסימה יוסרו אם המשתמש נחסם לאחר מועד הבקשה (או 5 דקות לפני)
// שימו לב: הסקריפט יודע לזהות רק בקשות שנכתבו באמצעות התבניות המתאימות - ״בקשת מחיקה״, ״לחסום״ ו״בקשת הגנה
// כמו כן, הסקריפט יסיר תגובות לאותה בקשה אם היא טופלה. מכיוון שניתן להקליד טקסט חופשי בדף, הסקריפט עשוי לטעות בזיהוי הטקסט שיש להסיר, ולכן לפני ההסרה הוא מציג בקשת אישור לבקשות שזוהו, ומומלץ לבדוק את התוצאה לאחר השימוש.
// Authored by User:Tomer T
mw.loader.using(['mediawiki.api']).then(function () {
    $(function () {
		var title = mw.config.get('wgPageName');
        if (title.indexOf( ":בקשות_ממפעילים") < 0) return;
        var allEditableSections = $('.mw-editsection');
        for (var i = 0; i < allEditableSections.length; i++) {
			var editableSection = $(allEditableSections).eq(i);
			var sectionHeaderElem = editableSection.parent()[0];
			// This will retreive the header level - for h1 ("=") - 1, for h2 ("==") - 2, etc.
            var headerLevel = sectionHeaderElem.tagName.split('H')[1];
			// We don't want to add any button for the highest header - for example next to the edit source button attached to the page title ("בקשות ממפעילים")
            if (headerLevel < 2) continue;
			
			// Check if section is supported
			var supportedSections = ["בקשות מחיקה", "בקשות חסימה / הסרת חסימה", "בקשות הגנה / הסרת הגנה"];
			var sectionTitle = "";
			for (var j = 0; j < sectionHeaderElem.childNodes.length; j++) {
				if (sectionHeaderElem.childNodes[j].className == "mw-headline") {
					sectionTitle = sectionHeaderElem.childNodes[j].innerText;
					break;
				}
			}
			if (!supportedSections.includes(sectionTitle)) {
				continue;
			}
			
			// This will retreive the link to edit this section
            var relativeEditURL = editableSection.children('a').eq(0).attr('href');
			// Extracting the section number
            var secNumMatch = relativeEditURL.match(/action=edit&section=(\d+)/);
            if (!secNumMatch) { continue };
			// Second item in the struct is the match inside parentheses
            var secNum = secNumMatch[1];
			
			function monthToNum(monthStr) {
				switch(monthStr) {
					case "ינואר":
						return 1;
					case "פברואר":
						return 2;
					case "מרץ":
						return 3;
					case "אפריל":
						return 4;
					case "מאי":
						return 5;
					case "יוני":
						return 6;
					case "יולי":
						return 7;
					case "אוגוסט":
						return 8;
					case "ספטמבר":
						return 9;
					case "אוקטובר":
						return 10;
					case "נובמבר":
						return 11;
					case "דצמבר":
						return 12;						
				}
				return 0;
			}
			
			function parseDate(dateStr) {
				var signatureDateMatch = dateStr.match(/(\d{2})\:(\d{2})\,\s+(\d{1,2})\s+(ב(ינואר|פברואר|מרץ|אפריל|מאי|יוני|יולי|אוגוסט|ספטמבר|אוקטובר|נובמבר|דצמבר))\s+(\d{4})/);
				var signatureDate = null;
				if (signatureDateMatch) { 
					var d = {"hour": signatureDateMatch[1], "minute": signatureDateMatch[2], "day": signatureDateMatch[3], "month": monthToNum(signatureDateMatch[5]), "year": signatureDateMatch[6]};
					signatureDate = new Date(d.year, d.month -1, d.day, d.hour, d.minute);
				}
				return signatureDate;
			}
			
			function cleanSection(data, toRemove, secNum, header) {
				var changedData = data;
				var willRemove = "";
				
				for (item of toRemove) {
					changedData = changedData && changedData.replaceAll(item.content, "");
					willRemove = willRemove + item.name + ", ";
				}
				willRemove = willRemove.substring(0, willRemove.length - 2);
				
				if (willRemove.length == 0) {
					mw.notify("לא נמצאו בקשות שניתן להסיר");
					return;
				}
				
				if (confirm('הבקשות הבאות יוסרו - ' + willRemove + ". האם ברצונך להמשיך?")) {
					// Save it!
					var fullSummary = "/*" + header + "*/" + "הוסרו " + toRemove.length + " בקשות שטופלו";
				
					new mw.Api().postWithToken('csrf', { action: 'edit', section: secNum, text: changedData, summary: fullSummary, title: title }).done(function (done) {
						if (done.edit.result == 'Success') {
							location.reload();
						} else {
							mw.notify('Server error: section not cleaned');
						}
					})
				} else {
					// Do nothing!
					console.log('User declined change.');
				}
			}
			
			function clearDeletionReq(deletionRequest) {
				// Find the first "|" in the template, and get evertyhing following it, that is not "|" or "}"
				var deleteTitleMatch = deletionRequest.match(/\*\s*{{בקשת מחיקה\s*\|\s*([^\|\}]*).*}}/);
				if (!deleteTitleMatch) { 
					mw.notify('Unexpected error: could not find deletion title');
					return null;
				}
				var deleteTitle = deleteTitleMatch[1];
				return [$.ajax({
					url: mw.config.get('wgServer') + '/w/index.php',
					data: {action: 'raw', title: deleteTitle},
				}), deleteTitle];
			}
			
			function handleDeletionSection(reg, data, toRemove, secNum, header) {
				var req;
				console.log("handleDeletionSection");
				if((req = reg.exec(data)) !== null) {
					fullReq = req[1];
					console.log("fullReq " + fullReq);
					var clear = clearDeletionReq(fullReq);
					clear[0].done(function() {
						// Done - page exists, don't remove
						console.log("don't remove");
						handleDeletionSection(reg, data, toRemove, secNum, header);
					}).fail(function() {
						// Fail - page doesn't exist, remove
						console.log("remove " + clear[1]);
						toRemove.push({"name": clear[1], "content": fullReq});
						handleDeletionSection(reg, data, toRemove, secNum, header);
					});
				} else {
					cleanSection(data, toRemove, secNum, header);
				}
			}
			
			function readBlockLog(blockRequest) {
				// Find the first "|" in the template, and get evertyhing following it, that is not "|" or "}"
				var blockUserMatch = blockRequest.match(/\*\s*{{לחסום\s*\|\s*([^\|\}]*).*}}/);
				if (!blockUserMatch) { 
					mw.notify('Unexpected error: could not find username to block');
					return null;
				}
				var username = blockUserMatch[1];
				var signatureDate = parseDate(blockRequest);

				return [$.ajax({
					url: mw.config.get('wgServer') + '/w/index.php',
					data: {action: 'raw', title: "מיוחד:יומנים", type: "block", page:  "משתמש:" + username},
					dataType: 'html',
				}), signatureDate, "משתמש:" + username];
			}
			
			function clearByLatestLog(dataLog, signatureDate, page, loglineClass) {
				var doc = new DOMParser().parseFromString(dataLog, "text/html");
				var logLines = doc.getElementsByClassName(loglineClass);
				if (logLines.length == 0) {
					return null;
				}
				var latestLogLine = logLines[0];
				var date = $(latestLogLine).children('a')[0].innerHTML;
				var latestLogDate = parseDate(date);
				var MS_PER_MINUTE = 60000;
				// We support removing a case of a request, that was requested up to 5 minutes prior to the actual block/protect action (= a request that was redundant all along)
				if (signatureDate && latestLogDate && (latestLogDate >= new Date(signatureDate - 5 * MS_PER_MINUTE))) {
					return page;
				} else {
					return null;
				}
			}
			
			function handleBlockSection(reg, data, toRemove, secNum, header) {
				var req;
				if((req = reg.exec(data)) !== null) {
					fullReq = req[1];
					block = readBlockLog(fullReq);
					block[0].done(function(d) {
						var toClear = clearByLatestLog(d, block[1], block[2], 'mw-logline-block');
						if (toClear !== null) {
							console.log("remove " + toClear);
							toRemove.push({"name": toClear, "content": fullReq});
						} else {
							console.log("don't remove");
						}
						handleBlockSection(reg, data, toRemove, secNum, header);
					});
				} else {
					cleanSection(data, toRemove, secNum, header);
				}
			}
			
			function readProtectLog(protectRequest) {
				// Find the first "|" in the template, and get evertyhing following it, that is not "|" or "}"
				var protectPageMatch = protectRequest.match(/\*\s*{{בקשת הגנה\s*\|\s*([^\|\}]*).*}}/);
				if (!protectPageMatch) { 
					mw.notify('Unexpected error: could not find page to protect');
					return null;
				}
				var page = protectPageMatch[1];
				var signatureDate = parseDate(protectRequest);

				return [$.ajax({
					url: mw.config.get('wgServer') + '/w/index.php',
					data: {action: 'raw', title: "מיוחד:יומנים", type: "protect", page: page},
					dataType: 'html',
				}), signatureDate, page];
			}
			
			function handleProtectSection(reg, data, toRemove, secNum, header) {
				var req;
				if((req = reg.exec(data)) !== null) {
					fullReq = req[1];
					protect = readProtectLog(fullReq);
					protect[0].done(function(d) {
						var toClear = clearByLatestLog(d, protect[1], protect[2], 'mw-logline-protect');
						if (toClear !== null) {
							console.log("remove " + toClear);
							toRemove.push({"name": toClear, "content": fullReq});
						} else {
							console.log("don't remove");
						}
						handleProtectSection(reg, data, toRemove, secNum, header);
					});
				} else {
					cleanSection(data, toRemove, secNum, header);
				}
			}

            function done(secNum) {
                var URL = mw.config.get('wgServer') + '/w/index.php?title=' + title + '&action=raw&section=' + secNum;
                $.get(URL, function (data, status) {
					var headerMatch = data.match(/==(.+?)==/);
					var header = headerMatch[1];
					
					var type = 0;
					var toRemove = [];
					switch(header.trim()) {
						case "בקשות מחיקה":
							 handleDeletionSection(/(\*\s*{{בקשת מחיקה.+}}.*(\n+|$)(\s*(\*\*|\:|\*+\:).+(\n+|$))*)/g, data, toRemove, secNum, header);
							 break;
						case "בקשות חסימה / הסרת חסימה":
						     handleBlockSection(/(\*\s*{{לחסום.+}}.*(\n+|$)(\s*(\*\*|\:|\*+\:).+(\n+|$))*)/g, data, toRemove, secNum, header);
							 break;
						case "בקשות הגנה / הסרת הגנה":
							 handleProtectSection(/(\*\s*{{בקשת הגנה.+}}.*(\n+|$)(\s*(\*\*|\:|\*+\:).+(\n+|$))*)/g, data, toRemove, secNum, header);
							 break;
					}
                })
            }
			
			var explanation;
			switch(sectionTitle) {
				case "בקשות מחיקה":
					 explanation = "ניקוי דפים מחוקים - רק בקשות שסומנו באמצעות תבנית בקשת מחיקה";
					 break;
				case "בקשות חסימה / הסרת חסימה":
					 explanation = "ניקוי בקשות חסימה - אם בוצעה חסימה של המשתמש מאוחר יותר מתאריך הבקשה, הבקשה תוסר";
					 break;
				case "בקשות הגנה / הסרת הגנה":
					 explanation = "ניקוי בקשות הגנה - אם בוצעה הגנה מאוחר יותר מתאריך הבקשה, הבקשה תוסר";
					 break;
				default:
					explanation = "ניקוי הבקשות שטופלו";
					break;
			}
			
            var direction = $('.mw-editsection').css('float') == 'left' ? 'left' : 'none';
            var S = $('<span>').css("background", "#eeeeee").attr("title","ריקון הבקשות שטופלו מהמקטע")
            $(S).append(" • ",
                $('<a>').attr("name", secNum).text('ניקוי').attr("title", explanation).click(function () {
                    done(this.name)
                })
            );
            editableSection.append(" ", S);
        }
    });
});