User:Philippe/Scripts/Notepad.js

'use strict';

var api = new mw.Api({});

var app = { styleSheet: mw.util.addCSS(`           :root {                --notepad-width: 30vw             }            body.notepad {                margin-right: var(--notepad-width)            }            body.notepad #p-personal {                margin-right: var(--notepad-width)            }            body.notepad #right-navigation {                margin-right: var(--notepad-width)            }            body.notepad #simpleSearch {                width: 5em            }            body:not(.notepad) #notepad-window {                display: none            }            #notepad-window {                position:fixed;                 top:0;                 right:0;                 bottom: 0;                 width: var(--notepad-width);                 border-left: 2px solid #a7d7f9;                 box-shadow: 0px 0px 4px 2px #eee;                 background-color: #fcfdfe;             } #notepad-window:before { top: -100px; content: ''; position:absolute; left: -30px; width: 0; height: 0; border: 15px solid transparent; border-right-color: #a7d7f9; margin-top:-15px; }           #notepad-window:after { top: -100px; content: ''; position:absolute; left: -25px; width: 0; height: 0; border: 15px solid transparent; border-right-color: transparent; margin-top:-15px; }           #notepad-window #notepad-slider { position:absolute; top: 20px; left: -10px; bottom: 0; width: 15px; opacity: 0; cursor: ew-resize; }           #notepad-window #notepad-container { height: 100%; width: 100%; padding: 0px 10px; line-height: 1.6; font-size: 0.875em; }           #notepad-window article { position:absolute; top: 50px; bottom: 0px; width: calc(100% - 15px); overflow: auto; }           #notepad-window textarea { height: 100%; width: 100%; background-color: transparent; border: none; resize: none; }           #notepad-window textarea:focus { outline-color: transparent; }

#notepad-container:not([status=saving]) #notepad-saving { display:none; }           #notepad-container #notepad-saving { position:fixed; top: 0px; right: 0px; font-size: 10px; padding: 2px; width: 40px; text-align:center; background-color: #fef6e7; }

#notepad-container:not([tab=edit]) #notepad-edit { display:none; }           #notepad-container:not([tab=render]) #notepad-render { display:none; }           #notepad-container:not([tab=all]) #notepad-all { display:none; }           #notepad-container:not([tab=con:wfig]) #notepad-config { display:none; }

#notepad-container #notepad-header { border-bottom: 1px solid #ccc; padding: 8px 0; margin: 0; }           #notepad-container #notepad-header a { padding: 10px 20px; font-weight: bold; color: black; font-size: 12px; }           #notepad-container[tab=edit] #notepad-link-edit, #notepad-container[tab=render] #notepad-link-render, #notepad-container[tab=all] #notepad-link-all, #notepad-container #notepad-header a:hover { color: #0645ad; border-bottom: 2px solid #0645ad; text-decoration: none; }

#notepad-container #notepad-render #loading { position:absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #a7d7f9; }           #notepad-container #notepad-render #loading img { width: 30px; height: 30px; opacity:0.5; }

#notepad-container #notepad-all a { color: #000; }           #notepad-container #notepad-all a:hover, #notepad-container #notepad-all a:focus { text-decoration: none; color: #000; }

#notepad-container #notepad-all section { box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); width: calc(100% - 32px); margin:10px auto; padding:10px; }           #notepad-container #notepad-all section:hover { box-shadow: 0 4px 8px 0 rgba(6,69,173,0.2); outline: 2px solid #a7d7f9; }           #notepad-container #notepad-all section h4 { color: #0645ad; padding: 0; }           #notepad-container #notepad-all section > div { font-family: monospace; max-height: 190px; overflow: hidden; }

`),       init: function(oninit, onload) {            app.onload = onload;            mw.loader.using(["mediawiki.util", "mediawiki.user"]).then(function  { app.$link = $(mw.util.addPortletLink('p-views', , 'Notes', 'notepad-portlet', 'Private notepad [ctrl+alt+n]', , '.mw-watchlink')) app.$link.click(app.click);

document.addEventListener('keydown', function(e) {                   if (e.altKey && e.ctrlKey && e.code == 'KeyN') {                        app.$link.click;                    }                });

oninit; })       },        click: function(e) {            e.preventDefault;            if (!app.loaded) app.load;            app.$link.toggleClass('selected');            $("body").toggleClass('notepad');            app.resize;        },        load: function {            var $wnd = $(" ", {'id': 'notepad-window'}).appendTo("body");            var $container = $(" ", {'id': 'notepad-container'}).appendTo($wnd);

$wnd.append(               $(" ", {'id': 'notepad-slider'})                .mousedown(function(e) { function mouseup { $("body").off("mousemove", app.mousemove); app.resize; }                   if (e.which==1) { mouseup; app.mousemove = function(e) { e.preventDefault; var x = e.pageX; if (x * 2 < window.innerWidth) x = (window.innerWidth/2)+1 if (window.innerWidth - x < 100) x = window.innerWidth - 99 app.resize("calc(100vw - 12px - " + x + "px)", x==e.pageX); }                       $("body").mousemove(app.mousemove); $("body").mouseup(mouseup); }               })            );            app.$container = $container; app.loaded=true; app.onload; },       resize: function(val, suppresstrigger) { if (val) document.body.style.setProperty('--notepad-width', val); if (!suppresstrigger) window.dispatchEvent(new Event('resize')); }   }

