Add dedicated Title field to WYSIWYG editor

This takes styling from the Classic Editor on Write.as.

It adds all application code for auto-saving the title, publishing it
with the post body, and including it in the word count.
This commit is contained in:
Matt Baer 2020-03-11 13:28:02 -04:00
parent 4b0833435f
commit f76bfebfde
6 changed files with 112 additions and 31 deletions

View file

@ -515,7 +515,7 @@ pre, body#post article, #post .alert, #subpage .alert, body#collection article,
line-height: 1.5;
}
}
textarea, pre, body#post article, body#collection article p {
textarea, input#title, pre, body#post article, body#collection article p {
&.norm, &.sans, &.wrap {
line-height: 1.5;
white-space: pre-wrap; /* CSS 3 */
@ -525,7 +525,7 @@ textarea, pre, body#post article, body#collection article p {
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
}
textarea, pre, body#post article, body#collection article, body#subpage article, span, .font {
textarea, input#title, pre, body#post article, body#collection article, body#subpage article, span, .font {
&.norm {
font-family: @serifFont;
}

View file

@ -188,18 +188,18 @@ body#pad, body#pad-sub {
body#pad {
.pad-theme-transition;
textarea {
textarea, #title {
.pad-theme-transition;
}
&.dark {
textarea, #editor {
textarea, #title, #editor {
background-color: @darkBG;
color: @darkTextColor;
}
}
&.light {
textarea, #editor {
textarea, #title, #editor {
background-color: @lightBG;
color: @lightTextColor;
}

View file

