Updated system, spring remix with a better editor

This commit is contained in:
markseu 2018-04-15 14:45:50 +02:00
parent 8c5d7e58d9
commit ef97347fe2
12 changed files with 1009 additions and 129 deletions

View file

@ -55,6 +55,7 @@ MultiLanguageMode: 0
InstallationMode: 1
StartupUpdate: none
EditLocation: /edit/
EditToolbarButtons: auto
EditEndOfLine: auto
EditUserFile: user.ini
EditUserPasswordMinLength: 4

View file

@ -5,7 +5,7 @@
class YellowCore
{
const VERSION = "0.7.2";
const VERSION = "0.7.3";
var $page; //current page
var $pages; //pages from file system
var $files; //files from file system

245
system/plugins/edit.css Executable file → Normal file
View file

@ -2,7 +2,7 @@
/* Copyright (c) 2013-2018 Datenstrom, https://datenstrom.se */
/* This file may be used and distributed under the terms of the public license. */
.yellow-bar { position:relative; overflow:hidden; line-height:2em; margin-bottom:10px; }
.yellow-bar { position:relative; line-height:2em; margin-bottom:10px; }
.yellow-bar-left { display:block; float:left; }
.yellow-bar-right { display:block; float:right; }
.yellow-bar-right a { margin-left:1em; }
@ -18,19 +18,20 @@
}
.yellow-pane h1 { color:#000; font-size:2em; margin:0 1em; }
.yellow-pane p { margin:0.5em; }
.yellow-pane div { overflow:hidden; }
.yellow-close {
position:absolute;
top:0.4em; right:0.8em; cursor:pointer;
font-size:1.2em; color:#bbb; text-decoration:none; }
top:0.8em; right:1em; cursor:pointer;
font-size:0.9em; color:#bbb; text-decoration:none;
}
.yellow-close:hover { color:#000; text-decoration:none; }
.yellow-arrow { position:absolute; top:0; left:0; }
.yellow-arrow:after, .yellow-arrow:before {
position:absolute;
pointer-events:none;
bottom:100%;
height:0; width:0;
border:solid transparent;
content:" ";
content:"";
}
.yellow-arrow:after {
border-color:rgba(255, 255, 255, 0);
@ -44,10 +45,88 @@
border-width:11px;
margin-left:-11px;
}
.yellow-popup {
position:absolute; display:none; z-index:200; padding:10px 0;
background-color:#fff; color:#000;
border:1px solid #bbb;
border-radius:4px; box-shadow:2px 4px 10px rgba(0, 0, 0, 0.2);
}
.yellow-dropdown { list-style:none; margin:0; padding:0; }
.yellow-dropdown span { display:block; margin:0; padding:0.25em 1em; }
.yellow-dropdown a { display:block; padding:0.2em 1em; text-decoration:none; }
.yellow-dropdown a:hover { color:#fff; background-color:#18e; text-decoration:none; }
.yellow-dropdown-menu a { color:#000; }
.yellow-toolbar { list-style:none; margin:0; padding:0; }
.yellow-toolbar-left { display:inline-block; float:left; }
.yellow-toolbar-right { display:inline-block; float:right; }
.yellow-toolbar-banner { clear:both; }
.yellow-toolbar li { display:inline-block; vertical-align:top; }
.yellow-toolbar a {
display:inline-block; padding:6px 16px; text-decoration:none;
background-color:#fff; color:#000;
font-size:0.9em; font-weight:normal;
border:1px solid #bbb;
border-radius:4px;
}
.yellow-toolbar a:hover {
background-color:#18e; background-image:none; border-color:#18e; color:#fff;
text-decoration:none;
}
.yellow-toolbar-left a { margin-right:4px; margin-bottom:10px; }
.yellow-toolbar-right a { margin-left:4px; margin-bottom:10px; }
.yellow-toolbar .yellow-icon
{
font-size:0.9em; min-width:1em; text-align:center;
}
.yellow-toolbar .yellow-toolbar-btn {
padding:6px 10px; min-width:4em; text-align:center;
}
.yellow-toolbar .yellow-toolbar-btn-edit {
background-color:#29f; border-color:#29f; color:#fff;
}
.yellow-toolbar .yellow-toolbar-btn-create {
background-color:#29f; border-color:#29f; color:#fff
}
.yellow-toolbar .yellow-toolbar-btn-delete {
background-color:#e55; border-color:#e55; color:#fff
}
.yellow-toolbar .yellow-toolbar-btn-delete:hover { background-color:#d44; border-color:#d44; }
.yellow-toolbar .yellow-toolbar-btn-separator { visibility:hidden; padding:6px; }
.yellow-toolbar-tooltip { position:relative; }
.yellow-toolbar-tooltip::after, .yellow-toolbar-tooltip::before {
position:absolute; z-index:300; display:none;
pointer-events:none;
}
.yellow-toolbar-tooltip::after {
padding:2px 9px;
font-weight:normal;
font-size:0.9em;
text-align:center;
white-space:nowrap;
content:attr(aria-label);
background-color:#111; color:#ddd;
border-radius:3px;
top:100%;
right:50%;
margin-top:6px;
transform:translateX(50%);
}
.yellow-toolbar-tooltip::before {
width:0; height:0;
content:"";
border:4px solid transparent;
top:auto;
right:50%;
bottom:-6px;
margin-right:-4px;
border-bottom-color:#111;
}
.yellow-toolbar-tooltip:hover::before, .yellow-toolbar-tooltip:hover::after {
display:inline-block;
}
.yellow-toolbar-selected.yellow-toolbar-tooltip::before, .yellow-toolbar-selected.yellow-toolbar-tooltip::after {
display:none;
}
.yellow-form-control {
margin:0; padding:2px 4px;
display:inline-block;
@ -76,12 +155,6 @@
text-decoration:none;
}
.yellow-btn:active { box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.1); }
.yellow-btn-delete {
background-color:#c33c35; color:#ffffff;
background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);
border-color:#b13121 #b13121 #802020;
}
.yellow-btn-delete:hover, .yellow-btn-delete:focus, .yellow-btn-delete:active { color:#ffffff; }
#yellow-pane-login { text-align:center; white-space:nowrap; }
#yellow-pane-login .yellow-form-control { width:15em; box-sizing:border-box; }
@ -117,10 +190,150 @@
#yellow-pane-version-fields { text-align:center; margin:0.5em 0; }
#yellow-pane-version-buttons { margin-top:-0.5em; }
#yellow-pane-edit h1 { margin:0 0 10px 0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
#yellow-pane-edit-page { padding:5px; outline:none; resize:none; }
#yellow-pane-edit-buttons { margin-top:5px; }
#yellow-pane-edit-buttons input { margin-right:10px; }
#yellow-pane-edit-help { float:right; }
#yellow-pane-edit-toolbar-title { margin:-5px 0 0 0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
#yellow-pane-edit-text { padding:0 2px; outline:none; resize:none; border:none; }
#yellow-pane-edit-preview { padding:0; overflow:auto; }
#yellow-pane-edit-preview h1 { margin:0.67em 0; }
#yellow-pane-edit-preview p { margin:1em 0; }
#yellow-pane-edit-preview .content { margin:0; padding:0; }
#yellow-pane-user { padding:10px 0; }
#yellow-popup-format, #yellow-popup-heading, #yellow-popup-list { width:16em; }
#yellow-popup-format a, #yellow-popup-heading a { padding:0.25em 16px; }
#yellow-popup-format #yellow-popup-format-h1, #yellow-popup-heading #yellow-popup-heading-h1 { font-size:2em; font-weight:bold; }
#yellow-popup-format #yellow-popup-format-h2, #yellow-popup-heading #yellow-popup-heading-h2 { font-size:1.6em; font-weight:bold; }
#yellow-popup-format #yellow-popup-format-h3, #yellow-popup-heading #yellow-popup-heading-h3 { font-size:1.3em; font-weight:bold; }
#yellow-popup-format #yellow-popup-format-quote { font-style:italic; }
#yellow-popup-format #yellow-popup-format-pre { font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace; font-size:0.9em; line-height:1.8; }
#yellow-popup-emojiawesome { padding:10px; width:14em; }
#yellow-popup-emojiawesome a { padding:0.2em; }
#yellow-popup-emojiawesome .yellow-dropdown li { display:inline-block; }
#yellow-popup-fontawesome { padding:10px; width:13em; }
#yellow-popup-fontawesome a { padding:0.18em 0.3em; min-width:1em; text-align:center; }
#yellow-popup-fontawesome .yellow-dropdown li { display:inline-block; }
@font-face {
font-family:'Edit';
font-weight:normal;
font-style:normal;
src:url('edit.woff') format('woff');
}
.yellow-icon {
display:inline-block;
font-family:Edit;
font-style:normal;
font-weight:normal;
-webkit-font-smoothing:antialiased;
-moz-osx-font-smoothing:grayscale;
}
.yellow-spin {
-webkit-animation:yellow-spin 1s infinite steps(16);
animation:yellow-spin 1s infinite steps(16);
}
@-webkit-keyframes yellow-spin {
0% { -webkit-transform:rotate(0deg); transform:rotate(0deg); }
100% { -webkit-transform:rotate(359deg); transform:rotate(359deg); }
}
@keyframes yellow-spin {
0% { -webkit-transform:rotate(0deg); transform:rotate(0deg); }
100% { -webkit-transform:rotate(359deg); transform:rotate(359deg); }
}
.yellow-icon-preview:before {
content: "\f100";
}
.yellow-icon-format:before {
content: "\f101";
}
.yellow-icon-paragraph:before {
content: "\f101";
}
.yellow-icon-heading:before {
content: "\f102";
}
.yellow-icon-h1:before {
content: "\f103";
}
.yellow-icon-h2:before {
content: "\f104";
}
.yellow-icon-h3:before {
content: "\f105";
}
.yellow-icon-bold:before {
content: "\f106";
}
.yellow-icon-italic:before {
content: "\f0f7";
}
.yellow-icon-strikethrough:before {
content: "\f108";
}
.yellow-icon-quote:before {
content: "\f109";
}
.yellow-icon-code:before {
content: "\f10a";
}
.yellow-icon-pre:before {
content: "\f10a";
}
.yellow-icon-link:before {
content: "\f10b";
}
.yellow-icon-file:before {
content: "\f10c";
}
.yellow-icon-list:before {
content: "\f10d";
}
.yellow-icon-ul:before {
content: "\f10d";
}
.yellow-icon-ol:before {
content: "\f10e";
}
.yellow-icon-tl:before {
content: "\f10f";
}
.yellow-icon-hr:before {
content: "\f110";
}
.yellow-icon-table:before {
content: "\f111";
}
.yellow-icon-emojiawesome:before {
content: "\f112";
}
.yellow-icon-fontawesome:before {
content: "\f113";
}
.yellow-icon-draft:before {
content: "\f114";
}
.yellow-icon-undo:before {
content: "\f115";
}
.yellow-icon-redo:before {
content: "\f116";
}
.yellow-icon-spinner:before {
content: "\f200";
}
.yellow-icon-search:before {
content: "\f201";
}
.yellow-icon-close:before {
content: "\f202";
}
.yellow-icon-help:before {
content: "\f203";
}
.yellow-icon-markdown:before {
content: "\f203";
}
.yellow-icon-logo:before {
content: "\f8ff";
}

692
system/plugins/edit.js Executable file → Normal file
View file

@ -19,6 +19,7 @@ yellow.edit =
paneActionOld: 0, //previous pane action
paneAction: 0, //current pane action
paneStatus: 0, //current pane status
popupId: 0, //visible popup ID
intervalId: 0, //timer interval ID
// Handle initialisation
@ -57,9 +58,10 @@ yellow.edit =
case "edit": this.showPane("yellow-pane-edit", action, status, true); break;
case "delete": this.showPane("yellow-pane-edit", action, status, true); break;
case "user": this.showPane("yellow-pane-user", action, status); break;
case "help": this.hidePane(this.paneId); location.href = this.getText("UserHelpUrl", "yellow"); break;
case "send": this.sendPane(this.paneId, this.paneAction); break;
case "close": this.hidePane(this.paneId); break;
case "toolbar": this.processToolbar(status, args); break;
case "help": this.processHelp(); break;
}
},
@ -79,7 +81,8 @@ yellow.edit =
// Handle mouse clicked
click: function(e)
{
if(this.paneId && !document.getElementById(this.paneId).contains(e.target)) this.hidePane(this.paneId);
if(this.popupId && !document.getElementById(this.popupId).contains(e.target)) this.hidePopup(this.popupId, true);
if(this.paneId && !document.getElementById(this.paneId).contains(e.target)) this.hidePane(this.paneId, true);
},
// Handle keyboard
@ -147,7 +150,7 @@ yellow.edit =
case "yellow-pane-login":
elementDiv.innerHTML =
"<form method=\"post\">"+
"<a href=\"#\" class=\"yellow-close\" data-action=\"close\">x</a>"+
"<a href=\"#\" class=\"yellow-close\" data-action=\"close\"><i class=\"yellow-icon yellow-icon-close\"></i></a>"+
"<h1>"+this.getText("LoginTitle")+"</h1>"+
"<div id=\"yellow-pane-login-fields\">"+
"<input type=\"hidden\" name=\"action\" value=\"login\" />"+
@ -164,7 +167,7 @@ yellow.edit =
case "yellow-pane-signup":
elementDiv.innerHTML =
"<form method=\"post\">"+
"<a href=\"#\" class=\"yellow-close\" data-action=\"close\">x</a>"+
"<a href=\"#\" class=\"yellow-close\" data-action=\"close\"><i class=\"yellow-icon yellow-icon-close\"></i></a>"+
"<h1>"+this.getText("SignupTitle")+"</h1>"+
"<div id=\"yellow-pane-signup-status\" class=\""+paneStatus+"\">"+this.getText(paneAction+"Status", "", paneStatus)+"</div>"+
"<div id=\"yellow-pane-signup-fields\">"+
@ -182,7 +185,7 @@ yellow.edit =
case "yellow-pane-recover":
elementDiv.innerHTML =
"<form method=\"post\">"+
"<a href=\"#\" class=\"yellow-close\" data-action=\"close\">x</a>"+
"<a href=\"#\" class=\"yellow-close\" data-action=\"close\"><i class=\"yellow-icon yellow-icon-close\"></i></a>"+
"<h1>"+this.getText("RecoverTitle")+"</h1>"+
"<div id=\"yellow-pane-recover-status\" class=\""+paneStatus+"\">"+this.getText(paneAction+"Status", "", paneStatus)+"</div>"+
"<div id=\"yellow-pane-recover-fields-first\">"+
@ -213,7 +216,7 @@ yellow.edit =
}
elementDiv.innerHTML =
"<form method=\"post\">"+
"<a href=\"#\" class=\"yellow-close\" data-action=\"close\">x</a>"+
"<a href=\"#\" class=\"yellow-close\" data-action=\"close\"><i class=\"yellow-icon yellow-icon-close\"></i></a>"+
"<h1 id=\"yellow-pane-settings-title\">"+this.getText("SettingsTitle")+"</h1>"+
"<div id=\"yellow-pane-settings-status\" class=\""+paneStatus+"\">"+this.getText(paneAction+"Status", "", paneStatus)+"</div>"+
"<div id=\"yellow-pane-settings-fields\">"+
@ -231,7 +234,7 @@ yellow.edit =
case "yellow-pane-version":
elementDiv.innerHTML =
"<form method=\"post\">"+
"<a href=\"#\" class=\"yellow-close\" data-action=\"close\">x</a>"+
"<a href=\"#\" class=\"yellow-close\" data-action=\"close\"><i class=\"yellow-icon yellow-icon-close\"></i></a>"+
"<h1 id=\"yellow-pane-version-title\">"+yellow.toolbox.encodeHtml(yellow.config.serverVersion)+"</h1>"+
"<div id=\"yellow-pane-version-status\" class=\""+paneStatus+"\">"+this.getText("VersionStatus", "", paneStatus)+"</div>"+
"<div id=\"yellow-pane-version-fields\">"+yellow.page.rawDataOutput+"</div>"+
@ -241,15 +244,35 @@ yellow.edit =
"</form>";
break;
case "yellow-pane-edit":
var rawDataButtons = "";
if(yellow.config.editToolbarButtons && yellow.config.editToolbarButtons!="none")
{
var tokens = yellow.config.editToolbarButtons.split(",");
for(var i=0; i<tokens.length; i++)
{
var token = tokens[i].trim();
if(token!="separator")
{
rawDataButtons += "<li><a href=\"#\" id=\"yellow-toolbar-"+yellow.toolbox.encodeHtml(token)+"\" class=\"yellow-toolbar-btn-icon yellow-toolbar-tooltip\" data-action=\"toolbar\" data-status=\""+yellow.toolbox.encodeHtml(token)+"\" aria-label=\""+this.getText("Toolbar", "", token)+"\"><i class=\"yellow-icon yellow-icon-"+yellow.toolbox.encodeHtml(token)+"\"></i></a></li>";
} else {
rawDataButtons += "<li><a href=\"#\" class=\"yellow-toolbar-btn-separator\"></a></li>";
}
}
if(yellow.config.debug) console.log("yellow.edit.createPane buttons:"+yellow.config.editToolbarButtons);
}
elementDiv.innerHTML =
"<form method=\"post\">"+
"<a href=\"#\" class=\"yellow-close\" data-action=\"close\">x</a>"+
"<h1 id=\"yellow-pane-edit-title\">"+this.getText("Edit")+"</h1>"+
"<textarea id=\"yellow-pane-edit-page\" class=\"yellow-form-control\" name=\"rawdataedit\"></textarea>"+
"<div id=\"yellow-pane-edit-buttons\">"+
"<a href=\"#\" id=\"yellow-pane-edit-send\" class=\"yellow-btn\" data-action=\"send\">"+this.getText("EditButton")+"</a>"+
"<a href=\""+this.getText("MarkdownHelpUrl", "yellow")+"\" target=\"_blank\" id=\"yellow-pane-edit-help\">"+this.getText("MarkdownHelp")+"</a>" +
"<div id=\"yellow-pane-edit-toolbar\">"+
"<h1 id=\"yellow-pane-edit-toolbar-title\" class=\"yellow-toolbar yellow-toolbar-left\">"+this.getText("Edit")+"</h1>"+
"<ul id=\"yellow-pane-edit-toolbar-buttons\" class=\"yellow-toolbar yellow-toolbar-left\">"+rawDataButtons+"</ul>"+
"<ul id=\"yellow-pane-edit-toolbar-main\" class=\"yellow-toolbar yellow-toolbar-right\">"+
"<li><a href=\"#\" id=\"yellow-pane-edit-cancel\" class=\"yellow-toolbar-btn\" data-action=\"close\">"+this.getText("CancelButton")+"</a></li>"+
"<li><a href=\"#\" id=\"yellow-pane-edit-send\" class=\"yellow-toolbar-btn\" data-action=\"send\">"+this.getText("EditButton")+"</a></li>"+
"</ul>"+
"<ul class=\"yellow-toolbar yellow-toolbar-banner\"></ul>"+
"</div>"+
"<textarea id=\"yellow-pane-edit-text\" class=\"yellow-form-control\"></textarea>"+
"<div id=\"yellow-pane-edit-preview\"></div>"+
"</form>";
break;
case "yellow-pane-user":
@ -310,7 +333,7 @@ yellow.edit =
}
break;
case "yellow-pane-version":
if(paneStatus=="none" && yellow.config.userUpdate)
if(paneStatus=="none" && this.isPlugin("update"))
{
document.getElementById("yellow-pane-version-status").innerHTML = this.getText("VersionStatusCheck");
document.getElementById("yellow-pane-version-fields").innerHTML = "";
@ -322,31 +345,42 @@ yellow.edit =
}
break;
case "yellow-pane-edit":
document.getElementById("yellow-pane-edit-text").focus();
if(init)
{
var title;
var string = yellow.page.rawDataEdit;
switch(paneAction)
yellow.toolbox.setVisible(document.getElementById("yellow-pane-edit-text"), true);
yellow.toolbox.setVisible(document.getElementById("yellow-pane-edit-preview"), false);
document.getElementById("yellow-pane-edit-toolbar-title").innerHTML = yellow.toolbox.encodeHtml(yellow.page.title);
document.getElementById("yellow-pane-edit-text").value = paneAction=="create" ? yellow.page.rawDataNew : yellow.page.rawDataEdit;
var matches = document.getElementById("yellow-pane-edit-text").value.match(/^(\xEF\xBB\xBF)?\-\-\-[\r\n]+/);
var position = document.getElementById("yellow-pane-edit-text").value.indexOf("\n", matches ? matches[0].length : 0);
document.getElementById("yellow-pane-edit-text").setSelectionRange(position, position);
if(yellow.config.editToolbarButtons!="none")
{
case "create": title = this.getText("CreateTitle"); string = yellow.page.rawDataNew; break;
case "edit": title = yellow.page.title ? yellow.page.title : this.getText("Edit"); break;
case "delete": title = this.getText("DeleteTitle"); break;
yellow.toolbox.setVisible(document.getElementById("yellow-pane-edit-toolbar-title"), false);
}
if(yellow.config.userRestrictions)
{
yellow.toolbox.setVisible(document.getElementById("yellow-pane-edit-send"), false);
document.getElementById("yellow-pane-edit-text").readOnly = true;
}
document.getElementById("yellow-pane-edit-title").innerHTML = yellow.toolbox.encodeHtml(title);
document.getElementById("yellow-pane-edit-page").value = string;
yellow.toolbox.setCursorPosition(document.getElementById("yellow-pane-edit-page"), 0);
}
var key, className, readOnly;
switch(this.getAction(paneId, paneAction))
if(!yellow.config.userRestrictions)
{
case "create": key = "CreateButton"; className = "yellow-btn yellow-btn-create"; readOnly = false; break;
case "edit": key = "EditButton"; className = "yellow-btn yellow-btn-edit"; readOnly = false; break;
case "delete": key = "DeleteButton"; className = "yellow-btn yellow-btn-delete"; readOnly = false; break;
case "": key = "CancelButton"; className = "yellow-btn yellow-btn-cancel"; readOnly = true; break;
var key, className;
switch(this.getAction(paneId, paneAction))
{
case "create": key = "CreateButton"; className = "yellow-toolbar-btn yellow-toolbar-btn-create"; break;
case "edit": key = "EditButton"; className = "yellow-toolbar-btn yellow-toolbar-btn-edit"; break;
case "delete": key = "DeleteButton"; className = "yellow-toolbar-btn yellow-toolbar-btn-delete"; break;
}
if(document.getElementById("yellow-pane-edit-send").className != className)
{
document.getElementById("yellow-pane-edit-send").innerHTML = this.getText(key);
document.getElementById("yellow-pane-edit-send").className = className;
this.resizePane(paneId, paneAction, paneStatus);
}
}
document.getElementById("yellow-pane-edit-send").innerHTML = this.getText(key);
document.getElementById("yellow-pane-edit-send").className = className;
document.getElementById("yellow-pane-edit-page").readOnly = readOnly;
break;
}
this.bindActions(document.getElementById(paneId));
@ -359,7 +393,7 @@ yellow.edit =
var paneLeft = yellow.toolbox.getOuterLeft(elementBar);
var paneTop = yellow.toolbox.getOuterTop(elementBar) + yellow.toolbox.getOuterHeight(elementBar) + 10;
var paneWidth = yellow.toolbox.getOuterWidth(elementBar);
var paneHeight = yellow.toolbox.getWindowHeight() - paneTop - yellow.toolbox.getOuterHeight(elementBar);
var paneHeight = yellow.toolbox.getWindowHeight() - paneTop - Math.min(yellow.toolbox.getOuterHeight(elementBar) + 10, (yellow.toolbox.getWindowWidth()-yellow.toolbox.getOuterWidth(elementBar))/2);
switch(paneId)
{
case "yellow-pane-login":
@ -376,11 +410,24 @@ yellow.edit =
yellow.toolbox.setOuterTop(document.getElementById("yellow-pane-edit"), paneTop);
yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-edit"), paneHeight);
yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit"), paneWidth);
yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit-page"), yellow.toolbox.getWidth(document.getElementById("yellow-pane-edit")));
var elementWidth = yellow.toolbox.getWidth(document.getElementById("yellow-pane-edit"));
yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit-text"), elementWidth);
yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit-preview"), elementWidth);
var buttonsWidth = 0;
var buttonsWidthMax = yellow.toolbox.getOuterWidth(document.getElementById("yellow-pane-edit-toolbar")) -
yellow.toolbox.getOuterWidth(document.getElementById("yellow-pane-edit-toolbar-main")) - 1;
var element = document.getElementById("yellow-pane-edit-toolbar-buttons").firstChild;
for(; element; element=element.nextSibling)
{
element.removeAttribute("style");
buttonsWidth += yellow.toolbox.getOuterWidth(element);
if(buttonsWidth>buttonsWidthMax) yellow.toolbox.setVisible(element, false);
}
yellow.toolbox.setOuterWidth(document.getElementById("yellow-pane-edit-toolbar-title"), buttonsWidthMax);
var height1 = yellow.toolbox.getHeight(document.getElementById("yellow-pane-edit"));
var height2 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-pane-edit-content"));
var height3 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-pane-edit-page"));
yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-edit-page"), height1 - height2 + height3);
var height2 = yellow.toolbox.getOuterHeight(document.getElementById("yellow-pane-edit-toolbar"));
yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-edit-text"), height1 - height2);
yellow.toolbox.setOuterHeight(document.getElementById("yellow-pane-edit-preview"), height1 - height2);
var elementLink = document.getElementById("yellow-pane-"+paneAction+"-link");
var position = yellow.toolbox.getOuterLeft(elementLink) + yellow.toolbox.getOuterWidth(elementLink)/2;
position -= yellow.toolbox.getOuterLeft(document.getElementById("yellow-pane-edit")) + 1;
@ -417,61 +464,223 @@ yellow.edit =
this.paneId = paneId;
this.paneAction = paneAction;
this.paneStatus = paneStatus;
this.resizePane(paneId, paneAction, paneStatus);
this.updatePane(paneId, paneAction, paneStatus, this.paneActionOld!=this.paneAction);
this.resizePane(paneId, paneAction, paneStatus);
}
} else {
this.hidePane(this.paneId);
this.hidePane(this.paneId, true);
}
},
// Hide pane
hidePane: function(paneId)
hidePane: function(paneId, fadeout)
{
var element = document.getElementById(paneId);
if(yellow.toolbox.isVisible(element))
{
yellow.toolbox.removeClass(document.body, "yellow-body-modal-open");
yellow.toolbox.removeValue("meta[name=viewport]", "content", ", maximum-scale=1, user-scalable=0");
yellow.toolbox.setVisible(element, false);
yellow.toolbox.setVisible(element, false, fadeout);
this.paneId = 0;
this.paneActionOld = this.paneAction;
this.paneAction = 0;
this.paneStatus = 0;
}
this.hidePopup(this.popupId);
},
// Send pane
sendPane: function(paneId, paneAction, paneStatus, paneArgs)
{
if(yellow.config.debug) console.log("yellow.edit.sendPane id:"+paneId);
var args = { "action":paneAction };
if(paneId=="yellow-pane-edit")
{
paneAction = this.getAction(paneId, paneAction);
if(paneAction)
args.action = this.getAction(paneId, paneAction);
args.rawdatasource = yellow.page.rawDataSource;
args.rawdataedit = document.getElementById("yellow-pane-edit-text").value;
args.rawdataendofline = yellow.page.rawDataEndOfLine;
}
if(paneArgs)
{
var tokens = paneArgs.split("/");
for(var i=0; i<tokens.length; i++)
{
var args = {};
args.action = paneAction;
args.rawdatasource = yellow.page.rawDataSource;
args.rawdataedit = document.getElementById("yellow-pane-edit-page").value;
args.rawdataendofline = yellow.page.rawDataEndOfLine;
yellow.toolbox.submitForm(args);
} else {
this.hidePane(paneId);
var pair = tokens[i].split(/[:=]/);
if(!pair[0] || !pair[1]) continue;
args[pair[0]] = pair[1];
}
}
yellow.toolbox.submitForm(args);
},
// Process help
processHelp: function()
{
this.hidePane(this.paneId);
window.open(this.getText("HelpUrl", "yellow"), "_self");
},
// Process toolbar
processToolbar: function(status, args)
{
if(yellow.config.debug) console.log("yellow.edit.processToolbar status:"+status);
var elementText = document.getElementById("yellow-pane-edit-text");
var elementPreview = document.getElementById("yellow-pane-edit-preview");
if(!yellow.config.userRestrictions && this.paneAction!="delete" && !yellow.toolbox.isVisible(elementPreview))
{
switch(status)
{
case "h1": yellow.editor.setMarkdown(elementText, "# ", "insert-multiline-block", true); break;
case "h2": yellow.editor.setMarkdown(elementText, "## ", "insert-multiline-block", true); break;
case "h3": yellow.editor.setMarkdown(elementText, "### ", "insert-multiline-block", true); break;
case "paragraph": yellow.editor.setMarkdown(elementText, "", "remove-multiline-block");
yellow.editor.setMarkdown(elementText, "", "remove-fenced-block"); break;
case "quote": yellow.editor.setMarkdown(elementText, "> ", "insert-multiline-block", true); break;
case "pre": yellow.editor.setMarkdown(elementText, "```\n", "insert-fenced-block", true); break;
case "bold": yellow.editor.setMarkdown(elementText, "**", "insert-inline", true); break;
case "italic": yellow.editor.setMarkdown(elementText, "*", "insert-inline", true); break;
case "strikethrough": yellow.editor.setMarkdown(elementText, "~", "insert-inline", true); break;
case "code": yellow.editor.setMarkdown(elementText, "`", "insert-autodetect", true); break;
case "ul": yellow.editor.setMarkdown(elementText, "* ", "insert-multiline-block", true); break;
case "ol": yellow.editor.setMarkdown(elementText, "1. ", "insert-multiline-block", true); break;
case "tl": yellow.editor.setMarkdown(elementText, "- [ ] ", "insert-multiline-block", true); break;
case "link": yellow.editor.setMarkdown(elementText, "[link](url)", "insert", false, yellow.editor.getMarkdownLink); break;
case "file": yellow.editor.setMarkdown(elementText, "[image picture.jpg]", "insert"); break;
case "text": yellow.editor.setMarkdown(elementText, args, "insert"); break;
case "draft": yellow.editor.setMetaData(elementText, "status", "draft", true); break;
case "undo": yellow.editor.undo(); break;
case "redo": yellow.editor.redo(); break;
}
}
if(status=="preview") yellow.editor.showPreview(elementText, elementPreview);
if(status=="help") window.open(this.getText("HelpUrl", "yellow"), "_blank");
if(status=="markdown") window.open(this.getText("MarkdownUrl", "yellow"), "_blank");
if(status=="format" || status=="heading" || status=="list" || status=="emojiawesome" || status=="fontawesome")
{
this.showPopup("yellow-popup-"+status, status);
} else {
var args = {"action":paneAction};
if(paneArgs)
this.hidePopup(this.popupId);
}
},
// Update toolbar
updateToolbar: function(status)
{
if(status)
{
yellow.toolbox.addClass(document.getElementById("yellow-toolbar-"+status), "yellow-toolbar-selected");
} else {
var elements = document.getElementsByClassName("yellow-toolbar-selected");
for(var i=0, l=elements.length; i<l; i++)
{
var tokens = paneArgs.split("/");
for(var i=0; i<tokens.length; i++)
{
var pair = tokens[i].split(/[:=]/);
if(!pair[0] || !pair[1]) continue;
args[pair[0]] = pair[1];
}
yellow.toolbox.removeClass(elements[i], "yellow-toolbar-selected");
}
yellow.toolbox.submitForm(args);
}
},
// Create popup
createPopup: function(popupId)
{
if(yellow.config.debug) console.log("yellow.edit.createPopup id:"+popupId);
var elementPopup = document.createElement("div");
elementPopup.className = "yellow-popup";
elementPopup.setAttribute("id", popupId);
elementPopup.style.display = "none";
var elementDiv = document.createElement("div");
elementDiv.setAttribute("id", popupId+"-content");
switch(popupId)
{
case "yellow-popup-format":
elementDiv.innerHTML =
"<ul class=\"yellow-dropdown yellow-dropdown-menu\">"+
"<li><a href=\"#\" id=\"yellow-popup-format-h1\" data-action=\"toolbar\" data-status=\"h1\">"+this.getText("ToolbarH1")+"</a></li>"+
"<li><a href=\"#\" id=\"yellow-popup-format-h2\" data-action=\"toolbar\" data-status=\"h2\">"+this.getText("ToolbarH2")+"</a></li>"+
"<li><a href=\"#\" id=\"yellow-popup-format-h3\" data-action=\"toolbar\" data-status=\"h3\">"+this.getText("ToolbarH3")+"</a></li>"+
"<li><a href=\"#\" id=\"yellow-popup-format-paragraph\" data-action=\"toolbar\" data-status=\"paragraph\">"+this.getText("ToolbarParagraph")+"</a></li>"+
"<li><a href=\"#\" id=\"yellow-popup-format-pre\" data-action=\"toolbar\" data-status=\"pre\">"+this.getText("ToolbarPre")+"</a></li>"+
"<li><a href=\"#\" id=\"yellow-popup-format-quote\" data-action=\"toolbar\" data-status=\"quote\">"+this.getText("ToolbarQuote")+"</a></li>"+
"</ul>";
break;
case "yellow-popup-heading":
elementDiv.innerHTML =
"<ul class=\"yellow-dropdown yellow-dropdown-menu\">"+
"<li><a href=\"#\" id=\"yellow-popup-heading-h1\" data-action=\"toolbar\" data-status=\"h1\">"+this.getText("ToolbarH1")+"</a></li>"+
"<li><a href=\"#\" id=\"yellow-popup-heading-h2\" data-action=\"toolbar\" data-status=\"h2\">"+this.getText("ToolbarH2")+"</a></li>"+
"<li><a href=\"#\" id=\"yellow-popup-heading-h3\" data-action=\"toolbar\" data-status=\"h3\">"+this.getText("ToolbarH3")+"</a></li>"+
"</ul>";
break;
case "yellow-popup-list":
elementDiv.innerHTML =
"<ul class=\"yellow-dropdown yellow-dropdown-menu\">"+
"<li><a href=\"#\" id=\"yellow-popup-list-ul\" data-action=\"toolbar\" data-status=\"ul\">"+this.getText("ToolbarUl")+"</a></li>"+
"<li><a href=\"#\" id=\"yellow-popup-list-ol\" data-action=\"toolbar\" data-status=\"ol\">"+this.getText("ToolbarOl")+"</a></li>"+
"</ul>";
break;
case "yellow-popup-emojiawesome":
var rawDataEmojis = "";
if(yellow.config.emojiawesomeToolbarButtons && yellow.config.emojiawesomeToolbarButtons!="none")
{
var tokens = yellow.config.emojiawesomeToolbarButtons.split(" ");
for(var i=0; i<tokens.length; i++)
{
var token = tokens[i].replace(/[\:]/g,"");
var className = token.replace("+1", "plus1").replace("-1", "minus1").replace(/_/g, "-");
rawDataEmojis += "<li><a href=\"#\" id=\"yellow-popup-list-"+yellow.toolbox.encodeHtml(token)+"\" data-action=\"toolbar\" data-status=\"text\" data-args=\":"+yellow.toolbox.encodeHtml(token)+":\"><i class=\"ea ea-"+yellow.toolbox.encodeHtml(className)+"\"></i></a></li>";
}
}
elementDiv.innerHTML = "<ul class=\"yellow-dropdown yellow-dropdown-menu\">"+rawDataEmojis+"</ul>";
break;
case "yellow-popup-fontawesome":
var rawDataIcons = "";
if(yellow.config.fontawesomeToolbarButtons && yellow.config.fontawesomeToolbarButtons!="none")
{
var tokens = yellow.config.fontawesomeToolbarButtons.split(" ");
for(var i=0; i<tokens.length; i++)
{
var token = tokens[i].replace(/[\:]/g,"");
rawDataIcons += "<li><a href=\"#\" id=\"yellow-popup-list-"+yellow.toolbox.encodeHtml(token)+"\" data-action=\"toolbar\" data-status=\"text\" data-args=\":"+yellow.toolbox.encodeHtml(token)+":\"><i class=\"fa "+yellow.toolbox.encodeHtml(token)+"\"></i></a></li>";
}
}
elementDiv.innerHTML = "<ul class=\"yellow-dropdown yellow-dropdown-menu\">"+rawDataIcons+"</ul>";
break;
}
elementPopup.appendChild(elementDiv);
yellow.toolbox.insertAfter(elementPopup, document.getElementsByTagName("body")[0].firstChild);
this.bindActions(elementPopup);
},
// Show or hide popup
showPopup: function(popupId, status)
{
if(this.popupId!=popupId)
{
this.hidePopup(this.popupId);
if(!document.getElementById(popupId)) this.createPopup(popupId);
var element = document.getElementById(popupId);
if(yellow.config.debug) console.log("yellow.edit.showPopup id:"+popupId);
yellow.toolbox.setVisible(element, true);
this.popupId = popupId;
this.updateToolbar(status);
var elementParent = document.getElementById("yellow-toolbar-"+status);
var popupLeft = yellow.toolbox.getOuterLeft(elementParent);
var popupTop = yellow.toolbox.getOuterTop(elementParent) + yellow.toolbox.getOuterHeight(elementParent) - 1;
yellow.toolbox.setOuterLeft(document.getElementById(popupId), popupLeft);
yellow.toolbox.setOuterTop(document.getElementById(popupId), popupTop);
} else {
this.hidePopup(this.popupId, true);
}
},
// Hide popup
hidePopup: function(popupId, fadeout)
{
var element = document.getElementById(popupId);
if(yellow.toolbox.isVisible(element))
{
yellow.toolbox.setVisible(element, false, fadeout);
this.popupId = 0;
this.updateToolbar(0);
}
},
@ -482,6 +691,7 @@ yellow.edit =
for(var i=0, l=elements.length; i<l; i++)
{
if(elements[i].getAttribute("data-action")) elements[i].onclick = yellow.onClickAction;
if(elements[i].getAttribute("data-action")=="toolbar") elements[i].onmousedown = function(e) { e.preventDefault() };
}
},
@ -494,11 +704,10 @@ yellow.edit =
switch(paneAction)
{
case "create": action = "create"; break;
case "edit": action = document.getElementById("yellow-pane-edit-page").value ? "edit" : "delete"; break;
case "edit": action = document.getElementById("yellow-pane-edit-text").value.length!=0 ? "edit" : "delete"; break;
case "delete": action = "delete"; break;
}
if(yellow.page.statusCode==434 && paneAction!="delete") action = "create";
if(yellow.config.userRestrictions) action = "";
}
return action;
},
@ -507,7 +716,7 @@ yellow.edit =
getRequest: function(key, prefix)
{
if(!prefix) prefix = "request";
key = prefix + key.charAt(0).toUpperCase() + key.slice(1);
key = prefix + yellow.toolbox.toUpperFirst(key);
return (key in yellow.page) ? yellow.page[key] : "";
},
@ -516,8 +725,305 @@ yellow.edit =
{
if(!prefix) prefix = "edit";
if(!postfix) postfix = "";
key = prefix + key.charAt(0).toUpperCase() + key.slice(1) + postfix.charAt(0).toUpperCase() + postfix.slice(1);
key = prefix + yellow.toolbox.toUpperFirst(key) + yellow.toolbox.toUpperFirst(postfix);
return (key in yellow.text) ? yellow.text[key] : "["+key+"]";
},
// Check if plugin exists
isPlugin: function(name)
{
return name in yellow.config.serverPlugins;
}
};
yellow.editor =
{
// Set Markdown formatting
setMarkdown: function(element, prefix, type, toggle, callback)
{
var information = this.getMarkdownInformation(element, prefix, type);
var selectionStart = (information.type.indexOf("block")!=-1) ? information.top : information.start;
var selectionEnd = (information.type.indexOf("block")!=-1) ? information.bottom : information.end;
if(information.found && toggle) information.type = information.type.replace("insert", "remove");
if(information.type=="remove-fenced-block" || information.type=="remove-inline")
{
selectionStart -= information.prefix.length; selectionEnd += information.prefix.length;
}
var text = information.text;
var textSelectionBefore = text.substring(0, selectionStart);
var textSelection = text.substring(selectionStart, selectionEnd);
var textSelectionAfter = text.substring(selectionEnd, text.length);
var textSelectionNew, selectionStartNew, selectionEndNew;
switch(information.type)
{
case "insert-multiline-block":
textSelectionNew = this.getMarkdownMultilineBlock(textSelection, information);
selectionStartNew = information.start + this.getMarkdownDifference(textSelection, textSelectionNew, true);
selectionEndNew = information.end + this.getMarkdownDifference(textSelection, textSelectionNew);
if(information.start==information.top && information.start!=information.end) selectionStartNew = information.top;
if(information.end==information.top && information.start!=information.end) selectionEndNew = information.top;
break;
case "remove-multiline-block":
textSelectionNew = this.getMarkdownMultilineBlock(textSelection, information);
selectionStartNew = information.start + this.getMarkdownDifference(textSelection, textSelectionNew, true);
selectionEndNew = information.end + this.getMarkdownDifference(textSelection, textSelectionNew);
if(selectionStartNew<=information.top) selectionStartNew = information.top;
if(selectionEndNew<=information.top) selectionEndNew = information.top;
break;
case "insert-fenced-block":
textSelectionNew = this.getMarkdownFencedBlock(textSelection, information);
selectionStartNew = information.start + information.prefix.length;
selectionEndNew = information.end + this.getMarkdownDifference(textSelection, textSelectionNew) - information.prefix.length;
break;
case "remove-fenced-block":
textSelectionNew = this.getMarkdownFencedBlock(textSelection, information);
selectionStartNew = information.start - information.prefix.length;
selectionEndNew = information.end + this.getMarkdownDifference(textSelection, textSelectionNew) + information.prefix.length;
break;
case "insert-inline":
textSelectionNew = information.prefix + textSelection + information.prefix;
selectionStartNew = information.start + information.prefix.length;
selectionEndNew = information.end + information.prefix.length;
break;
case "remove-inline":
textSelectionNew = text.substring(information.start, information.end);
selectionStartNew = information.start - information.prefix.length;
selectionEndNew = information.end - information.prefix.length;
break;
case "insert":
textSelectionNew = callback ? callback(textSelection, information) : information.prefix;
selectionStartNew = information.start + textSelectionNew.length;
selectionEndNew = selectionStartNew;
}
if(textSelection!=textSelectionNew || selectionStart!=selectionStartNew || selectionEnd!=selectionEndNew)
{
element.focus();
element.setSelectionRange(selectionStart, selectionEnd);
document.execCommand("insertText", false, textSelectionNew);
element.value = textSelectionBefore + textSelectionNew + textSelectionAfter;
element.setSelectionRange(selectionStartNew, selectionEndNew);
}
if(yellow.config.debug) console.log("yellow.editor.setMarkdown type:"+information.type);
},
// Return Markdown formatting information
getMarkdownInformation: function(element, prefix, type)
{
var text = element.value;
var start = element.selectionStart;
var end = element.selectionEnd;
var top = start, bottom = end;
while(text.charAt(top-1)!="\n" && top>0) top--;
if(bottom==top && bottom<text.length) bottom++;
while(text.charAt(bottom-1)!="\n" && bottom<text.length) bottom++;
if(type=="insert-autodetect")
{
if(text.substring(start, end).indexOf("\n")!=-1)
{
type = "insert-fenced-block"; prefix = "```\n";
} else {
type = "insert-inline"; prefix = "`";
}
}
var found = false;
if(type.indexOf("multiline-block")!=-1)
{
if(text.substring(top, top+prefix.length)==prefix) found = true;
} else if(type.indexOf("fenced-block")!=-1) {
if(text.substring(top-prefix.length, top)==prefix && text.substring(bottom, bottom+prefix.length)==prefix)
{
found = true;
}
} else {
if(text.substring(start-prefix.length, start)==prefix && text.substring(end, end+prefix.length)==prefix)
{
if(prefix=="*")
{
var lettersBefore = 0, lettersAfter = 0;
for(var index=start-1; text.charAt(index)=="*"; index--) lettersBefore++;
for(var index=end; text.charAt(index)=="*"; index++) lettersAfter++;
found = lettersBefore!=2 && lettersAfter!=2;
} else {
found = true;
}
}
}
return { "text":text, "prefix":prefix, "type":type, "start":start, "end":end, "top":top, "bottom":bottom, "found":found };
},
// Return Markdown length difference
getMarkdownDifference: function(textSelection, textSelectionNew, firstTextLine)
{
var textSelectionLength, textSelectionLengthNew;
if(firstTextLine)
{
var position = textSelection.indexOf("\n");
var positionNew = textSelectionNew.indexOf("\n");
textSelectionLength = position!=-1 ? position+1 : textSelection.length+1;
textSelectionLengthNew = positionNew!=-1 ? positionNew+1 : textSelectionNew.length+1;
} else {
var position = textSelection.indexOf("\n");
var positionNew = textSelectionNew.indexOf("\n");
textSelectionLength = position!=-1 ? textSelection.length : textSelection.length+1;
textSelectionLengthNew = positionNew!=-1 ? textSelectionNew.length : textSelectionNew.length+1;
}
return textSelectionLengthNew - textSelectionLength;
},
// Return Markdown for multiline block
getMarkdownMultilineBlock: function(textSelection, information)
{
var textSelectionNew = "";
var lines = yellow.toolbox.getTextLines(textSelection);
for(var i=0; i<lines.length; i++)
{
var matches = lines[i].match(/^(\s*[\#\*\-\>\s]+)?(\s+\[.\]|\s*\d+\.)?[ \t]+/);
if(matches)
{
textSelectionNew += lines[i].substring(matches[0].length);
} else {
textSelectionNew += lines[i];
}
}
textSelection = textSelectionNew;
if(information.type.indexOf("remove")==-1)
{
textSelectionNew = "";
var linePrefix = information.prefix;
lines = yellow.toolbox.getTextLines(textSelection.length!=0 ? textSelection : "\n");
for(var i=0; i<lines.length; i++)
{
textSelectionNew += linePrefix+lines[i];
if(information.prefix=="1. ")
{
var matches = linePrefix.match(/^(\d+)\.\s/);
if(matches) linePrefix = (parseInt(matches[1])+1)+". ";
}
}
textSelection = textSelectionNew;
}
return textSelection;
},
// Return Markdown for fenced block
getMarkdownFencedBlock: function(textSelection, information)
{
var textSelectionNew = "";
var lines = yellow.toolbox.getTextLines(textSelection);
for(var i=0; i<lines.length; i++)
{
var matches = lines[i].match(/^```/);
if(!matches) textSelectionNew += lines[i];
}
textSelection = textSelectionNew;
if(information.type.indexOf("remove")==-1)
{
if(textSelection.length==0) textSelection = "\n";
textSelection = information.prefix + textSelection + information.prefix;
}
return textSelection;
},
// Return Markdown for link
getMarkdownLink: function(textSelection, information)
{
return textSelection.length!=0 ? information.prefix.replace("link", textSelection) : information.prefix;
},
// Set meta data
setMetaData: function(element, key, value, toggle)
{
var information = this.getMetaDataInformation(element, key);
if(information.bottom!=0)
{
var selectionStart = information.found ? information.start : information.bottom;
var selectionEnd = information.found ? information.end : information.bottom;
var text = information.text;
var textSelectionBefore = text.substring(0, selectionStart);
var textSelection = text.substring(selectionStart, selectionEnd);
var textSelectionAfter = text.substring(selectionEnd, text.length);
var textSelectionNew = yellow.toolbox.toUpperFirst(key)+": "+value+"\n";
if(information.found && information.value==value && toggle) textSelectionNew = "";
var selectionStartNew = selectionStart;
var selectionEndNew = selectionStart + textSelectionNew.trim().length;
element.focus();
element.setSelectionRange(selectionStart, selectionEnd);
document.execCommand("insertText", false, textSelectionNew);
element.value = textSelectionBefore + textSelectionNew + textSelectionAfter;
element.setSelectionRange(selectionStartNew, selectionEndNew);
element.scrollTop = 0;
if(yellow.config.debug) console.log("yellow.editor.setMetaData key:"+key);
}
},
// Return meta data information
getMetaDataInformation: function(element, key)
{
var text = element.value;
var value = "";
var start = 0, end = 0, top = 0, bottom = 0;
var found = false;
var parts = text.match(/^(\xEF\xBB\xBF)?(\-\-\-[\r\n]+)([\s\S]+?)\-\-\-[\r\n]+/);
if(parts)
{
key = yellow.toolbox.toLowerFirst(key);
start = end = top = ((parts[1] ? parts[1] : "")+parts[2]).length;
bottom = ((parts[1] ? parts[1] : "")+parts[2]+parts[3]).length;
var lines = yellow.toolbox.getTextLines(parts[3]);
for(var i=0; i<lines.length; i++)
{
var matches = lines[i].match(/^\s*(.*?)\s*:\s*(.*?)\s*$/);
if(matches && yellow.toolbox.toLowerFirst(matches[1])==key && matches[2].length!=0)
{
value = matches[2];
end = start + lines[i].length;
found = true;
break;
}
start = end = start + lines[i].length;
}
}
return { "text":text, "value":value, "start":start, "end":end, "top":top, "bottom":bottom, "found":found };
},
// Show or hide preview
showPreview: function(elementText, elementPreview)
{
if(!yellow.toolbox.isVisible(elementPreview))
{
var formData = new FormData();
formData.append("action", "preview");
formData.append("rawdataedit", elementText.value);
formData.append("rawdataendofline", yellow.page.rawDataEndOfLine);
var request = new XMLHttpRequest();
request.open("POST", window.location.pathname, true);
request.onload = function() { if(this.status==200) yellow.editor.updatePreview(elementText, elementPreview, this.responseText); };
request.send(formData);
} else {
yellow.toolbox.setVisible(elementText, true);
yellow.toolbox.setVisible(elementPreview, false);
elementText.focus();
}
},
// Update preview
updatePreview: function(elementText, elementPreview, responseText)
{
yellow.toolbox.setVisible(elementText, false);
yellow.toolbox.setVisible(elementPreview, true);
elementPreview.innerHTML = responseText;
},
// Undo changes
undo: function()
{
document.execCommand("undo");
},
// Redo changes
redo: function()
{
document.execCommand("redo");
}
};
@ -683,23 +1189,28 @@ yellow.toolbox =
return { "width":width, "height":height };
},
// Set input cursor position
setCursorPosition: function(element, pos)
{
element.focus();
element.setSelectionRange(pos, pos);
},
// Get input cursor position
getCursorPosition: function(element)
{
return element.selectionStart;
},
// Set element visibility
setVisible: function(element, show)
setVisible: function(element, show, fadeout)
{
element.style.display = show ? "block" : "none";
if(fadeout && !show)
{
var opacity = 1;
function renderFrame()
{
opacity -= .1;
if(opacity<=0)
{
element.style.opacity = "initial";
element.style.display = "none";
} else {
element.style.opacity = opacity;
requestAnimationFrame(renderFrame);
}
}
renderFrame();
} else {
element.style.display = show ? "block" : "none";
}
},
// Check if element exists and is visible
@ -708,6 +1219,27 @@ yellow.toolbox =
return element && element.style.display!="none";
},
// Convert first letter to lowercase
toLowerFirst: function(string)
{
return string.charAt(0).toLowerCase()+string.slice(1);
},
// Convert first letter to uppercase
toUpperFirst: function(string)
{
return string.charAt(0).toUpperCase()+string.slice(1);
},
// Return lines from text string, including newline
getTextLines: function(string)
{
var lines = string.split("\n");
for(var i=0; i<lines.length; i++) lines[i] = lines[i]+"\n";
if(string.length==0 || string.charAt(string.length-1)=="\n") lines.pop();
return lines;
},
// Encode HTML special characters
encodeHtml: function(string)
{

80
system/plugins/edit.php Executable file → Normal file
View file

@ -5,7 +5,7 @@
class YellowEdit
{
const VERSION = "0.7.9";
const VERSION = "0.7.10";
var $yellow; //access to API
var $response; //web response
var $users; //user accounts
@ -19,6 +19,7 @@ class YellowEdit
$this->users = new YellowUsers($yellow);
$this->merge = new YellowMerge($yellow);
$this->yellow->config->setDefault("editLocation", "/edit/");
$this->yellow->config->setDefault("editToolbarButtons", "auto");
$this->yellow->config->setDefault("editEndOfLine", "auto");
$this->yellow->config->setDefault("editUserFile", "user.ini");
$this->yellow->config->setDefault("editUserPasswordMinLength", "4");
@ -205,6 +206,7 @@ class YellowEdit
case "create": $statusCode = $this->processRequestCreate($scheme, $address, $base, $location, $fileName); break;
case "edit": $statusCode = $this->processRequestEdit($scheme, $address, $base, $location, $fileName); break;
case "delete": $statusCode = $this->processRequestDelete($scheme, $address, $base, $location, $fileName); break;
case "preview": $statusCode = $this->processRequestPreview($scheme, $address, $base, $location, $fileName); break;
}
} else {
$this->yellow->lookup->requestHandler = "core";
@ -695,6 +697,20 @@ class YellowEdit
}
return $statusCode;
}
// Process request to show preview
function processRequestPreview($scheme, $address, $base, $location, $fileName)
{
$page = $this->response->getPagePreview($scheme, $address, $base, $location, $fileName,
$_REQUEST["rawdataedit"], $_REQUEST["rawdataendofline"]);
$statusCode = $this->yellow->sendData(200, $page->outputData, "", false);
if(defined("DEBUG") && DEBUG>=1)
{
$parser = $page->get("parser");
echo "YellowEdit::processRequestPreview parser:$parser<br/>\n";
}
return $statusCode;
}
// Check request
function checkRequest($location)
@ -928,7 +944,27 @@ class YellowResponse
}
return $page;
}
// Return preview page
function getPagePreview($scheme, $address, $base, $location, $fileName, $rawData, $endOfLine)
{
$page = new YellowPage($this->yellow);
$page->setRequestInformation($scheme, $address, $base, $location, $fileName);
$page->parseData($this->normaliseLines($rawData, $endOfLine), false, 200);
$this->yellow->text->setLanguage($page->get("language"));
$page->set("pageClass", "page-preview");
$page->set("pageClass", $page->get("pageClass")." template-".$page->get("template"));
$output = "<div class=\"".$page->getHtml("pageClass")."\"><div class=\"content\">";
if($this->yellow->config->get("editToolbarButtons")!="none")
{
$output .= "<h1>".$page->getHtml("titleContent")."</h1>\n";
}
$output .= $page->getContent();
$output .= "</div></div>";
$page->setOutput($output);
return $page;
}
// Return page data including login information
function getPageData()
{
@ -967,16 +1003,23 @@ class YellowResponse
$data["userHome"] = $this->plugin->users->getHome($this->userEmail);
$data["userRestrictions"] = intval($this->isUserRestrictions());
$data["userWebmaster"] = intval($this->isUserWebmaster());
$data["userUpdate"] = intval($this->yellow->plugins->isExisting("update"));
$data["serverScheme"] = $this->yellow->config->get("serverScheme");
$data["serverAddress"] = $this->yellow->config->get("serverAddress");
$data["serverBase"] = $this->yellow->config->get("serverBase");
$data["serverVersion"] = "Datenstrom Yellow ".YellowCore::VERSION;
$data["serverPlugins"] = array();
foreach($this->yellow->plugins->plugins as $key=>$value)
{
$data["serverPlugins"][$key] = $value["plugin"];
}
$data["serverLanguages"] = array();
foreach($this->yellow->text->getLanguages() as $language)
{
$data["serverLanguages"][$language] = $this->yellow->text->getTextHtml("languageDescription", $language);
}
$data["serverScheme"] = $this->yellow->config->get("serverScheme");
$data["serverAddress"] = $this->yellow->config->get("serverAddress");
$data["serverBase"] = $this->yellow->config->get("serverBase");
$data["serverVersion"] = "Datenstrom Yellow ".YellowCore::VERSION;
$data["editToolbarButtons"] = $this->getToolbarButtons("edit");
$data["emojiawesomeToolbarButtons"] = $this->getToolbarButtons("emojiawesome");
$data["fontawesomeToolbarButtons"] = $this->getToolbarButtons("fontawesome");
} else {
$data["editLoginEmail"] = $this->yellow->config->get("editLoginEmail");
$data["editLoginPassword"] = $this->yellow->config->get("editLoginPassword");
@ -992,7 +1035,7 @@ class YellowResponse
$data = array();
foreach($_REQUEST as $key=>$value)
{
if($key=="login" || $key=="password") continue;
if($key=="login" || $key=="password" || substru($key, 0, 7)=="rawdata") continue;
$data["request".ucfirst($key)] = trim($value);
}
return $data;
@ -1007,6 +1050,27 @@ class YellowResponse
return array_merge($textLanguage, $textEdit, $textYellow);
}
// Return toolbar buttons
function getToolbarButtons($name)
{
if($name=="edit")
{
$toolbarButtons = $this->yellow->config->get("editToolbarButtons");
if($toolbarButtons=="auto")
{
$toolbarButtons = "";
if($this->yellow->plugins->isExisting("markdown")) $toolbarButtons = "preview, format, bold, italic, code, list, link, file";
if($this->yellow->plugins->isExisting("emojiawesome")) $toolbarButtons .= ", emojiawesome";
if($this->yellow->plugins->isExisting("fontawesome")) $toolbarButtons .= ", fontawesome";
if($this->yellow->plugins->isExisting("draft")) $toolbarButtons .= ", draft";
if($this->yellow->plugins->isExisting("markdown")) $toolbarButtons .= ", markdown";
}
} else {
$toolbarButtons = $this->yellow->config->get("{$name}ToolbarButtons");
}
return $toolbarButtons;
}
// Return end of line format
function getEndOfLine($rawData = "")
{

BIN
system/plugins/edit.woff Executable file

Binary file not shown.

View file

@ -3,7 +3,7 @@
Language: de
LanguageDescription: Deutsch
LanguageTranslator: David Fehrmann
LanguageVersion: 0.7.4
LanguageVersion: 0.7.5
BlogBy: von
BlogFilter: Blog:
@ -101,9 +101,32 @@ EditDeleteButton: Löschen
EditEdit: Seite bearbeiten
EditCreate: +
EditDelete: -
EditCreateTitle: Seite erzeugen
EditDeleteTitle: Seite löschen
EditMarkdownHelp: Markdown
EditToolbarPreview: Vorschau
EditToolbarFormat: Format
EditToolbarHeading: Überschrift
EditToolbarH1: Überschrift 1
EditToolbarH2: Überschrift 2
EditToolbarH3: Überschrift 3
EditToolbarParagraph: Normaler Text
EditToolbarPre: Quellcode
EditToolbarQuote: Zitat
EditToolbarBold: Fettschrift
EditToolbarItalic: Kursiv
EditToolbarStrikethrough: Durchgestrichen
EditToolbarCode: Code
EditToolbarList: Liste
EditToolbarUl: • Unsortierte Liste
EditToolbarOl: 1. Sortierte Liste
EditToolbarTl: ✓ Aufgabenliste
EditToolbarLink: Link
EditToolbarFile: Datei
EditToolbarEmojiawesome: Emoji
EditToolbarFontawesome: Symbol
EditToolbarDraft: Entwurf
EditToolbarUndo: Rückgängig
EditToolbarRedo: Wiederholen
EditToolbarMarkdown: Markdown
EditToolbarHelp: Hilfe
EditUserHelp: Hilfe
EditUserLogout: Abmelden
PagePrevious: ← Zurück: @title
@ -123,5 +146,5 @@ WikiTag: Tags:
WikiSpecialPages: Alle Seiten
WikiSpecialChanges: Letzte Änderungen
YellowUrl: https://datenstrom.se/de/yellow/
YellowUserHelpUrl: https://developers.datenstrom.se/de/help/
YellowMarkdownHelpUrl: https://developers.datenstrom.se/de/help/markdown-cheat-sheet
YellowHelpUrl: https://developers.datenstrom.se/de/help/
YellowMarkdownUrl: https://developers.datenstrom.se/de/help/markdown-cheat-sheet

View file

@ -3,7 +3,7 @@
Language: en
LanguageDescription: English
LanguageTranslator: Mark Seuffert
LanguageVersion: 0.7.4
LanguageVersion: 0.7.5
BlogBy: by
BlogFilter: Blog:
@ -101,9 +101,32 @@ EditDeleteButton: Delete
EditEdit: Edit page
EditCreate: +
EditDelete: -
EditCreateTitle: Create page
EditDeleteTitle: Delete page
EditMarkdownHelp: Markdown
EditToolbarPreview: Preview
EditToolbarFormat: Format
EditToolbarHeading: Heading
EditToolbarH1: Heading 1
EditToolbarH2: Heading 2
EditToolbarH3: Heading 3
EditToolbarParagraph: Normal text
EditToolbarPre: Source code
EditToolbarQuote: Quote
EditToolbarBold: Bold
EditToolbarItalic: Italic
EditToolbarStrikethrough: Strikethrough
EditToolbarCode: Code
EditToolbarList: List
EditToolbarUl: • Unordered list
EditToolbarOl: 1. Ordered list
EditToolbarTl: ✓ Task list
EditToolbarLink: Link
EditToolbarFile: File
EditToolbarEmojiawesome: Emoji
EditToolbarFontawesome: Icon
EditToolbarDraft: Draft
EditToolbarUndo: Undo
EditToolbarRedo: Redo
EditToolbarMarkdown: Markdown
EditToolbarHelp: Help
EditUserHelp: Help
EditUserLogout: Logout
PagePrevious: ← Previous: @title
@ -123,5 +146,5 @@ WikiTag: Tags:
WikiSpecialPages: All pages
WikiSpecialChanges: Recent changes
YellowUrl: https://datenstrom.se/yellow/
YellowUserHelpUrl: https://developers.datenstrom.se/help/
YellowMarkdownHelpUrl: https://developers.datenstrom.se/help/markdown-cheat-sheet
YellowHelpUrl: https://developers.datenstrom.se/help/
YellowMarkdownUrl: https://developers.datenstrom.se/help/markdown-cheat-sheet

View file

@ -3,7 +3,7 @@
Language: fr
LanguageDescription: Français
LanguageTranslator: Juh Nibreh
LanguageVersion: 0.7.4
LanguageVersion: 0.7.5
BlogBy: par
BlogFilter: Blog:
@ -101,9 +101,32 @@ EditDeleteButton: Supprimer
EditEdit: Éditer page
EditCreate: +
EditDelete: -
EditCreateTitle: Créer page
EditDeleteTitle: Supprimer page
EditMarkdownHelp: Markdown
EditToolbarPreview: Aperçu
EditToolbarFormat: Format
EditToolbarHeading: Titre
EditToolbarH1: Titre 1
EditToolbarH2: Titre 2
EditToolbarH3: Titre 3
EditToolbarParagraph: Texte normal
EditToolbarPre: Code source
EditToolbarQuote: Citation
EditToolbarBold: Gras
EditToolbarItalic: Italique
EditToolbarStrikethrough: Barré
EditToolbarCode: Code
EditToolbarList: Liste
EditToolbarUl: • Liste non ordonnée
EditToolbarOl: 1. Liste commandée
EditToolbarTl: ✓ Liste des tâches
EditToolbarLink: Lien
EditToolbarFile: Fichier
EditToolbarEmojiawesome: Emoji
EditToolbarFontawesome: Icone
EditToolbarDraft: Brouillon
EditToolbarUndo: Annuler
EditToolbarRedo: Refaire
EditToolbarMarkdown: Markdown
EditToolbarHelp: Aide
EditUserHelp: Aide
EditUserLogout: Déconnexion
PagePrevious: ← Précédent: @title
@ -123,5 +146,5 @@ WikiTag: Tags:
WikiSpecialPages: Toutes les pages
WikiSpecialChanges: Changements récents
YellowUrl: https://datenstrom.se/fr/yellow/
YellowUserHelpUrl: https://developers.datenstrom.se/fr/help/
YellowMarkdownHelpUrl: https://developers.datenstrom.se/fr/help/markdown-cheat-sheet
YellowHelpUrl: https://developers.datenstrom.se/fr/help/
YellowMarkdownUrl: https://developers.datenstrom.se/fr/help/markdown-cheat-sheet

View file

@ -5,7 +5,7 @@
class YellowLanguage
{
const VERSION = "0.7.4";
const VERSION = "0.7.5";
}
$yellow->plugins->register("language", "YellowLanguage", YellowLanguage::VERSION);

View file

@ -1,5 +1,5 @@
/* Flatsite theme, https://github.com/datenstrom/yellow-themes/tree/master/flatsite */
/* Copyright (c) 2013-2017 Datenstrom, https://datenstrom.se */
/* Copyright (c) 2013-2018 Datenstrom, https://datenstrom.se */
/* This file may be used and distributed under the terms of the public license. */
html, body, div, form, pre, span, tr, th, td, img { margin:0; padding:0; border:0; vertical-align:baseline; }
@ -29,7 +29,7 @@ body {
font-weight:300;
line-height:1.5;
}
h1, h2, h3, h4, h5, h6 { color:#07d; font-weight:normal; }
h1, h2, h3, h4, h5, h6 { color:#111; font-weight:normal; }
h1 { font-size:2.0em; }
hr { height:1px; background:#ddd; border:0; }
strong { font-weight:bold; }
@ -37,7 +37,8 @@ code { font-size:1.1em; }
a { color:#07d; text-decoration:none; }
a:hover { color:#07d; text-decoration:underline; }
.content h1:first-child, .content>*:first-child { margin-top:0; }
.content h1 a:hover { text-decoration:none; }
.content h1 a { color:#111; }
.content h1 a:hover { color:#111; text-decoration:none; }
.content img { max-width:100%; height:auto; }
.content form { margin:1em 0; }
.content table { border-spacing:0; border-collapse:collapse; }

View file

@ -1,11 +1,11 @@
<?php
// Flatsite theme, https://github.com/datenstrom/yellow-themes/tree/master/flatsite
// Copyright (c) 2013-2017 Datenstrom, https://datenstrom.se
// Copyright (c) 2013-2018 Datenstrom, https://datenstrom.se
// This file may be used and distributed under the terms of the public license.
class YellowThemeFlatsite
{
const VERSION = "0.7.2";
const VERSION = "0.7.3";
}
$yellow->themes->register("flatsite", "YellowThemeFlatsite", YellowThemeFlatsite::VERSION);