User:Jdlrobson/rl.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump.
This code will be executed when previewing this page.
This code will be executed when previewing this page.
Documentation for this user script can be added at User:Jdlrobson/rl.
mw.loader.implement("ext.gadget.readinglist@o1a0b",{"main":"resources/ext.gadget.readinglist/gadget.js","files":{"resources/ext.gadget.readinglist/gadget.js":function(require,module,exports){const{showOverlay,createMembersOverlay,editListOverlay}=require('./overlays.js');const{getCollectionsWithMembership,fromBase64,saveReadingList,deleteCollection,addToList,toBase64}=require('./api.js');(function(){if(mw.user.isAnon()){return;}var READING_LIST_URL='/wiki/Special:ReadingListz/'+mw.user.getName();function addImportFromTable(){Array.from(document.querySelectorAll('.wikitable')).filter((node)=>node.querySelectorAll('a[title]').length>4).forEach((table)=>{const titles={[window.location.host]:Array.from(table.querySelectorAll('a[title]')).map((link)=>link.getAttribute('title'))};const link=document.createElement('a');link.textContent='Import into list';const row=document.createElement('tr');const col=document.createElement('td');col.setAttribute('colspan',table.querySelectorAll('thead').
length);table.appendChild(row);const base64=toBase64(`Imported from tablez on ${mw.config.get('wgTitle')}`,'',titles);link.setAttribute('href',`${READING_LIST_URL}?limport=${base64}`);col.appendChild(link);table.appendChild(col);});}function addToUserMenu(){mw.util.addPortletLink('p-personal',READING_LIST_URL,'My reading lists','pt-readinglists',null,'l','pt-watchlist');}function addBookmarkNextToWatchAction(){let link=mw.util.addPortletLink('p-views','#','Bookmark','pt-bookmark');if(!link){link=mw.util.addPortletLink('page-actions','#','Bookmark','pt-bookmark');}if(!link){return;}link.addEventListener('click',()=>{const title=mw.config.get('wgPageName');showOverlay(getCollectionsWithMembership(mw.user.getName(),title).then((collections)=>{return createMembersOverlay(title,collections);}));});}const isSpecialReadingList=mw.config.get('wgTitle').indexOf('ReadingListz/')>-1||mw.config.get('wgTitle').indexOf('ReadingLists/')>-1
function editList(){const pathSplit=window.location.pathname.split('/');const id=parseInt(pathSplit[4],10);const h1=document.querySelector('.readinglist-collection-summary h1');const desc=document.querySelector('.readinglist-collection-description');const title=h1?h1.textContent:'';const description=desc?desc.textContent:'';showOverlay(Promise.resolve(editListOverlay(id,title,description,null,()=>{window.location.pathname=`${READING_LIST_URL}/${id}?updated=${new Date()}`;})));}function createList(){showOverlay(Promise.resolve(editListOverlay(null,'','',null,()=>{window.location.pathname=`${READING_LIST_URL}/?updated=${new Date()}`;})));}function deleteList(){const pathSplit=window.location.pathname.split('/');const id=parseInt(pathSplit[4],10);const ok=confirm('Are you sure you want to delete this list?');if(ok){deleteCollection(id).then(()=>{mw.notify('List has been deleted.');window.location.pathname=READING_LIST_URL;})}}function registerTemporaryReadingListPage(){if(
isSpecialReadingList){const action=document.createElement('button');const container=document.createElement('div')
container.setAttribute('id','reading-list-container')
$('#mw-content-text').html('').append(container)
$('#firstHeading').text('Reading lists');mw.util.addPortletLink('p-associated-pages',READING_LIST_URL,'Your lists');mw.loader.using('special.readinglist.scripts');const callback=(mutationList,observer)=>{for(const mutation of mutationList){if(mutation.type==='childList'){action.removeEventListener('click',createList);const pathSplit=window.location.pathname.split('/');if(pathSplit.length===4){action.removeEventListener('click',deleteList);action.textContent='Create list';action.addEventListener('click',createList);const editBtn=document.querySelector('.readinglist-collection-summary .rl-edit-btn');if(editBtn){editBtn.parentNode.removeChild(editBtn);}}else{action.textContent='Delete list';action.removeEventListener('click',createList);action.addEventListener('click',deleteList);const summaryArea=document.querySelector('.readinglist-collection-summary');const existingEdit=summaryArea.querySelector('.rl-edit-btn');if(summaryArea&&!existingEdit){const editBtn=document.createElement(
'button');editBtn.classList.add('rl-edit-btn');editBtn.textContent='Edit list';editBtn.addEventListener('click',editList);summaryArea.appendChild(editBtn)}}}}};const observer=new MutationObserver(callback);const config={attributes:true,childList:true,subtree:true};observer.observe(document.querySelector('#reading-list-container'),config);mw.util.$content[0].appendChild(action);}}function importFunctionality(){const importValue=mw.util.getParamValue('limport')||mw.util.getParamValue('lexport');if(importValue){const btn=document.createElement('button');btn.textContent='Import this list!';mw.util.$content[0].appendChild(btn);btn.addEventListener('click',()=>{const list=fromBase64(importValue);saveReadingList(null,list.name,list.description).then((id)=>{Promise.all(Object.keys(list.list).map((project)=>addToList(id,list.list[project],project))).then(()=>{mw.notify('List successfully imported!');window.location.pathname=READING_LIST_URL;});});});}}addToUserMenu();addImportFromTable();
registerTemporaryReadingListPage();addBookmarkNextToWatchAction();importFunctionality();}());},"resources/ext.gadget.readinglist/icons.json":{"cdxIconBookmark":"\u003Cpath d=\"M5 1a2 2 0 00-2 2v16l7-5 7 5V3a2 2 0 00-2-2z\"/\u003E","cdxIconBookmarkOutline":"\u003Cpath d=\"M5 1a2 2 0 00-2 2v16l7-5 7 5V3a2 2 0 00-2-2zm10 14.25-5-3.5-5 3.5V3h10z\"/\u003E"},"resources/ext.gadget.readinglist/api.js":function(require,module,exports){const api=new mw.Api();const DEFAULT_READING_LIST_NAME='Saved';const DEFAULT_READING_LIST_DESCRIPTION='Default list for your saved articles.';function deleteCollection(id){return api.postWithToken('csrf',{action:'readinglists',list:id,command:'delete'});}function toBase64(name,description,list){return btoa(JSON.stringify({name,description,list}));}function fromBase64(data){return JSON.parse(atob(data));}function saveReadingList(id,name,description){if(id){return api.postWithToken('csrf',{action:'readinglists',list:id,name,description,command:'update'});}else{
return api.postWithToken('csrf',{action:'readinglists',name,description,command:'create'}).then((result)=>result&&result.create&&result.create.id);}}const getReadingListUrl=(ownerName,id,title)=>{let titlePath='ReadingLists';if(ownerName){titlePath+=`/${ownerName}`;}if(id){titlePath+=`/${id}`;}const titleWithName=title?`${titlePath}/${encodeURIComponent(title)}`:titlePath;try{return(new mw.Title(titleWithName,-1)).getUrl();}catch(e){return(new mw.Title(titlePath,-1)).getUrl();}};const readingListToCard=(collection,ownerName)=>{const description=collection.default?DEFAULT_READING_LIST_DESCRIPTION:collection.description;const name=collection.default?DEFAULT_READING_LIST_NAME:collection.name;const url=getReadingListUrl(ownerName,collection.id,name);return Object.assign({},collection,{ownerName,name,description,url});};function getCollections(ownerName,marked){return new Promise((resolve,reject)=>{api.get({action:'query',format:'json',rldir:'descending',rlsort:'updated',meta:'readinglists'
,formatversion:2}).then(function(data){resolve((data.query.readinglists||[]).map((collection)=>readingListToCard(collection,ownerName,marked)));},function(err){if(err==='readinglists-db-error-not-set-up'){setupCollections().then(()=>getCollections(ownerName,marked)).then((collections)=>resolve(collections));}else{reject(err);}});});}function setupCollections(){return api.postWithToken('csrf',{action:'readinglists',command:'setup'});}function getCurrentProjectName(){const server=mw.config.get('wgServer');return server.indexOf('//')===0?window.location.protocol+server:server;}function getCollectionsWithMembership(ownerName,title){return getCollections(ownerName).then((cards)=>{return api.get({action:'query',format:'json',meta:'readinglists',rldir:'descending',rlsort:'updated',rlproject:getCurrentProjectName(),rltitle:title,formatversion:2}).then(function(data){const marked=data.query.readinglists.map((collection)=>collection.id);return cards.map((card)=>{return Object.assign(card,{marked
:marked.indexOf(card.id)>-1});});});});}function addToList(id,titleOrTitles,projectName){let project=projectName||getCurrentProjectName();const title=typeof titleOrTitles==='string'?titleOrTitles:undefined;const batch=typeof titleOrTitles!=='string'?JSON.stringify(titleOrTitles.map((title)=>({title,project}))):undefined;project=batch?undefined:project;return api.postWithToken('csrf',{action:'readinglists',list:id,project,title,batch,command:'createentry'}).then((result)=>({id}));}function findItemInList(id,title){return api.get({action:'query',format:'json',list:'readinglistentries',rlelists:id}).then(function(data){const items=data.query.readinglistentries.filter((item)=>item.title===title);if(items.length===0){throw new Error('findItemInList doesn\'t know how to deal with pagination yet.');}else{return items[0];}});}function removeFromList(id,title){return findItemInList(id,title).then(function(entry){return api.postWithToken('csrf',{action:'readinglists',entry:entry.id,command:
'deleteentry'});});}module.exports={fromBase64,toBase64,saveReadingList,deleteCollection,removeFromList,addToList,getCollectionsWithMembership};},"resources/ext.gadget.readinglist/overlays.js":function(require,module,exports){const CollectionDialog=require('./CollectionDialog.vue');const CollectionEditorDialog=require('./CollectionEditorDialog.vue');const Vue=require('vue').default||require('vue');const{removeFromList,addToList,saveReadingList}=require('./api.js');function registerOverlayArea(){if(document.querySelectorAll('.readinglist-overlay-area').length){return;}const node=document.createElement('div');node.classList.add('readinglist-overlay-area');document.body.appendChild(node);}function hideOverlay(promise){registerOverlayArea();const container=document.querySelector('.readinglist-overlay-area');container.innerHTML='';}function showOverlay(promise){registerOverlayArea();return promise.then((app)=>{app.mount('.readinglist-overlay-area');});}function editListOverlay(existingID,
name,description,title,onSaveFn){const onSave=onSaveFn||(()=>{});return Vue.createMwApp(CollectionEditorDialog,{initialTitle:name,initialDescription:description,onSave:(name,description)=>{hideOverlay();saveReadingList(existingID,name,description).then((id)=>{mw.notify(existingID?'List edited!':'List created!');if(title){addToList(id,title).then(()=>{mw.notify('Added title to list!');onSave();});}else{onSave();}},()=>{mw.notify('Error creating list');})},onHide:()=>{hideOverlay();}});}function createMembersOverlay(title,collections){return Vue.createMwApp(CollectionDialog,{collections,onSelect:(id,isSelected,name,callback)=>{if(isSelected){removeFromList(id,title).then(()=>{mw.notify(isSelected?`Removed page from ${name}`:`Added page to ${name}.`);callback();});}else{addToList(id,title).then(()=>{mw.notify(isSelected?`Removed page from ${name}`:`Added page to ${name}.`);callback();});}},onCreate:()=>{showOverlay(Promise.resolve(editListOverlay(null,'','',title)));},onHide:()=>{
hideOverlay();}});}module.exports={showOverlay,hideOverlay,editListOverlay,createMembersOverlay};},"resources/ext.gadget.readinglist/CollectionDialog.vue":function(require,module,exports){const{CdxButton,CdxCard,CdxIcon}=require('@wikimedia/codex');const{cdxIconBookmark,cdxIconBookmarkOutline}=require('./icons.json');const CdxDialog=require('./Dialog.vue');module.exports={name:'CollectionDialog',components:{CdxDialog,CdxButton,CdxIcon,CdxCard},props:{collections:{type:Array}},computed:{collectionsUrl:()=>`/wiki/Special:ReadingListz/${mw.user.getName()}`,collectionsWithThumb(){return this.collections;},markedIcon:()=>cdxIconBookmark,unmarkedIcon:()=>cdxIconBookmarkOutline},data:function(){const selected={};this.collections.forEach((collection)=>{selected[collection.id]=collection.marked;});console.log('goo',selected,this.collections);return{selected};},methods:{createList:function(){this.$emit('create');},hide:function(){this.$emit('hide');},getName:function(id){const collections=this.
collections.filter((c)=>c.id===id);if(!collections.length){throw new Error('Unable to locate collection with id '+id);}return collections[0].name;},select:function(id){this.$emit('select',id,this.selected[id],this.getName(id),()=>{this.selected[id]=!this.selected[id];});}},props:{collections:[]}};;module.exports.template=
"<cdx-dialog class=\"dialog-collection\" @cancel=\"hide\" :simple=\"false\" cancel-msg=\"Cancel\" title=\"Add to existing list\"><ul><li v-for=\"(collection, i) in collectionsWithThumb\" :key=\"i\" @click=\"select(collection.id)\"><cdx-card :key=\"collection.id\" :data-selected=\"selected[collection.id]\"><template #title=\"\">{{ collection.name }}<\/template> <template #description=\"\">{{ collection.description }}<\/template> <template #supporting-text=\"\"><cdx-icon v-if=\"selected[collection.id]\" :icon=\"markedIcon\"><\/cdx-icon> <cdx-icon v-else=\"\" :icon=\"unmarkedIcon\"><\/cdx-icon><\/template><\/cdx-card><\/li><\/ul> <footer><cdx-button @click=\"createList\">Add to new list<\/cdx-button> <a :href=\"collectionsUrl\">Manage lists<\/a><\/footer><\/cdx-dialog>";},"resources/ext.gadget.readinglist/CollectionEditorDialog.vue":function(require,module,exports){const{CdxTextInput,CdxCard,CdxButton}=require('@wikimedia/codex');const CdxDialog=require('./Dialog.vue');module.exports={
name:'CollectionDialog',components:{CdxDialog,CdxTextInput,CdxButton,CdxCard},data(){return{exists:!!this.initialTitle,title:this.initialTitle,description:this.initialDescription};},computed:{label(){return this.exists?'Edit list':'Create list';},getDialogTitle(){return!this.initialDescription?'Create reading list':undefined;},isSaveDisabled(){return!this.title;},suggestion(){return{title:this.title,description:this.description};}},props:{initialTitle:{type:String,default:''},initialDescription:{type:String,default:''}},methods:{cancel(){this.$emit('hide');},save(){this.$emit('save',this.title,this.description);}}};;module.exports.template=
"<cdx-dialog @cancel=\"cancel\" :simple=\"true\" :title=\"getDialogTitle\"><div class=\"dialog-collection-editor-panel\"><cdx-card class=\"dialog-collection-editor-panel-preview\"><template #title=\"\">{{ title }}<\/template> <template #description=\"\">{{ description }}<\/template><\/cdx-card> <label>Name<\/label> <cdx-text-input v-model=\"title\" placeholder=\"Name this list\" class=\"dialog-collection-editor-panel-input\"><\/cdx-text-input> <label>Description<\/label> <cdx-text-input v-model=\"description\" placeholder=\"Describe this list\" class=\"dialog-collection-input dialog-collection-editor-panel-input-description\"><\/cdx-text-input><\/div> <template #footer=\"\"><cdx-button :disabled=\"isSaveDisabled\" @click=\"save\">{{ label }}<\/cdx-button><\/template><\/cdx-dialog>";},"resources/ext.gadget.readinglist/Dialog.vue":function(require,module,exports){const wvuiIconClose='M4.34 2.93l12.73 12.73-1.41 1.41L2.93 4.35z M17.07 4.34L4.34 17.07l-1.41-1.41L15.66 2.93z';const{
CdxButton,CdxIcon}=require('@wikimedia/codex');module.exports={name:'CdxDialog',components:{CdxButton,CdxIcon},computed:{rootClass(){return{'wvui-dialog':true,'wvui-dialog-simple':this.simple,'wvui-dialog-complex':!this.simple};}},methods:{onContinue(){this.$emit('continue')},onCancel(){this.$emit('cancel');}},props:{continueDisabled:{type:Boolean,default:false},closeIcon:{type:String,default:wvuiIconClose},continueMsg:{type:String,default:''},cancelMsg:{type:String,default:''},title:{type:String,default:'Title of dialog'},simple:{type:Boolean,default:true}}};;module.exports.template=
"<div :class=\"rootClass\"><div class=\"wvui-dialog-shield\" @click=\"onCancel\"><\/div> <div class=\"wvui-dialog-container\" @click.stop=\"\"><header class=\"wvui-dialog-container-heading\"><h2>{{ title }}<\/h2> <cdx-icon v-if=\"cancelMsg && !simple\" class=\"wvui-dialog-container-heading-cancel\" :icon=\"closeIcon\" @click=\"onCancel\">{{ cancelMsg }}<\/cdx-icon><\/header> <div class=\"wvui-dialog-container-content\"><slot><\/slot><\/div> <nav class=\"wvui-dialog-container-footer\"><slot name=\"footer\"><\/slot><\/nav><\/div><\/div>";}}},{"css":[
".mw-ui-icon-vector-gadget-pt-readinglists:before{background:url(/w/resources/lib/ooui/themes/wikimediaui/images/icons/listBullet-ltr.svg)}.readinglist-overlay-area{z-index:9999}.dialog-collection h2{font-size:1.2em;border:0;font-weight:bold;padding:0;margin:0.5em 0 0}.dialog-collection footer{text-align:center;position:absolute;bottom:10px;left:0;right:0}.dialog-collection footer a{color:#333}.dialog-collection ul{height:calc(100% - 100px);overflow:scroll}.dialog-collection li{display:flex;align-items:center}.dialog-collection li .cdx-card__text,.dialog-collection li .cdx-card{flex-grow:1}.dialog-collection li .cdx-card__text__supporting-text{justify-content:end;display:flex}.dialog-collection-editor-panel{min-width:300px}.dialog-collection-editor-panel-preview{border-top:1px solid rgba(0,0,0,0.2);border-bottom:1px solid rgba(0,0,0,0.2)}.dialog-collection-editor-panel label{margin-top:2em;font-weight:bold;margin-bottom:0.5em;display:block}.dialog-collection-editor-panel-input{margin-bottom:20px;display:block}.dialog-collection-editor-panel-input-description{margin-bottom:20px}.wvui-dialog{z-index:1;display:flex;align-items:center;justify-content:center;box-sizing:border-box}.wvui-dialog-shield,.wvui-dialog{position:fixed;top:0;bottom:0;left:0;right:0}.wvui-dialog-shield{opacity:0.5;background:#ccc}.wvui-dialog-container \u003E *{margin:0}.wvui-dialog-container-button + .wvui-dialog-container-button{margin-top:0.5em}.wvui-dialog-container-heading{display:flex}.wvui-dialog-container-heading h2{flex-grow:1;margin:0}.wvui-dialog-container{position:absolute;background:white;margin:auto}.wvui-dialog-container-heading-continue{display:none}.wvui-dialog-simple{align-items:center}.wvui-dialog-simple .wvui-dialog-container-heading{margin:0 0 1.25em}.wvui-dialog-simple .wvui-dialog-container{padding:1.5em;position:absolute;background:white;margin:auto;max-width:400px}.wvui-dialog-complex .wvui-dialog-container{height:100%;max-height:500px}.wvui-dialog-complex .wvui-dialog-container-content{overflow:scroll;height:100%}@media all and (max-width:400px){.wvui-dialog-complex{align-items:flex-start}.wvui-dialog-complex .wvui-dialog-container{width:100%;padding-bottom:40px;box-sizing:border-box}.wvui-dialog-complex .wvui-dialog-container-heading-cancel{order:1;padding:16px}.wvui-dialog-complex .wvui-dialog-container-heading h2{order:2;margin-left:16px;padding:16px 0}.wvui-dialog-complex .wvui-dialog-container-heading-continue{display:block;order:3}.wvui-dialog-complex .wvui-dialog-container-content{padding:16px;box-sizing:border-box}.wvui-dialog-complex .wvui-dialog-container-footer{display:none}}@media all and (min-width:400px){.wvui-dialog-complex .wvui-dialog-container{width:500px;max-width:500px}.wvui-dialog-complex .wvui-dialog-container-heading{margin:1.25em 1.25em 1em}.wvui-dialog-complex .wvui-dialog-container-content{margin:0 1.25em}.wvui-dialog-complex .wvui-dialog-container-footer{border-top:1px solid gray;padding:1.25em;text-align:right}}.wvui-dialog-container-footer{margin-top:1em}"
]});