@ -256,7 +256,7 @@ body#pad {
border: 0;
outline: 0;
}
textarea {
textarea, #title {
position: fixed !important;
top: 3em;
right: 0;
@ -367,6 +367,14 @@ body#pad {
top: 2.25em;
padding-top: 0.25em;
}
&.classic {
#editor {
top: 5.25em;
}
#title {
top: 3.5rem;
}
}
#tools {
padding-top: 0.5em;
padding-bottom: 0.5em;
@ -420,40 +428,40 @@ body#pad {
}
@media all and (min-width: 50em) {
body#pad {
textarea {
body#pad, body#pad.classic {
textarea, #title {
padding-left: 10%;
padding-right: 10%;
}
}
}
@media all and (min-width: 60em) {
body#pad {
textarea {
body#pad, body#pad.classic {
textarea, #title {
padding-left: 15%;
padding-right: 15%;
}
}
}
@media all and (min-width: 70em) {
body#pad {
textarea {
body#pad, body#pad.classic {
textarea, #title {
padding-left: 20%;
padding-right: 20%;
}
}
}
@media all and (min-width: 85em) {
body#pad {
textarea {
body#pad, body#pad.classic {
textarea, #title {
padding-left: 25%;
padding-right: 25%;
}
}
}
@media all and (min-width: 105em) {
body#pad {
textarea {
body#pad, body#pad.classic {
textarea, #title {
padding-left: 30%;
padding-right: 30%;
}

View file

@ -1,3 +1,36 @@
body#pad.classic {
header {
display: flex;
justify-content: space-between;
align-items: center;
}
#editor {
top: 4em;
}
#title {
top: 4.25rem;
bottom: unset;
height: auto;
font-weight: bold;
font-size: 2em;
padding-top: 0;
padding-bottom: 0;
border: 0;
}
#tools {
#belt {
float: none;
}
}
#target {
ul {
a {
padding: 0 0.5em !important;
}
}
}
}
.ProseMirror {
position: relative;
height: calc(~"100% - 1.6em");
@ -5,13 +38,13 @@
box-sizing: border-box;
-moz-box-sizing: border-box;
font-size: 1.2em;
}
.ProseMirror {
word-wrap: break-word;
white-space: pre-wrap;
-webkit-font-variant-ligatures: none;
font-variant-ligatures: none;
padding: 0.5em 0;
line-height: 1.5;
outline: none;
}
.ProseMirror pre {
@ -344,12 +377,6 @@ li.ProseMirror-selectednode:after {
margin-top: 10px;
}
.ProseMirror {
padding: 4px 8px 4px 14px;
line-height: 1.2;
outline: none;
}
.ProseMirror p {
margin-bottom: 1em;
}

View file

@ -119,6 +119,15 @@ var H = {
save: function($el, key) {
localStorage.setItem(key, $el.el.value);
},
saveClassic: function($titleEl, $el, key) {
var out = "";
var title = $titleEl.el.value;
if (title !== "") {
out = "# "+title+"\n\n";
}
out += $el.el.value;
localStorage.setItem(key, out);
},
load: function($el, key, onlyLoadPopulated) {
var val = localStorage.getItem(key);
if (onlyLoadPopulated && val == null) {
@ -127,6 +136,20 @@ var H = {
}
$el.el.value = val;
},
loadClassic: function($titleEl, $el, key, onlyLoadPopulated) {
var val = localStorage.getItem(key);
if (onlyLoadPopulated && val == null) {
// Do nothing
return;
}
if (val.indexOf("# ") === 0) {
var eol = val.indexOf("\n");
title = val.substring("# ".length, eol);
val = val.substring(eol+"\n\n".length);
$titleEl.el.value = title;
}
$el.el.value = val;
},
set: function(key, value) {
localStorage.setItem(key, value);
},

View file

@ -10,7 +10,7 @@
<meta name="google" value="notranslate">
</head>
<body id="pad" class="light">
<body id="pad" class="light classic">
<div id="overlay"></div>
@ -19,6 +19,7 @@
<!-- Markdown <input type=radio name=inputformat value=markdown checked>&nbsp;</label> -->
<!-- <label>&nbsp;<input type=radio name=inputformat value=prosemirror> WYSIWYM</label> -->
<!-- </div> -->
<input type="text" id="title" name="title" placeholder="Title..." {{if .Post.Title}}value="{{.Post.Title}}"{{end}} autofocus />
<div id="editor" style="margin-bottom: 0"></div>
<div style="display: none"><textarea id="content"{{if .Post.Content }} value={{.Post.Content}}>{{.Post.Content}}{{else}}>{{end}}</textarea></div>
@ -93,6 +94,7 @@
if (H.get('padTheme', 'light') != 'light') {
toggleTheme();
}
var $title = H.getEl('title');
var $writer = H.getQEl('div.ProseMirror');
var $content = H.getEl('content');
var $btnPublish = H.getEl('publish');
@ -103,6 +105,10 @@
if (val != '') {
words = $content.el.value.trim().replace(/\s+/gi, ' ').split(' ').length;
}
val = $title.el.value.trim();
if (val != '') {
words += $title.el.value.trim().replace(/\s+/gi, ' ').split(' ').length;
}
$wc.el.innerText = words + " word" + (words != 1 ? "s" : "");
};
var setButtonStates = function() {
@ -118,7 +124,7 @@
};
{{if .Post.Id}}var draftDoc = 'draft{{.Post.Id}}';
var origDoc = '{{.Post.Content}}';{{else}}var draftDoc = 'lastDoc';{{end}}
H.load($content, draftDoc, true);
H.loadClassic($title, $writer, draftDoc, true);
updateWordCount();
var typingTimer;
@ -140,7 +146,7 @@
var publishing = false;
var justPublished = false;
var silenced = {{.Silenced}};
var publish = function(content, font) {
var publish = function(title, content, font) {
if (silenced === true) {
alert("Your account is silenced, so you can't publish or update posts.");
return;
@ -165,7 +171,7 @@
var params = {
body: post.content,
title: post.title,
title: title,
font: font,
lang: lang
};
@ -248,6 +254,21 @@
};
setButtonStates();
$title.on('keyup input', function() {
setButtonStates();
clearTimeout(typingTimer);
typingTimer = setTimeout(doneTyping, doneTypingInterval);
}, false);
$title.on('keydown', function(e) {
if (e.keyCode == 13) {
if (e.metaKey || e.ctrlKey) {
$btnPublish.el.click();
} else {
e.preventDefault();
$writer.el.focus();
}
}
});
$writer.on('keyup input', function() {
setButtonStates();
clearTimeout(typingTimer);
@ -262,8 +283,9 @@
$btnPublish.on('click', function(e) {
e.preventDefault();
if (!publishing && $content.el.value) {
var title = $title.el.value;
var content = $content.el.value;
publish(content, selectedFont);
publish(title, content, selectedFont);
}
});
@ -329,6 +351,7 @@
e.preventDefault();
selectedFont = this.href.substring(this.href.indexOf('#')+1);
// TODO: don't change classes on the editor window
//$title.el.className = selectedFont;
//$writer.el.className = selectedFont;
document.querySelector('nav#font-picker li.selected').classList.remove('selected');
this.parentElement.classList.add('selected');
@ -346,7 +369,7 @@
var doneTyping = function() {
if (draftDoc == 'lastDoc' || $content.el.value != origDoc) {
H.save($content, draftDoc);
H.saveClassic($title, $content, draftDoc);
updateWordCount();
}
};