שיחת מדיה ויקי:Gadget-IsBlock.js

תוכן הדף אינו נתמך בשפות אחרות.
מתוך ויקיפדיה, האנציקלופדיה החופשית

קיפודנחש, הסקריפט אמור לבדוק קישורים של [[מיוחד:חסימה/{{{1}}}]] ולהפוך אותם ל[[מיוחד:חסימה/{{{1}}}]] {{{1}}} חסומ/ה. מיועד למפעילים בוק:במ. הבעיה היא, שכשזה מחליף, זה מחליף את כל הקישורים, ולא רק של המשתמש הנוכחי למרות שבביטוי הרגולרי מופיע בבירור שם המשתמש {{{1}}}. יש לך מושג למה זה לא עובד? אורשיחה@17:47, 31 בינואר 2017 (IST)[תגובה]

הצצתי בסקריפט. לא התעמקתי לחקור מה הבעיה בדיוק, אבל יש בסקריפט הזה כמה פגמים יסודיים מאד. אם הבנתי נכון, אתה חושב להוסיף את הסקריפט ל-common.js. אם כך, חובה לתקן את הפגמים הללו, ואם תעשה זאת, לא תהיה לך הבעיה הנוכחית.
אנסה למנות את הפגמים, ואת הדרך לתקן כל אחד.
  1. אתה אוסף את שמות המשתמשים שיש לבדוק על ידי הרצת ביטוי רגולרי על :#bodyContent.innerHTML. זה אולי לא "פשע", אבל זה כמעט הכי קרוב שאפשר להגיע בכתיבת סקריפט לדפדפן. אין שום סיבה להתנהג כך: כל הקישורים הללו באים מתבנית {{לחסום}}. ביקשת וקיבלת הרשאת עורך ממשק, שצמודה אליה הרשאת "עורך תבניות". גש לתבנית הזו, ולמד אותה "לייצא" את שם המשתמש בעזרת אלמנט ממחלקה ידועה כלשהי שמשמשת רק לזה (משהו כמו blockRequestUserName או כדומה - שם ארוך מספיק כך שבטוח שאינו בשימוש), ושים (בתבנית) את שם המשתמש בשדה כלשהו. בריצה אתה פשוט מוצא את כל האלמנטים הללו בדף, בקש את (לפי הדוגמה שלי - כמובן השתמש באותו שם מחלקה שמופיע בתבנית).
  2. אתה קורא ל-API עבור כל מופע של "מיוחד/חסימה" שמופיע בדף, אפילו כשיש כפילויות (כלומר אם יש בדף חמש בקשות עבור אותו משתמש, אתה קורא ל-API חמש פעמים עבורו, וכמובן גם עבור כל האחרים). זה יוצר תעבורה מיותרת ועבודה מיותרת לשרתים. בהמשך לסעיף הקודם, אחרי שאספת את שמות כל המשתמשים עבורם אתה רוצה לבדוק, שלח בקשה אחת ל-API עם כל המשתמשים שאתה רוצה לבדוק (נכון, אם יש יותר מ-50 תצטרך לבדוק בקבוצות של 50, אבל לא נראה לי שזה ממשי - אופתע אם אי פעם היו ב-וק:במ בקשות חסימה ל-50 רשומים או ל-50 אלמונים שונים באותו זמן. כשהקריאה ל-API חוזרת, אתה משתמש באוסף האלמנטים שאספת בשלב הראשון, ששמורים במילון לפי שם המשתמש, ויש לך גישה ישירה לאלמנט. בנקודה זו אתה אומר מוסיף לאלמנט את הסימון "כבר חסום", ושלום על ישראל.
  3. הסקריפט שלך מגדיר את המשתנים a, b, m, ו-anon בסקופ הגלובלי. זה דבר שלא עושים. עדיף לא להגדיר שום דבר בסקופ הגלובלי (ואין לתוכנית שלך שום סיבה לעשות זאת), ובמקרים שצריך, נותנים למשתנים הללו שמות ייחודיים, באופן שלא תהיה התנגשות עם משתנים גלובליים שמישהו אחר הגדיר. ברור ששמות כמו a או anon לא מתאימים.
אם חלק ממה שכתבתי לא לגמרי מובן, שאל ואפרט. קיפודנחש 00:48, 2 בפברואר 2017 (IST)[תגובה]
היי, תודה רבה. 1, לא הבנתי איך לעשות זאת, באמצעות div? תוכל לעזור לי בזה? 2, יטופל. 3, כנ"ל. אני לא אפעיל את זה כברירת מחדל אצל כולם, פשוט אפרט טוב מה זה הסקריפט הזה ואיך בדיוק מוסיפים אותו, ואתייג את כל המפעילים. תודה, אורשיחה20:28, 2 בפברואר 2017 (IST)[תגובה]
התבנית הזו הוא inline, אז יותר סביר span מאשל div. אתה מדביק בתבנית span ריק, עם class שרק אתה משתמש בו (כמו בדוגמה שנתתי למעלה), ועם שדה data שתוכנו שם המשתמש (כלומר הפרמטר שהועבר לתבנית). נניח
<span class="blockRequestUserName " data_username="{{{1}}}">
בסקריפט עצמו, אתה יכול ללכוד את כולם בקלות כך: השתדלתי לכתוב הערות כדי להסביר מה כל חלק בסקריפט עושה, ולמה. בדרך כלל יש הרבה פחות הערות בסקריפטים שלי, כי הקוד אמור להיות ברור ומובן. במקרה הזה הוספתי הערות בעיקר עבורך.
var list = {};
$('.blockRequestUserName').each( function() {
   var span = $(this); // this is one such span.
   var username = span.data('username');
   if (list[username]) {
      list[username].push(span);
    } else {
        list[username] = [ span ];
    }
});

var users_to_query = Object.keys(list);
כמובן שאינך יכול להשתמש קוד הזה כמו שהוא: למשל, הוא לא מבחין בין רשומים לאלמונים. זו רק סקיצה. מה שחשוב זה שבסוף הפעולה יש לך רשימה (users_to_query) עם כל המשתמשים שצריך לשאול עליהם, ואתה מבצע קריאה אחת ל-API כדי לקבל את כולם (אתה משרשר את כל השמות עם | ). כשה-API חוזר, אתה יכול למצוא כל שם משתמש חסום במשתנה list, ולקבל מיד מערך של כל ה-span-ים שצריך לעדכן (בדרך כלל אחד, אבל יהיו מקרים שיש כמה בקשות חסימה לאותו המשתמש בדף). אתה רץ על כל ה-span-ים האלו, ולמשל מוסיף להם טקסט "חסום", ואם אתה רוצה לעשות משהו יפה, אתה מוסיף להם גם title עם מידע מי חסם ולכמה זמן (מידע שה-API מחזיר לך). אתה יכול לשחק עם זה על ידי כך שתבנה דף פרטי שלך עם כמה תבניות {{לחסום}}, כך שבכמה מהן מופיעים משתמשים ואלמונים חסומים (ראה יומן החסימות) ובכמה אחרים משתמשים ואלמונים לא חסומים, עד שזה יעבוד יפה. בגדול, צריך לבצע לכל היותר שתי קריאות ל-API (אם יש גם רשומים וגם אלמונים שצריך לבדוק). מקווה שההסבר ברור, ואם לא, אנסה לסרוג סקריפט להדגמה. קיפודנחש 22:46, 2 בפברואר 2017 (IST)[תגובה]
תודה ענקית! עכשיו הסקריפט עובד טוב + הוספתי לו את מי חסם + אני חושב שסידרתי את עניין המשתנים הגלובליים. מה שעדיין לא נעשה, ולא יודע עד כמה קריטי, זה שיהיו רק 2 קריאות לAPI. המשתנה users_to_query לא עובד ומחזיר לי undefined. מצאתי דרך אחרת לקבל את שמות המשתמשים. תודה רבה, אורשיחה07:40, 3 בפברואר 2017 (IST)[תגובה]
"עכשיו הסקריפט עובד טוב": לא. יש כמה פגמים:
  1. אתה קורא ל-using גם אם לא צריך. התיקון פשוט: בצע את הבדיקה של שם הדף _לפני_ הקריאה של using במקום אחרי. במילים אחרות, החלך שת השורה הראשונה והשנייה בסקריפ שלך.
  2. שמות הפונקציות גרועים ומטעים. פונקציה ששמה isAnon, צריכה להחזיר true או false לפי הפרמטר שמועבר לה. במקום זה אצלך זו פונקציה שמקבלת כתובת IP ומבצעת קריאה ל-API.
  3. טעיתי והטעיתי כשכתבתי שאפשר לבדוק את כל האלמונים ביחד: מסיבה כלשהי, כשמשתמשים בפרמטר bkipף אפשר להעביר רק כתובת אחת. זה כנראה משום שבמקרה כזה הפרמטר יכול להתייחס לטווח כתובות, והטיפול בו שונה. לעומת זאת, כשמשתמשים ב-bkusers, בהחלט אפשר לשאול על כולם בשאילתה אחת.
  4. אתה עושה שם משהו מוזר מאד, כשאתה דוחף את התשובה שחזרה מה-API למשתנה גלובלי בשם logs (במילים שלך logs = ans. לא הצהרת על המשתנה logs בשום מקום, ולכן הוא משתנה גלובלי. זה לחלוטין לא נחוץ - כל מה שאתה עושה אתו אתה יכול לעשות ישירות עם המשתנה המקומי (ans).
כשמשהו לא עובד, מדבגים ומוצאים למה, לא עוקפים את זה על ידי דברים משונים כמו for (x in list.undefined). במקרה הזה זה היה כי הטעיתי אותך: כשמגדירים שדה data, משתמשים במקף ("סימן מינוס"), לא קו תחתי. בעצם מה שקרה זה שכל ה-span-ים החזירו undefined מהקריאה span.data('username'). תיקנתי את התבנית (כלומר data-username במקום data_username), ועכשיו זה עובד כמו שהתכוונתי.
להדגמה, הנה הקוד (עובד) כמו שהתכוונתי. לא כל כך משנה איזה סקריפט תשים בוק:ס, הכוונה היא שתקרא את הקוד הזה ותבין אותו. אם יש בו משהו שאינו ברור לך, בקש הסברים. הקוד הזה משתמש ב-jQuery ולכן לא מכיל דברים כמו list.undefined[x][0].children["0"].innerText. שים לב שהסקריפט הזה עובד רק בדף ששמו whatever - כאמור, זה מיועד להסבר והדגמה, לא לשימוש כמו שזה (למרות שאם תשנה את שם הדף, אפשר להשתמש). את הצורה בה חסימות מוצגות אפשר לשפר על ידי עריכת הפונקציה addBlockedMarker.
if ( mw.config.get( 'wgPageName') === 'whatever' )
mw.loader.using(['mediawiki.util', 'mediawiki.api']).done( () => {
	
	var list = {};

	// collect all {{לחסום}} requests. note that it's an object, keyed by user name.
	// so, if there are multiple requests for same users, we only ask for one, and remember for each
	// all the spans we want to update for this user.
	$( '.blockRequestUserName ').each( function() {
		var span = $( this ),
			username = span.data( 'username' );
		(list[username] = (list[username] || [])).push(span);
	});

	// filter all anons to one list, and registered to another.
	var anons = Object.keys(list).filter( mw.util.isIPAddress );
	var registered = Object.keys(list).filter( u => ! mw.util.isIPAddress(u) );
	
	// construct an api object to be used below
	var api = new mw.Api();
	
	// start sending api calls. for anons ("bkip" parameter), we can only ask one at a time.
	anons.forEach( anon => {
		api.get( {
			list: 'blocks',
			bkip: anon
		})
		.done( reportBlocks );
	});
	
	
	// for registered, we can ask for up to 50 at a time.
	// todo: check list length, use .slice() or .splice() to chuck them in batches of 50.
	if (registered.length) {
		api.get( {
			list: 'blocks',
			bkusers: registered.join('|')
		})
		.done( reportBlocks );
	}
	
	// when query returns, see if there are any blocks, and if there are, add the block marker.
	// note that list[user] is an array of all the spans in the page requesting to block this user.
	// typically this array will be of length 1, but it can be more.
	function reportBlocks( data ) {
		if (data && data.query && data.query.blocks )
			data.query.blocks.forEach( block => {
				var user = decodeURIComponent( block.user ); // the api returns the user name encoded.
				addBlockedMarker( list[user], block.by, block.expiry );
			});
	}
	
	function addBlockedMarker( spans, by, expiry ) {
		spans.forEach( span => 
			span
			.text(' חסום!')
			.attr('title', 'על ידי: ' + by + ' פקיעה: ' + expiry )
		);
	}
});
קיפודנחש 20:48, 3 בפברואר 2017 (IST)[תגובה]
וואו, תודה ענקית קיפודנחש! דבר אחד לא הבנתי, מה הפירוש של ה=>? אני מניח שכעת ניתן להעביר למרחב מדיה ויקי? אורשיחה23:10, 3 בפברואר 2017 (IST)[תגובה]
הסימון הזה משמש לציין פונקציה אנונימית. גם אני לא הכרתי אותו עד לא מזמן, למרות שהוא לא חדש. שימוש בו הופך את הקוד ברור וקצר יותר. אפשר למשל לכתוב דברים כמו:
var cube = x => x * x * x;
var eight = cube(2); 
// which is the same as
var cube_with_curlies = (x) => {
    return x * x * x;
};
// which is _almost_ the same thing as:
var fcube = function(x) {
    return x * x * x;
};
// which in turn, is _exactly_ the same as
function ffcube(x) {
    return x * x * x;
}
(מומלץ: פתח קונסול של JS על ידי F12 בדפדפן, ונסה זאת! שים גם לב שבהגדרת משתנה הוספתי ; בסיום ההגדרה, ובהגדרת פונקציה לא). בין שתי הצורות הראשונות לשתי הבאות יש הבדל קטן, שקשור לאופן בו ג'אווהסקריפט ממשת object oriented, אבל ברוב המכריע של המקרים זה לא משנה לך, ובדרך כלל, אם זה כן משנה, זה שינוי לטובה (רמז: המשמעות של this בתוך ה"פונקציה" שונה). תוכל לקרוא הסבר מלא ואוטוריטטיבי כאן. זה תמיד משפר את הקריאות והבהירות, ולכן מאז למדתי את הסינטקס הזה, אני עושה בו שימוש בכל מקום בו נדרשת פונקציה אנונימית, שבג'אווהסקריפט זה "המון". לגבי העברה למרחב מדיה ויקי: אתה יכול, אם כי כדאי אולי לנסות לשפר את זה קצת לפני כן: למשל, להוסיף לרמז את הזמן בו בוצעה החסימה, או במקרה ו-expiry זה תאריך, לחשב עוד כמה זמן זה ולהציג "עוד 7 שעות" במקום הצורה הנוכחית. אפשר גם להוסיף מידע נוסף, כמו reason, וכן הלאה. אתה יכול גם לממש את ה- todo, כלומר לטפל במקרה שיש יותר מ-50 משתמשים רשומים לבדוק. מבחינה מעשית אין לזה חשיבות רבה (אין הרבה מצבים בהם מתבקשת חסימה של מעל 50 רשומים...), אבל בתור תרגיל זה דבר טוב, וכשתעשה זאת בהצלחה, זה יתן לך ביטחון שאתה באמת שולט בקוד. כמו כן שים לב שהסקיצה שרשמתי כאן רצה מיד, בלי לחכות לגמר טעינת הדף, שזה דבר שצריך לתקן.
לגבי הוספה למדיה ויקי: זה שיש לך הרשאות עורך ממשק אומר שאתה לא צריך רשות. לדעתי אין סיבה להוסיף ל-common.js, ומספיק להוסיף זאת כעוד סקריפט בוק:ס. במקרה זה אפשר גם להסיר את התנאי שמגביל את זה ל-וק:במ: באופן כזה מי שמתקין את הסקריפט יראה את המידע בכל דף בו יש שימוש ב{{לחסום}}, לא רק בוק:במ, והמחיר מזערי (סריקת הדף לחיפוש אלמנטים מה-class המתאים לוקחת אפס זמן, וכמובן, כמעט בשום דף אין כאלו, והסקריפט יוצא בלי לעשות כלום). כמובן שאם היה נחוץ להוסיף זאת ל-common.js אז כן היה נכון צריך לבדוק את הדף - לא סביר שסקריפט כזה ירוץ עבור כל משתמש בוויקיפדיה כל פעם שהוא פותח דף כלשהו (לעומת זאת, זה כן סביר כשמדובר על מספר מצומצם של אנשים שיתקינו את הסקריפט ידנית). קיפודנחש 02:43, 4 בפברואר 2017 (IST)[תגובה]
קודם כל, אגיד עוד פעם תודה. אני חושב שאני עכשיו אתייג את המפעילים, אסביר להם, ואבקש לשמוע משובים. אם הם ירצו מי חסם או מתי, אני אוסיף. אני לא חושב שיהיה מצב בו יהיו יותר מ50 פעמים בדף של בקשות חסימה של משתמשים רשומים. תודה רבה! בברכה, אורשיחה09:20, 4 בפברואר 2017 (IST)[תגובה]