var util = { get pagename { var ns = mw.config.get('wgNamespaceNumber'); var page = mw.config.get('wgPageName'); if (ns % 2 == 1) { var p1 = mw.config.get('wgFormattedNamespaces')[ns].replace(' ', '_'); var p0 = mw.config.get('wgFormattedNamespaces')[ns-1].replace(' ', '_'); var r = new RegExp("^" + p1 + ':'); page = page.replace(r, p0 + ':'); }

return page; },       get now { function pad(n) { if (n<10) { return '0' + n;               } else { return '' + n;               } }           var d = new Date return d.getUTCFullYear + '-' + pad(d.getUTCMonth+1) + '-' + pad(d.getUTCDate) + 'T'            + pad(d.getUTCHours) + ':' + pad(d.getUTCMinutes) + ':' + pad(d.getUTCSeconds) + 'Z'; }   }

var notes = { get: function { var s = mw.user.options.get("userjs-pagenotes"); if (s && s.length) { var obj = JSON.parse(s); return obj[util.pagename] } else { return ""; }       },        refresh: function { var deferred = new $.Deferred; api.get({               action: 'query',                meta: 'userinfo',                uiprop: 'options'            }).done(function (response, data) {                var s = data.responseJSON.query.userinfo.options['userjs-pagenotes'];                mw.user.options.set('userjs-pagenotes', s);                deferred.resolve(s);            }); return deferred.promise; },       save: function(content) { var deferred = new $.Deferred; var cur = mw.user.options.get("userjs-pagenotes"); var obj = {}; if (cur && cur.length) { obj = JSON.parse(cur); }           if (!obj[util.pagename] || (obj[util.pagename] && (content != obj[util.pagename].content))) { if (content) { obj[util.pagename] = { 'updated': util.now, 'content': content };               } else { delete obj[util.pagename] }               var out = JSON.stringify(obj); mw.user.options.set("userjs-pagenotes", out); api.saveOption("userjs-pagenotes", out).then(function {                   deferred.resolve;                }); } else { deferred.resolve; }           return deferred.promise; },       init: function { var $link = app.$link; if (notes.get) { $link.find('a').css('font-weight', 'bold'); }       },        onload: function { var $container = app.$container var text = ''; if (notes.get) { $container.attr('tab', 'render'); text = notes.get.content; } else { $container.attr('tab', 'edit'); }

//draw top bar $(" ", {'id': 'notepad-header'}) .appendTo($container) .append($("", {'id': 'notepad-link-edit'}).text("Notes")                   .click(function  { $container.attr('tab', 'edit') }))               .append($("", {'id': 'notepad-link-render'}).text("Preview")                    .click(function { $container.attr('tab', 'render'); save; render; }))               .append($("", {'id': 'notepad-link-all'}).text("Recent")                    .click(function { $container.attr('tab', 'all'); save; allnotes; }))

//draw edit window var $editwindow = $(" ", {'id': 'notepad-edit'}).appendTo($container); var $saving = $(' ', {'id': 'notepad-saving'}).appendTo($editwindow); $saving.append('Saving...'); var $textarea = $(" ", {'id': 'notepad-text', 'placeholder': 'Record a private note here...'}).appendTo($editwindow); $textarea.val(text);

function save { notes.save($.trim($textarea.val)).then(function {                   $container.attr('status', 'saved');                }); }

var timer = 0; $textarea.change(function {               clearTimeout(timer);                $container.attr('status', 'saving');                save;            }); $textarea.keyup(function {               clearTimeout(timer);                $container.attr('status', 'saving');                timer = setTimeout(function { save }, 1000);           });

//draw render window var $renderwindow = $(" ", {'id': 'notepad-render'}).appendTo($container); $(' ', {'id': 'loading'}) .append($(' ', {'src': "https://upload.wikimedia.org/wikipedia/commons/3/30/Chromiumthrobber.svg"})) .appendTo($renderwindow);

function render { if (notes.get && notes.get.content) { var s = notes.get.content; api.parse(s, {'contentmodel': 'wikitext', 'preview': true, 'pst': true}) .then(function(data) {                           $renderwindow.empty.append($(data));                            $renderwindow.find('.mw-editsection').remove;                        }); } else { $renderwindow.empty }           }            render;

//draw all notes var $allnotes = $(" ", {'id': 'notepad-all'}).appendTo($container); function allnotes { $allnotes.empty; var s = mw.user.options.get("userjs-pagenotes"); if (s && s.length) { var list = JSON.parse(s); var keys = Object.keys(list).sort(                       function(a,b) {                            if (list[a].updated > list[b].updated) return -1;                            if (list[a].updated < list[b].updated) return 1;                            return 0;                        }                    );

for (var i=0; i', {'href': '/wiki/' + keys[i]}).appendTo($allnotes); var $sec = $(' ', {'key': keys[i]}).appendTo($a); $sec.append($(' ').append(keys[i].replace(/_/g,' '))); var $preview = $(' ').appendTo($sec);

var content = list[keys[i]].content; $preview.append(content); }               }            }

//refresh from server on focus window.addEventListener('focus', function {               notes.refresh.then(function  { var g = notes.get; if (g) { $textarea.val(notes.get.content); } else { $textarea.val(''); }                   render; allnotes; console.log('focus'); });                           });

}   }

app.init(notes.init, notes.onload);

} (jQuery, mediaWiki ));