User:BEANS X2/Scripts/TodoList.js

/*** Todo List ***/

// Adds a todo list that also has a convient popup // By User:BrandonXLF // Forked by User:BEANS X2

$.when(mw.loader.using([ 'mediawiki.user', 'oojs-ui-core', 'oojs-ui-windows', 'oojs-ui.styles.icons-movement', 'oojs-ui.styles.icons-editing-core', 'oojs-ui.styles.icons-interactions', 'oojs-ui.styles.icons-moderation', 'oojs-ui.styles.icons-content' ]),$.ready).then(function{	mw.util.addCSS( '.userjs-todo-list .item:hover .act { visibility: visible !important; }' + '[data-drop="above"]::before { display: block; border-top: 2px solid #066; margin-top: -2px; content: ""; }' + '[data-drop="below"]::after { display: block; border-top: 2px solid #066; margin-top: -2px; content: ""; }' + '.userjs-todo-list .items:empty { border: none !important; margin: 0 !important; padding: 0 !important;}' + '.userjs-todo-moreinfo > a { min-width: unset !important; min-height: unset !important; padding: 0.65em !important; }' + '.userjs-todo-moreinfo > a > span { min-width: unset !important; min-height: unset !important; width: 1.3em !important; left: 0 !important; }' );	if (mw.config.get('skin') === 'minerva') {		mw.util.addCSS( '.userjs-todo-list .item .act { visibility: visible !important; }' + '#userjs-todo-popup { top: 0 !important; bottom: 0 !important; left: 0 !important; right: 0 !important; width: 100%; height: 100%; }' + '#userjs-todo-popup .userjs-todo-list { width: 100%; height: 100%; } ' );	}	var api = new mw.Api;	var link = $(mw.util.addPortletLink('p-personal', mw.util.getUrl('Special:BlankPage/todo'), 'note', 'userjs-todo', 'Click to see your todo list', 'd', '#pt-mytalk'));	$("#userjs-todo a").addClass("material-icons icon")	var changes = [mw.user.options.get('userjs-todo-script')];	var undo = 0;	var req = 0;	var parent;	var ispopup = false;	var loader = $('').on('change',function(e){ if (!this.files || !this.files[0]) return; var file = this.files[0]; var reader = new FileReader; reader.onload = function (e) { save(reader.result, true, true); };		reader.readAsText(file); }).appendTo(document.body);	$(window).on('beforeunload',function { if (req > 0) return true; });	function save (what, record, relist) {		if (typeof what != 'string') { what = JSON.stringify(what); }		mw.user.options.set('userjs-todo-script', what);		req++;		parent.find('.status').text('Saving changes...');		api.saveOption('userjs-todo-script', what).done(function{ req--; if (req === 0) { parent.find('.status').text(''); }		});		if (record !== false) {			while (undo > 0) {				changes.pop;				undo--;			}			changes.push(mw.user.options.get('userjs-todo-script'));			if (changes.length > 50) changes.shift;		}		if (relist) {			list;			if (req > 0) {				parent.find('.status').text('Saving changes...');			}		}	}	Math.clamp = function (max, x, min) {		return Math.min(max, Math.max(min, x));	};	function item (parent, array) {		var date = new Date(+array[2]);		var url = array[0] || ;		var txt = array[0] || ;		if (url.match(/^(https:|http:|:)\/\//) && url.match(/ /)) {			var reg = /(.*?) (.*)/.exec(url);			url = reg[1];			txt = reg[2];		} else if (!url.match(/^(https:|http:|:)\/\//)) {			url = mw.util.getUrl(url);		}		parent.append($(' ') .attr('data-page', array[0] || '') .attr('data-info', array[1] || '') .attr('data-date', array[2] || '') .append((new OO.ui.IconWidget({icon:'draggable',title:'Drag'})).$element				.css({cursor:'move',height:'1.2em',width:'1.2em',minWidth:'unset',minHeight:'unset',marginRight:'0.5em'})				.on('mousedown',function{ $(this).parent.attr('draggable','true'); })				.on('mouseup',function{ $(this).parent.attr('draggable','false'); })			)			.append(' ' + txt + ' ') .append(array[0] && array[1] ? ' . . ' : '') .append(' ' + (array[1] || '') + ' ') .append(array[0] || array[1] ? ' . . ' : '') .append((new OO.ui.IconWidget({icon:'trash',title:'Delete',flags:['destructive']})).$element				.css({cursor:'pointer',visibility:'hidden',height:'1.1em',width:'1.1em',minWidth:'unset',minHeight:'unset',marginRight:'0.5em'})				.addClass('act')				.click(function{ var arr = []; $(this).parent.siblings.each(function(i){						arr.push([$(this).attr('data-page'),$(this).attr('data-info'),$(this).attr('data-date')]);					}); $(this).parent.remove; save(arr); })			)			.append((new OO.ui.IconWidget({icon:'edit',title:'Edit',flags:['progressive']})).$element				.css({cursor:'pointer',visibility:'hidden',height:'1em',width:'1em',minWidth:'unset',minHeight:'unset',marginRight:'0.5em'})				.addClass('act edit')				.click(function{ $(this).css('display','none'); $(' ')						.append((new OO.ui.TextInputWidget({ 							placeholder: 'Page name or URL',							value: $(this).parent.attr('data-page')						})).$element.css({maxWidth:'unset',margin:'4px 0'})) .append((new OO.ui.TextInputWidget({ 							placeholder: 'Comment',							value: $(this).parent.attr('data-info')						})).$element.css({maxWidth:'unset',margin:'4px 0'})) .append($(' Ex: Ex:  ')							.append('Comment: An additional comment.')						) .append(' Notes ') .append($('')							.append('A valid URL must start with,   or   or else it will be treated as a page name. Page names will by automatically converted to a link to the wiki article with that title.')							.append('If the URL contains a space, the text after the space will be used as the display text. For example,  will show up as   since URLs cannot contain spaces. Spaces can be repersented as,   or  .</li>')							.append('<li>Page names cannot be be displayed differently than the page name. If you desire to diplay the name differently, use the URL of the page followed by your desired display text instead.</li>')							.append('<li>Page name and Comment are optional, but at least one is required.</li>')						) .append(' Managing and deleting items ') .append(' Global ') .append($('<ul></ul>')							.append('<li>Redo and Undo: Redo and undo changes. You should not expect to be able to undo all changes. Changes including uploading a todo list, deleting an item, reordering items, deleting the todo list, editing an item, redoing a change, and adding an item. Redo will redo the last undone change. Once you reload the editor, all change history is lost.</li>')							.append('<li>Clear: Delete your entire todo list. This should be able to be undone, but don\'t rely on it. Once you reload the editor, this action cannot be undone.</li>')							.append('<li>Download: Download all itmes currently in the todo list as a JSON file. The file can later to uploaded again the replace the current todo list. Do not edit the JSON file unless you understand the risks associated with doing so and you understand the structure of the file.</li>')							.append('<li>Upload: Upload a todo list JSON file. The new list will replace the current list. The operation should be able to be undone. Only upload a file created by the download fiel button, or else you may cause issues with the script, causing it to become non functional.</li>')						) .append(' Item specfic ') .append($('<ul></ul>')							.append($('<li></li>') .append((new OO.ui.IconWidget({icon:'draggable'}).$element.css({height:'1.2em',width:'1.2em',minWidth:'unset',minHeight:'unset',marginRight:'0.5em'}))) .append('Drag: Drag to change the position of the item. ') )							.append($('<li></li>') .append((new OO.ui.IconWidget({icon:'trash',flags:['destructive']})).$element.css({height:'1.1em',width:'1.1em',minWidth:'unset',minHeight:'unset',marginRight:'0.5em'})) .append('Delete: Delete an item. ') )							.append($('<li></li>') .append((new OO.ui.IconWidget({icon:'edit',flags:['progressive']})).$element.css({height:'1em',width:'1em',minWidth:'unset',minHeight:'unset',marginRight:'0.5em'})) .append('Edit: Edit an item (page name & comment) ') )							.append($('<li></li>') .append((new OO.ui.IconWidget({icon:'info'})).$element.css({height:'1.3em',width:'1.3em',minWidth:'unset',minHeight:'unset',marginRight:'0.2em'})) .append('More information: View more information about an item. ') )						)						.append(' Saving changes ') .append('<ul><li>All changes are synced with the API after an action is performed (saving, deleting, dragging etc.).</li><li>When a change is being saved the text "Saving changes..." should appear at the end of the list. Do not leave the page or close the popup until the text dissapears as this may cause changes to not be saved.</li></ul>') .append(' About ') .append(' <a href="' + mw.util.getUrl('User:BrandonXLF/TodoList') + '">Todo List</a> (<a href="' + mw.util.getUrl('User:BrandonXLF/TodoList.js') + '">code</a>) by <a href="' + mw.util.getUrl('User:BrandonXLF') + '">User:BrandonXLF</a> (<a href="' + mw.util.getUrl('User talk:BrandonXLF') + '">talk</a>) ') .appendTo($('.userjs-todo-list')) ;				}))			)			.append($(' ') .append((new OO.ui.TextInputWidget({ 					placeholder: 'Page name or URL',					value: mw.config.get('wgPageName').replace(/_/g,' ') != 'Special:BlankPage/todo' ? mw.config.get('wgPageName').replace(/_/g,' ') : ''				})).$element.css({maxWidth:'unset',margin:'4px 0'})) .append((new OO.ui.TextInputWidget({ 					placeholder: 'Comment'				})).$element.css({maxWidth:'unset',margin:'4px 0'})) .append((new OO.ui.ButtonWidget({ 					label: 'Add'				}).$element.css('width','100%').children.css('width','100%').parent).click(function{ var opts = JSON.parse(mw.user.options.get('userjs-todo-script') || '[]'); var arr = []; arr.push($(this).parent.parent.find('input[placeholder="Page name or URL"]').val); arr.push($(this).parent.parent.find('input[placeholder="Comment"]').val); if (!arr.join('')) return; arr.push((new Date).getTime); item($('.userjs-todo-list .items'), arr); opts.push(arr); save(opts); $('#userjs-todo-popup').css({top:Math.max(parseInt($('#userjs-todo-popup').css('top')),0)}); }))			)			.append($(' '))			.append(' ')		); if (ispopup) { todo.find('.todo-menu') .css('cursor','grab') .append((new OO.ui.ButtonWidget({					framed: false,					icon: 'close',					invisibleLabel: true,					title: 'Close'				}).$element.css({float:'right',marginRight:'0'}).click(function{					parent.remove;				}))) .append(($('<a></a>').attr('href',mw.util.getUrl('Special:BlankPage/todo')).append((new OO.ui.ButtonWidget({					framed: false,					icon: 'newWindow',					invisibleLabel: true,					title: 'Your Todo List'				}).$element.css('float','right').click(function{					location.url = mw.util.getUrl('Special:BlankPage/todo');				}))))) .on('mousedown',function(e){					if (e.target !== this) return;					this.style.cursor = 'grabbing';					var x = parent.position.left - e.pageX;					var y = parent.position.top - e.pageY;					var b = $(document.body);					function move (e) {						parent.css({ left: Math.clamp($(window).width - parent.width, e.pageX + x, 0) + 'px', top: Math.clamp($(window).height - parent.height, e.pageY +	y, 0) + 'px', right: '', bottom: '' });					}					function up {						e.target.style.cursor = 'grab';						b.off('mousemove', move);						b.off('mouseup', up);					}					b.on('mousemove',move);					b.on('mouseup',up);				}); }		$.each(JSON.parse(mw.user.options.get('userjs-todo-script') || '[]'), function (a,b) { item(todo.find('.items'), b); }); return todo; }	function repos (pos,css,pvar,cond,pcss,ccss) { return $(' ').attr('id',pos + 'gfdgfdgfd').css('cursor',pos + '-resize').css(css).on('mousedown',function(e){			if (e.target !== this) return;			var p = parent;			var c = p.find('.userjs-todo-list');			var q = eval(pvar);			var b = $(document.body);			b.css('user-select','none');			function move (e) {				if (eval(cond)) return;				(new Function('e', 'p', 'q', 'p.css(' + pcss + ')'))(e, p, q);				(new Function('e', 'c', 'q', 'c.css(' + ccss + ')'))(e, c, q);			}			function up {				b.css('user-select','');				b.off('mousemove', move);				b.off('mouseup', up);			}			b.on('mousemove', move);			b.on('mouseup', up);		}); }	if (mw.config.get('wgPageName') === 'Special:BlankPage/todo') { document.title = 'Your Todo List - ' + mw.config.get('wgSiteName'); $('#firstHeading').text('Your Todo List'); parent = mw.util.$content.empty; list; link.children.first.click(function(e){			e.preventDefault;			mw.notify('Unable to open todo list popup while on the todo list page.',{tag:'rtbyilounmt7udfnod'});		}); } else { link.children.first.click(function(e){			e.preventDefault;			if ($('#userjs-todo-popup').css("visibility") == "visible") {				$('#userjs-todo-popup').css("visibility","hidden")				ispopup=false			}			else if ($('#userjs-todo-popup').css("visibility") == "hidden") {				$('#userjs-todo-popup').css("visibility","visible")				ispopup = true			}			else {				ispopup = true;				parent = $('<div style="overflow:auto;min-height:3em;z-index:' + "100" + ';box-shadow:0 2px 2px 0 rgba(0,0,0,0.25);color:#222;min-width:20em;position:fixed;right:25px;background-color:white;border-radius:4px;border: 1px solid #a2a9b1;font-size:0.75rem;max-width:100vw;max-height:100vh;" id="userjs-todo-popup"> ')					.appendTo(document.body)					.css('top',link.position.top + link.height + 8 + 'px')					.append($(' ') .append(repos('e',{top:0,right:0,width:'7px',height:'100%'},'p.position.left','e.clientX - q < 40','{right:"",minWidth:"",left:q	+ "px"}','{width:e.clientX - q + "px"}')) .append(repos('n',{top:0,height:'7px',width:'100%'},'p.position.top + p.height','q <= e.clientY + 40','{top:Math.max(e.clientY, 0) + "px"}','{height:q - e.clientY + "px"}')) .append(repos('s',{bottom:0,height:'7px',width:'100%'},'p.position.top','e.clientY - q < 40','{top:Math.max(q,0) + "px"}','{height:e.clientY - q + "px"}')) .append(repos('w',{left:0,width:'7px',height:'100%'},'p.position.left + parent.width','q <= e.clientX + 40','{right:"",minWidth:"",left:e.clientX + "px"}','{width:q - e.clientX + "px"}')) .append($('<div style="pointer-events:all;position:absolute;height:100%;top:0;right:0;width:7px;height:7px;cursor:ne-resize;"> ').on('mousedown',function(e){ e.originalEvent.stopImmediatePropagation; $('#egfdgfdgfd').trigger('mousedown'); $('#ngfdgfdgfd').trigger('mousedown'); }))						.append($('<div style="pointer-events:all;position:absolute;height:100%;top:0;left:0;width:7px;height:7px;cursor:nw-resize;"> ').on('mousedown',function(e){ e.originalEvent.stopImmediatePropagation; $('#wgfdgfdgfd').trigger('mousedown'); $('#ngfdgfdgfd').trigger('mousedown'); }))						.append($('<div style="pointer-events:all;position:absolute;height:100%;bottom:0;right:0;width:7px;height:7px;cursor:se-resize;"> ').on('mousedown',function(e){ e.originalEvent.stopImmediatePropagation; $('#egfdgfdgfd').trigger('mousedown'); $('#sgfdgfdgfd').trigger('mousedown'); }))						.append($('<div style="pointer-events:all;position:absolute;height:100%;bottom:0;left:0;width:7px;height:7px;cursor:sw-resize;"> ').on('mousedown',function(e){ e.originalEvent.stopImmediatePropagation; $('#wgfdgfdgfd').trigger('mousedown'); $('#sgfdgfdgfd').trigger('mousedown'); }))					)			}				parent.css('top',Math.max(parseInt(parent.css('top')),0));				list;		}); } });