MediaWiki:Gadget-EditNoticesOnMobile.js
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
//<nowiki>
/*
EditNoticesOnMobile is public domain (for the embedded lz-string library licensing see below), irrevocably released as WTFPL Version 2[http://www.wtfpl.net/about/] by its author, Alexis Jazz. The community requested edit notices on the mobile site for years (see community wishlist 2021 and 2022 and T201595), but the WMF hasn't implemented them yet nor given a clear roadmap for their implementation. This workaround was created to get them anyway until a native implementation becomes available.
If an edit notice contains an element with the "nopopupnotice" class the automatic popup will be suppressed.
At @media screen and (max-width:767px) the button to (re)visit a notice will be hidden in the visual editor. (that toolbar is already crowded) UNLESS you disable automatic popups in which case I hope you like crowds
MediaWiki:Gadgets-definition example entry: EditNoticesOnMobile[ResourceLoader|default|dependencies=mediawiki.storage|targets=mobile|skins=minerva|supportsUrlLoad=true]|EditNoticesOnMobile.js
----
lz-string by Pieroxy[https://pieroxy.net/blog/pages/lz-string/index.html], originally licensed WTFPL, Version 2. Functions that were unneeded for EditNoticesOnMobile were stripped.
The license currently offered by Pieroxy is MIT:
----
MIT License
Copyright (c) 2013 pieroxy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
----
The MIT license is included here to be safe, the lz-string 1.4.4 archive that lz-string was copied from for EditNoticesOnMobile contains a copy of the WTFPL Version 2 license.
----
Known issues/concerns:
-Some people voiced concerns over showing the edit notice over the anoneditwarning, before the user has confirmed they are okay with anon editing. I think it's good actually: before they bother to log in or sign up (captcha!), tell the user that the earth is REALLY not flat and they shouldn't bother us with conspiracy theories and old wives' tales. But if this would end up being a sticking point, ctrl+f for "uncomment this to show the popup after the anoneditwarning" and uncomment that stuff.
-General concern that users will be annoyed by too many popups. (please note that the Android app already has edit notices as popups) The same notice for the same page doesn't repeat, pages without a notice have no popup, the gadget can be turned off in preferences. The community should consider adding an element with the "nopopupnotice" class to notices that are informative in nature and not warnings. Also apply the "nomobile" class where appropriate.
*/
/*globals $:false,OO:false,ve:false,mw:false*/
if ( typeof Object.values == 'undefined' ) { //ES5 :-/
Object.values = function(obj1,int,arr) {
arr = [];
for (int=0;int<Object.keys(obj1).length;int++) {
arr.push(obj1[Object.keys(obj1)[int]]);
}
return arr;
};
}
//only load EditNoticesOnMobile on Minerva skin on the mobile site and if it's not already loaded
if ( mw.config.get('skin') == 'minerva' && window.location.host.match(/(^|\.)m\./) && ( ! window.enom || ! window.enom.msgs ) ) {
window.enom = {};
var enom = window.enom;
enom.msgs = {
noticetitle:'View edit notice',
ok:'OK',
enable:'Enable automatic popups',
disable:'Disable automatic popups',
disablenote:'If you disable automatic popups you may miss out on important information about edit restrictions. <b>Those restrictions will still apply to you.</b> Are you sure you want to disable automatic popups?',
disablenote2:'The community doesn\'t recommend this. Are you absolutely sure? (final warning)'
};
//start lz-string by Pieroxy
enom.LZString=function(){/*jshint bitwise:false,asi:true,boss:true,expr:true*/function o(o,r){if(!t[o]){t[o]={};for(var n=0;n<o.length;n++)t[o][o.charAt(n)]=n}return t[o][r]}var r=String.fromCharCode,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$",t={},i={compressToUTF16:function(o){return null==o?"":i._compress(o,15,function(o){return r(o+32)})+" "},decompressFromUTF16:function(o){return null==o?"":""==o?null:i._decompress(o.length,16384,function(r){return o.charCodeAt(r)-32})},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(o,r,n){if(null==o)return"";var e,t,i,s={},p={},u="",c="",a="",l=2,f=3,h=2,d=[],m=0,v=0;for(i=0;i<o.length;i+=1)if(u=o.charAt(i),Object.prototype.hasOwnProperty.call(s,u)||(s[u]=f++,p[u]=!0),c=a+u,Object.prototype.hasOwnProperty.call(s,c))a=c;else{if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++),s[c]=f++,a=String(u)}if(""!==a){if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;for(;;){if(m<<=1,v==r-1){d.push(n(m));break}v++}return d.join("")},decompress:function(o){return null==o?"":""==o?null:i._decompress(o.length,32768,function(r){return o.charCodeAt(r)})},_decompress:function(o,n,e){var t,i,s,p,u,c,a,l,f=[],h=4,d=4,m=3,v="",w=[],A={val:e(0),position:n,index:1};for(i=0;3>i;i+=1)f[i]=i;for(p=0,c=Math.pow(2,2),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(t=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 2:return""}for(f[3]=l,s=l,w.push(l);;){if(A.index>o)return"";for(p=0,c=Math.pow(2,m),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(l=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 2:return w.join("")}if(0==h&&(h=Math.pow(2,m),m++),f[l])v=f[l];else{if(l!==d)return null;v=s+s.charAt(0)}w.push(v),f[d++]=s+v.charAt(0),h--,s=v,0==h&&(h=Math.pow(2,m),m++)}}};return i}();
//end lz-string by Pieroxy
//
//CRC32 checksum generator. Based on https://simplycalc.com/crc32-source.php ("This source code is in the public domain. You may use, share, modify it freely, without any conditions or restrictions."). Compacted a bit.
//enom.CRC32('test'); //should return d87f7e0c (3632233996)
// Why are you reading this?
// >>> is unsigned right shift/zero-fill right shift. n >>> 1 Could also be written as o=n;if(n<0){o=n+4294967296};h=Number(parseInt('0'+Number(o).toString(2).slice(0,-1), 2));
// & is Bitwise AND. If both bits are 1 it returns 1, otherwise 0. (27 & 30) compares 11011 to 11110 and gives 11010 as the third and fifth bit aren't both 1. As (n & 1) always compares to one that really just says what the last bit is. Can be rewritten as Number(Number(n).toString(2).slice(-1)) in that case.
// ^ is XOR. (27 ^ 30) compares 11011 to 11110 and gives 00101 as only the third and fifth bits differ. 101 is binary for 5 so that's what it'd return
// If you learned nothing go to https://www.w3schools.com/js/js_bitwise.asp
enom.genCRC32t = function(t,i,j,n) {/*jshint bitwise:false*/
for (i = 0; i < 256; i++) { //table will have 256 entries
n = i;
for (j = 8; j > 0; j--) {
if ((n & 1) == 1) {
n = (n >>> 1) ^ 0xEDB88320; //0xEDB88320 is the reversed polynomial for CRC32, see en.wikipedia.org/wiki/Cyclic_redundancy_check
} else {
n = n >>> 1;
}
}
t[i] = n;
}
return t;
};
enom.CRC32 = function(s,i,c) {/*jshint bitwise:false*/
//console.log('enom: create CRC32 checksum');
if ( ! enom.CRC32t ) { //CRC32 table hasn't been generated yet
enom.CRC32t = enom.genCRC32t([]); //passes empty array as first argument
}
c = 0xFFFFFFFF;
for (i = 0; i < s.length; i++){ //iterate through input string
c = (c >>> 8) ^ enom.CRC32t[(s.charCodeAt(i)) ^ (c & 255)]; //add byte. Unsigned right shift, XOR to table entry for charCode of the Nth character in the string to XOR to bitwise AND of c and 255. s.charCodeAt(i) is the same as s.substr(i).charCodeAt(0)
}
return ((c > -1) ? (0xFFFFFFFF - c) : c -c-c-1).toString(16);
};
//console.log('enom: EditNoticesOnMobile loaded');
enom.time = new Date().getTime();
enom.evilClasses = ['fmbox','tmbox','tmbox-content','messagebox','fmbox-editnotice'];
enom.setItemLS = function(key,val) {
return mw.storage.set(key,val);
};
enom.testValidJSON = function (string) {
if(string==null){return false;}
try{enom.parsedJSON = JSON.parse(enom.LZString.decompressFromUTF16(string.slice(11)));}catch(e){return false;}
return enom.parsedJSON;
};
enom.getDisabledSetting = function(){
if ( mw.storage.get('ENOMDisablePopup') ) {
enom.neverPopup = true;
} else {
delete enom.neverPopup;
}
};
enom.getDisabledSetting();
enom.storeNotice = function(notice){
enom.cachedNotices = enom.testValidJSON(mw.storage.get('ENOM'));
if ( ! enom.cachedNotices ) {
enom.setItemLS('ENOM','lzsdeflU16,'+enom.LZString.compressToUTF16('{}'));
enom.cachedNotices = enom.testValidJSON(mw.storage.get('ENOM'));
}
if ( enom.cachedNotices ) {
enom.cachedNotices[enom.pageTitle] = {CRC32:enom.testIfEmptyInnerTextCRC32,date:enom.time,text:notice};
//console.log('enom: generated checksum '+enom.cachedNotices[enom.pageTitle].CRC32+' for notice on '+enom.pageTitle);
enom.cachedNoticesNew = JSON.stringify(enom.cachedNotices);
if ( enom.cachedNoticesNew.length > 1000000 ) { //it's quite unlikely a user would accumulate >1MB of edit notices, but if it somehow happens we purge all and start with a clean slate
enom.cachedNoticesNew = '{}';
}
enom.setItemLS('ENOM','lzsdeflU16,'+enom.LZString.compressToUTF16(enom.cachedNoticesNew));
}
};
enom.getNotice = function(trigger) {
enom.cachedNotices = enom.testValidJSON(mw.storage.get('ENOM'));
if ( trigger && trigger.target && trigger.target.href ) {
//console.log('enom: extract page title from URL');
enom.pageTitle = mw.util.getParamValue("title", trigger.target.href);
} else {
//console.log('enom: use title of current page');
enom.pageTitle = mw.config.get('wgPageName');
}
enom.pageTitle = enom.pageTitle.replace(/_/g,' ');
enom.newNotice = false;
if ( enom.cachedNotices ) {
enom.update = false;
enom.oldEditnoticeCRC32 = 0;
if ( enom.cachedNotices[enom.pageTitle] ) {
enom.oldEditnotice = enom.cachedNotices[enom.pageTitle].text;
enom.oldEditnoticeCRC32 = enom.cachedNotices[enom.pageTitle].CRC32;
}
for (enom.cachedInt=0;enom.cachedInt<Object.keys(enom.cachedNotices).length;enom.cachedInt++){
enom.checkEntry = enom.cachedNotices[Object.keys(enom.cachedNotices)[enom.cachedInt]];
if ( typeof window.enomCacheExpiry == 'number' ) { //give the user some control over the expiry period by specifying enomCacheExpiry in their common.js.
enom.cacheExpiry = window.enomCacheExpiry;
} else {
enom.cacheExpiry = 1209600000; //keep checksums for 2 weeks (1209600000 ms)
}
enom.cacheExpiryText = 7200000; //keep text for 2 hours (7200000 ms)
if ( enom.checkEntry.date < enom.time -enom.cacheExpiry || ( enom.checkEntry.date < enom.time -enom.cacheExpiryText && Object.keys(enom.cachedNotices)[enom.cachedInt] == enom.pageTitle) ) {//entry >2 weels old or the current page and >2 hours (7200000 ms) old
//console.log('enom: removed '+Object.keys(enom.cachedNotices)[enom.cachedInt]+' from locally cached notices');
delete enom.cachedNotices[Object.keys(enom.cachedNotices)[enom.cachedInt]];
enom.update = true;
} else if ( enom.checkEntry.date < enom.time -enom.cacheExpiryText && enom.cachedNotices[Object.keys(enom.cachedNotices)[enom.cachedInt]].text ) {
//console.log('enom: remove noticetext for '+Object.keys(enom.cachedNotices)[enom.cachedInt]+' from locally cached notices (older than 2 hours)');
delete enom.cachedNotices[Object.keys(enom.cachedNotices)[enom.cachedInt]].text;
enom.update = true;
}
if ( enom.update ) {
enom.setItemLS('ENOM','lzsdeflU16,'+enom.LZString.compressToUTF16(JSON.stringify(enom.cachedNotices)));
}
}
if ( enom.cachedNotices[enom.pageTitle] ){ //notice was cached less than 2 hours ago
//console.log('enom: found cached notice');
enom.popupNotice(enom.cachedNotices[enom.pageTitle].text,false);
return;
}
}
/* provides edit notices in a structured form but also a lot of unneeded big stuff
enom.editNoticeParams = {
format:'json',
action:'visualeditor',
paction:'metadata',
page:enom.pageTitle,
formatversion:'2',
};
*/
enom.namespaces = mw.util.escapeRegExp(Object.values(mw.config.get('wgFormattedNamespaces')).toString()).replace(/^,/,'').replace(/,/g,'|'); // "Talk|User|User talk|" etc
enom.pageTitleNoNS = enom.pageTitle.replace(new RegExp('^('+enom.namespaces+'):'),'').replace(/\//g,'-');
enom.editNoticeParams = {
format:'json',
action:'parse',
disablelimitreport:true,
title:enom.pageTitle,
contentmodel:'wikitext',
pst:'1',
prop:'text',
formatversion:'2',
text:'<div id="EditNoticeOnMobile">{{#ifexist:MediaWiki:Editnotice-{{NAMESPACENUMBER}}-'+enom.pageTitleNoNS+'|{{MediaWiki:Editnotice-{{NAMESPACENUMBER}}-'+enom.pageTitleNoNS+'}}|{{#ifexist:MediaWiki:Editnotice-{{NAMESPACENUMBER}}|{{MediaWiki:Editnotice-{{NAMESPACENUMBER}}}}}}}}</div><div id="enom_end"></div>',
};
mw.loader.using(['mediawiki.api'], function(){
//console.log('enom: download notice');
enom.newNotice = true;
var api = new mw.Api();
enom.writeLang = function(data) {
enom.setItemLS('ENOMUILang','lzsdeflU16,'+enom.LZString.compressToUTF16((data || '{"created":'+new Date().getTime()+'}')));
};
enom.wUL = mw.config.get('wgUserLanguage');
if ( enom.wUL != 'en' ) {
enom.UILang = ( enom.testValidJSON(mw.storage.get('ENOMUILang')) || {created:new Date().getTime()} );
if ( enom.UILang.created < new Date().getTime() - 604800000 ) { //localStorage object more than a week old
enom.writeLang();
}
if ( enom.UILang[enom.wUL] ) {
enom.msgs = enom.UILang[enom.wUL];
} else {
api = new mw.Api();
api.get({action:'query',prop:'revisions',titles:'MediaWiki:Gadget-EditNoticesOnMobile.js/i18n.json',rvlimit:1,rvprop:'content',rvslots:'*'}).then( function(data) {
enom.langObj = {};
try{enom.langObj = JSON.parse(data.query.pages[Object.keys(data.query.pages)[0]].revisions[0].slots.main['*']);}catch(e){}
enom.UILang[enom.wUL] = ( enom.langObj[enom.wUL] || enom.msgs );
enom.writeLang(JSON.stringify(enom.UILang));
enom.msgs = enom.UILang[enom.wUL];
},function(){ //API fail
enom.UILang[enom.wUL] = enom.msgs;
enom.writeLang(JSON.stringify(enom.UILang));
});
}
}
api.post( enom.editNoticeParams ).done( function ( data ) {
/* structured editnotices from VE API. see commented out params above
enom.parsednotices = '<div id="EditNoticeOnMobile">';
for(enom.noticeint=0;enom.noticeint<Object.keys(data.visualeditor.notices).length;enom.noticeint++){
if ( Object.keys(data.visualeditor.notices)[enom.noticeint].match(/editnotice/) ) { //there's also semiprotectedwarning, presumably some other protection warnings. is there an overview of all possible messages?
enom.parsednotices = enom.parsednotices + data.visualeditor.notices[Object.keys(data.visualeditor.notices)[enom.noticeint]];
}
}
enom.parsednotices = enom.parsednotices+'</div>';
*/
enom.parsednotices = data.parse.text.replace(/\n/g,'').replace(/.*(<div id="EditNoticeOnMobile">.*<\/div>)<div id="enom_end"><\/div>.*/,'$1');
enom.testIfEmpty = document.createElement('div');
enom.testIfEmpty.classList.add('enomTempDiv'); //need to attach this to the DOM to work with it.. maybe it's possible another way but this'll work
enom.testIfEmpty.classList.add('enomTempDivNew');
enom.testIfEmpty.innerHTML = enom.parsednotices;
$('body:eq(0)').append(enom.testIfEmpty);
enom.suppressPopup = typeof $('.enomTempDivNew .nopopupnotice')[0];
/*
We are going to test if the notice contains any text content after removing elements that don't contain vital information about editing some particular page.
* Nomobile elements wouldn't be displayed anyway. Edit notice creators should use "nomobile" as they see fit. Please consider that edit notices on mobile are presented as a popup, not a passive box above the text area.
* The editnotice-link just links to the page containing the notice. It should be displayed on mobile (so nomobile shouldn't be added to it) but we ignore it when checking if the notice has any text content.
* ..
*/
$('.enomTempDiv *').removeClass(enom.evilClasses);
enom.parsednotices = $('.enomTempDiv')[0].innerHTML; // save/check notice without evil classes
$('.enomTempDiv .nomobile,.enomTempDiv .editnotice-link,.enomTempDiv .editnotice-group').remove();
enom.testIfEmptyInnerText = $('.enomTempDivNew')[0].innerText.trim();
enom.testIfEmptyInnerTextCRC32 = enom.CRC32(enom.testIfEmptyInnerText);
//console.log('enom: checksum for this notice: '+enom.testIfEmptyInnerTextCRC32);
if ( enom.testIfEmptyInnerText == '' ) {
//console.log('enom: notice is (practically) empty, blanking');
enom.parsednotices = '';
}
$('.enomTempDiv').remove();
if ( enom.testIfEmptyInnerTextCRC32 == enom.oldEditnoticeCRC32 || enom.suppressPopup == 'object' || enom.neverPopup ) {
//console.log('enom: notice is identical to what we had cached (based on CRC32 checksum) or contains "nopopupnotice" class or you disabled automatic popups, adding button but no popup.');
enom.popupNotice(enom.parsednotices,false);
} else {
//console.log('enom: notice is different from what (if anything) was cached, adding button and creating popup');
enom.popupNotice(enom.parsednotices,true);
}
//if ( mw.config.get('wgUserName') != null ) { // 4/5 uncomment this to show the popup after the anoneditwarning
enom.storeNotice(enom.parsednotices);
//} // 5/5 uncomment this to show the popup after the anoneditwarning
});
});
};
enom.cleanupStyling = function(){
//console.log('enom: cleaning up notice');
$('#EditNoticeOnMobile *').removeClass(enom.evilClasses);
for (enom.noticeElementsInt=0;enom.noticeElementsInt<$('#EditNoticeOnMobile *').length;enom.noticeElementsInt++){
$('#EditNoticeOnMobile *')[enom.noticeElementsInt].style.background = ''; //remove background colors that many edit notices have. Not appropriate in a popup
}
if ( $('#EditNoticeOnMobile .mw-collapsible')[0] ) {
mw.loader.using('jquery.makeCollapsible').then( function () { //WP:HD includes a collapsible "Help desk templates" block
mw.util.addCSS('#EditNoticeOnMobile .mw-collapsible-toggle a{color:#3366cc}#EditNoticeOnMobile .mw-collapsible-toggle{font-weight:normal;}');
$($('#EditNoticeOnMobile .mw-collapsible')).makeCollapsible(); //T111565 FTFY
});
}
};
enom.showPopup = function(noticetext,settingbutton){
mw.loader.using(['oojs-ui-core','oojs-ui-windows']).then(function(){
enom.getDisabledSetting(); //in case the setting was changed in another tab since the script was loaded
enom.dialogActions = [{action: 'reject',label: enom.msgs.ok,flags: 'primary'}];
if ( settingbutton ) {
if ( enom.neverPopup ) {
enom.buttonLabel = enom.msgs.enable;
enom.buttonFlag = 'progressive';
} else {
enom.buttonLabel = enom.msgs.disable;
enom.buttonFlag = 'destructive';
}
enom.dialogActions.push({action: 'accept',label:enom.buttonLabel,flags:enom.buttonFlag});
}
if ( window.innerWidth > 300 && ! settingbutton ) { //on REALLY narrow (<300px) screens, let OOui handle it however it pleases
mw.util.addCSS('#EditNoticeOnMobile .mbox-image,.enomTempDiv{display:none} .oo-ui-windowManager-modal>.oo-ui-dialog.oo-ui-window-active>.oo-ui-window-frame{width:700px !important;max-width:90%;max-height:90%;border:1px solid #a2a9b1;box-shadow:0 2px 2px 0 rgba(0,0,0,0.25);border-radius:2px;}'); //T313140
}
if ( navigator.userAgent.match(/Firefox/) && $('html.client-dark-mode')[0]) {
enom.pageXOffset = window.pageXOffset;
enom.pageYOffset = window.pageYOffset;
window.scrollTo(0,0);
} else {
delete enom.pageXOffset;
delete enom.pageYOffset;
}
/* Hack-free method to have a windowed popup. But actual user experience might be worse. For example a 375px (portrait mode) iPhone SE would get 300px with this while the hack results in 90% (338px).
if ( window.innerWidth <= 500 ) { //T313140
enom.popupSize = 'small'; //300px
} else if ( window.innerWidth <= 700 ) {
enom.popupSize = 'medium'; //500px
} else {
enom.popupSize = 'large'; //700px
}
*/
noticetext = noticetext+'<script>enom.cleanupStyling();</script>'; // makes collapsible elements in notices collapsible
OO.ui.confirm(new OO.ui.HtmlSnippet(noticetext),{/*size:enom.popupSize,*/actions:enom.dialogActions}).done( function ( disable ) {
//console.log('enom: dismissed popup');
$('#EditNoticeOnMobile').remove(); //when the popup is dismissed it is just hidden it seems, any old instances must be gone so waitForElement() can detect when to launch cleanupStyling()
if ( enom.pageXOffset || enom.pageYOffset ) {
window.scrollTo(enom.pageXOffset,enom.pageYOffset);
}
if ( window.innerWidth > 300 && ! settingbutton ) {
mw.util.addCSS('.oo-ui-windowManager-modal>.oo-ui-dialog.oo-ui-window-active>.oo-ui-window-frame{width:unset !important;max-width:100%;max-height:100%;}');
}
if ( disable && window.localStorage && ! enom.neverPopup ) {
//console.log('enom: you decided to disable automatic popups :-(');
OO.ui.confirm(new OO.ui.HtmlSnippet(enom.msgs.disablenote),{size:'large'}).done( function ( disablenow ) {
if ( disablenow ) {
if ( mw.config.get('wgDBname') != 'enwiki' ) {
enom.setItemLS('ENOMDisablePopup','1');
enom.getDisabledSetting();
return;
}
//console.log('enom: you are really going through with this? :-( :-(');
OO.ui.confirm(enom.msgs.disablenote2,{size:'large'}).done( function ( disablenow ) {
if ( disablenow ) {
//console.log('enom: you really decided to disable automatic popups! :-( :-(');
enom.setItemLS('ENOMDisablePopup','1');
enom.getDisabledSetting();
}
});
}
} );
} else if ( disable && enom.neverPopup ) {
//console.log('enom: user decided to re-enable automatic popups :-)');
mw.storage.remove('ENOMDisablePopup');
delete enom.neverPopup;
}
} );
//enom.waitForElement('#EditNoticeOnMobile',enom.cleanupStyling); //popup doesn't immediately exist..
});
};
enom.popupNotice = function(noticetext,popup){
if ( noticetext == '' || noticetext.match(/<div[^>]EditNoticeOnMobile[^>]*><\/div>/) ) { //empty notice, don't show anything
//console.log('enom: notice is empty (no notice for this page)');
return;
}
if ( popup && ! enom.neverPopup ) { //shove popup into user's face only if freshly downloaded
/* // 1/5 uncomment this to show the popup after the anoneditwarning. NOTE: does the anoneditwarning appear for every single edit? Or does it stop showing if you publish an edit as anon? This code assumes the anoneditwarning ALWAYS shows for anons for every single edit, so if it doesn't this would cause problems. (probably failure to automatically popup the notice)
if ( mw.config.get('wgUserName') == null ) {
//console.log('enom: anon, put event listener on "Edit without logging in" button instead of showing it now');
enom.addToAnon = function(){
//console.log('enom: adding event listener to anonymous button');
$('.anonwarning a.anonymous').on('click',function(){
enom.showPopup(noticetext);
enom.storeNotice(enom.parsednotices);
//enom.waitForElement(enom.sourceClass,enom.applyToSourceToolbar);
//enom.waitingForVE(enom.VEClass,'visual',100,1000);
});
};
//enom.waitForElement('.anonwarning a.anonymous',enom.addToAnon);
} else {
*/ // 2/5 uncomment this to show the popup after the anoneditwarning
enom.showPopup(noticetext);
//} // 3/5 uncomment this to show the popup after the anoneditwarning
}
enom.addLink = function() {
if ( this.data && this.data.action == 'saveIntent' ) {
$('#enomNoticeLink').remove();
enom.noticeLink = document.createElement('a');
enom.noticeLink.id = 'enomNoticeLink';
enom.noticeLink.href = '';
enom.noticeLink.innerText = enom.msgs.noticetitle;
enom.noticeLink.onclick = function(){event.preventDefault();enom.showPopup(noticetext,1);};
if ( document.dir == 'ltr' ) {
enom.noticeLink.style.float = 'right';
} else {
enom.noticeLink.style.float = 'left';
}
$('.ve-ui-mwSaveDialog-summaryLabel').append(enom.noticeLink);
if ( ! $('#enomNoticeLink')[0] ) {
$('div.mw-overlays-container .save-panel.panel').prepend(enom.noticeLink);
}
}
};
if ( ! enom.linkEvent ) {
mw.trackSubscribe( 'event.EditAttemptStep', enom.addLink );
enom.linkEvent = 1;
}
};
if ( $('#ca-edit')[0] ) {
$('#ca-edit,.mw-editsection .edit-page').on('click', function(event) { enom.getNotice(event); } );
}
if ( window.location.href.match(/\#\/editor\//) ) {
//console.log('enom: found #editor in location.href, loading');
enom.getNotice();
}
} else {
//console.log('enom: don\'t load EditNoticesOnMobile on anything other than the mobile site with Minerva and don\'t try to load it twice.');
}
//</nowiki>