login/pass: error messages below page title
[minimedit.git] / edit / page.js
index e2475a7e2de83140b89a36a8382bfd946f166973..8aa2890b8d3c426c1155a0264ad7a04fb44e68b7 100644 (file)
@@ -1,19 +1,38 @@
+var pagebody;
+
+function editorcontents() {
+       return document.getElementsByClassName('static')[0];
+}
+
+function editorsetup() {
+
+CKEDITOR.disableAutoInline = true;
+
 CKEDITOR.plugins.add('inlinesave', {
        init: function(editor) {
                editor.addCommand( 'inlinesave', {
                        exec: function (editor) {
-                               var pagename = window.location.pathname.replace(/\/$/, '/index');
+                               var pagename = window.location.pathname;
                                var body = editor.getData();
+                               // trim trailing whitespace in non-empty paragraphs
+                               body = body.replace(/((?!<p>).{3})(?:\s|\u200B)+(?=<\/p>)/g, '$1');
                                // empty line is equivalent to a paragraph break
                                body = body.replace(/<br \/>\s*<br \/>/g, '<p>');
+                               // keep names and preceding abbreviations together
+                               body = body.replace(/\b((?:[Dd]hr|[Mm](?:w|e?vr|r|r?ss?)|[A-Z])\.)\s+(?=[A-Zdtv])/g, '$1&nbsp;');
                                // wrap long line after each sentence
                                body = body.replace(/^(\t*).{73,}/mg, function (line, indent) {
+                                       if (/^<meta /.test(line)) return line; // ignore metadata headers
                                        var dots = '(?:.{24,72}|.{73,}?)'; // chars before punctuation
                                        var wrap = new RegExp('('+dots+'[.:!?]) (?=[A-Z(<])', 'g'); // separate lines
                                        return line.replace(wrap, '$1\n'+indent+'\t');
                                });
                                // treat standalone placeholders as block elements
                                body = body.replace(/<p>(\[\[.*\]\])<\/p>/g, '$1');
+                               // strip redundant domain in relative urls
+                               var hostlink = 'https?://' + window.location.hostname.replace(/\W/g, '\\$&');
+                               hostlink = new RegExp('(<a [^>]*href="|<img [^>]*src=")' + hostlink + '(?=/)', 'gi');
+                               body = body.replace(hostlink, '$1');
 
                                var data = 'body='+encodeURIComponent(body);
                                var ajaxpost = new XMLHttpRequest();
@@ -22,14 +41,24 @@ CKEDITOR.plugins.add('inlinesave', {
                                ajaxpost.onreadystatechange = function () {
                                        if (ajaxpost.readyState != 4)
                                                return; // not done yet
-                                       if (ajaxpost.status != 200)
-                                               alert('Foutcode '+ajaxpost.status+' bij opslaan: '+ajaxpost.responseText);
-                                       else
+                                       if (ajaxpost.status == 200) {
                                                editor.resetDirty();
+                                               new CKEDITOR.plugins.notification(editor, {
+                                                       message: 'Pagina is succesvol opgeslagen',
+                                                       type: 'success',
+                                               }).show();
+                                       }
+                                       else {
+                                               new CKEDITOR.plugins.notification(editor, {
+                                                       message: 'Foutcode '+ajaxpost.status+' bij opslaan: '+ajaxpost.responseText,
+                                                       type: 'warning',
+                                               }).show();
+                                       }
                                };
                                ajaxpost.send(data);
                        },
                });
+               editor.setKeystroke(CKEDITOR.CTRL + 'S'.charCodeAt(0), 'inlinesave');
                editor.ui.addButton( 'Inlinesave', {
                        command: 'inlinesave',
                        label: editor.lang.save.toolbar,
@@ -42,15 +71,30 @@ CKEDITOR.on('dialogDefinition', function (event) {
        switch (event.data.name) {
        case 'table':
                // override initial attribute values
-               var infoTab = event.data.definition.getContents('info');
-               infoTab.get('txtWidth').default = '';
-               infoTab.get('txtBorder').default = '0';
-               infoTab.get('txtCellSpace').default = '';
-               infoTab.get('txtCellPad').default = '';
+               var infotab = event.data.definition.getContents('info');
+               infotab.remove('txtWidth');
+               infotab.remove('txtHeight');
+               infotab.remove('txtBorder');
+               infotab.remove('txtCellSpace');
+               infotab.remove('txtCellPad');
+               infotab.remove('cmbAlign');
+
+               // horizontal repositioning of existing elements
+               var hbox = {
+                       id: 'hboxDimensions',
+                       type: 'hbox',
+                       children: [ infotab.get('txtCols'), infotab.get('txtRows') ],
+               };
+               infotab.add(hbox, 'selHeaders');
+               infotab.remove('txtCols');
+               infotab.remove('txtRows');
+
                break;
        case 'link':
-               //TODO: remove unneeded widgets from the Link Info tab
-               var infotab = event.data.definition.getContents('info');
+               // hide unneeded widgets from the Link Info tab
+               event.data.definition.getContents('info').get('linkType').hidden = true;
+               let linktarget = event.data.definition.getContents('target').get('linkTargetType');
+               linktarget.items = [ linktarget.items[0], linktarget.items[3] ]; // only _blank
                break;
        }
 });
@@ -76,23 +120,46 @@ CKEDITOR.on('instanceCreated', function (event) {
                var config = editor.config;
                config.language = 'nl';
                config.extraPlugins = 'inlinesave,placeholder,image2,uploadimage';
-               config.format_tags = 'h2;h3;h4;p';
-               config.allowedContent = true;
+               config.removePlugins = 'image,exportpdf'; // conflicts with imag2
+               config.allowedContent = {
+                       $1: {
+                               elements: CKEDITOR.dtd,
+                               attributes: true,
+                               styles: true,
+                               classes: true,
+                       },
+               };
+               config.disallowedContent = 'img[width,height]';
                config.entities = false; // keep unicode
-               config.filebrowserImageUploadUrl = '/edit/page?output=ckescript';
-               config.uploadUrl = '/edit/page?output=ckjson';
+               config.filebrowserImageUploadUrl = '/edit/page?output=ckjson';
                config.image2_alignClasses = ['left', 'center', 'right'];
+               config.image2_prefillDimensions = false;
                config.image2_disableResizer = true;
                config.stylesSet = [
+                       { name: 'Paginakop', element: 'h2' },
+                       { name: 'Paragraafkop', element: 'h3' },
+                       { name: 'Alineakop', element: 'h4' },
+
+                       { name: 'Gerelateerd', element: 'aside' },
+                       { name: 'Voetnoot', element: 'div', attributes: { 'class': 'right' } },
                        { name: 'Kolom', element: 'div', attributes: { 'class': 'col' } },
-                       { name: 'Rechts', element: 'div', attributes: { 'class': 'right' } },
+                       { name: 'Navigatie', element: 'p', attributes: { 'class': 'nav' } },
+                       { name: 'Waarschuwing', element: 'div', attributes: { 'class': 'warn' } },
+
+                       { name: 'Klein', element: 'small' },
+                       { name: 'Aanhaling', element: 'q' },
+                       { name: 'Doorstreept', element: 's' },
+                       { name: 'Gemarkeerd', element: 'mark' },
+                       { name: 'Rechts', element: 'span', attributes: { 'class': 'right' } },
+                       { name: 'Attributie', element: 'em', attributes: { 'class': 'right' } },
+                       { name: 'Ingelogd', element: 'span', attributes: { 'class': 'login' } },
+                       { name: 'Uitgelogd', element: 'span', attributes: { 'class': 'logout' } },
                ];
                config.pasteFilter = pastefilter;
-               config.contentsCss = document.styleSheets[0].href;
+               config.contentsCss = [...document.styleSheets].map(e => e.href).filter(Boolean);
                config.toolbar = [
                        ['Inlinesave', '-', 'Undo', 'Redo'],
-                       ['Format'],
-                       ['Bold', 'Italic', 'Link'],
+                       ['Styles', 'Bold', 'Italic', 'Link'],
                        ['BulletedList', 'NumberedList', 'Blockquote'],
                        ['Table', 'CreateDiv'],
                        ['Image', 'HorizontalRule', 'CreatePlaceholder'],
@@ -102,6 +169,7 @@ CKEDITOR.on('instanceCreated', function (event) {
                config.toolbarCanCollapse = true;
                config.floatSpacePreferRight = true;
                config.floatSpaceDockedOffsetY = 0;
+               config.title = false;
                config.startupFocus = true;
 
                config.disableObjectResizing = true;
@@ -115,20 +183,28 @@ CKEDITOR.on('instanceCreated', function (event) {
        };
 });
 
-       CKEDITOR.disableAutoInline = true;
-
-// add edit link to menu
-var pagebody = document.getElementsByClassName('static')[0];
 if (pagebody) {
-       var editlink = document.querySelector('a[href="#edit"]');
-       if (editlink)
+       // add edit link to menu
+       var editdiv = document.querySelector('header .login > p');
+       if (!editdiv) return;
+       var editlink = editdiv.appendChild(document.createElement('a'));
+       editlink.append('\u270D');
+       editlink.className = 'icon icon-edit';
+       editlink.href = '#edit';
        editlink.onclick = function (e) {
                editlink.style.fontWeight = 'bold';
                editlink.href = '';
                editlink.onclick = undefined;
+               document.body.replaceChild(pagebody, editorcontents());
                pagebody.setAttribute('contenteditable', true);
-               pagebody.innerHTML = pagebody.innerHTML
-                       .replace(/<!--BLOCK:(.*?)-->[^]*?<!--\/-->/g, '$1');
+               pagebody.querySelectorAll('[data-dyn]').forEach(function (el) {
+                       let blockname = el.getAttribute('data-dyn');
+                       if (!blockname) {
+                               el.remove();
+                               return;
+                       }
+                       el.outerHTML = '[[' + blockname + ']]';
+               });
                CKEDITOR.inline(pagebody, { customConfig: '' });
                document.body.className = 'edit';
                return false;
@@ -138,3 +214,15 @@ if (pagebody) {
        }
 }
 
+}
+
+var ckesrc = document.currentScript.getAttribute('data-ckesrc');
+document.addEventListener('DOMContentLoaded', function (e) {
+       pagebody = editorcontents();
+       if (!pagebody) return;
+       pagebody = pagebody.cloneNode(true);
+       var editorinc = document.createElement('script');
+       editorinc.addEventListener('load', editorsetup);
+       editorinc.src = ckesrc;
+       document.getElementsByTagName('head')[0].appendChild(editorinc);
+});