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.
pull/383/head
Matt Baer 5 years ago
parent 4b0833435f
commit f76bfebfde
  1. 4
      less/core.less
  2. 6
      less/pad-theme.less
  3. 30
      less/pad.less
  4. 45
      less/prose-editor.less
  5. 23
      static/js/h.js
  6. 35
      templates/wysiwyg.tmpl

@ -515,7 +515,7 @@ pre, body#post article, #post .alert, #subpage .alert, body#collection article,
line-height: 1.5; 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 { &.norm, &.sans, &.wrap {
line-height: 1.5; line-height: 1.5;
white-space: pre-wrap; /* CSS 3 */ 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+ */ 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 { &.norm {
font-family: @serifFont; font-family: @serifFont;
} }

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

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

@ -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 { .ProseMirror {
position: relative; position: relative;
height: calc(~"100% - 1.6em"); height: calc(~"100% - 1.6em");
@ -5,13 +38,13 @@
box-sizing: border-box; box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
font-size: 1.2em; font-size: 1.2em;
}
.ProseMirror {
word-wrap: break-word; word-wrap: break-word;
white-space: pre-wrap; white-space: pre-wrap;
-webkit-font-variant-ligatures: none; -webkit-font-variant-ligatures: none;
font-variant-ligatures: none; font-variant-ligatures: none;
padding: 0.5em 0;
line-height: 1.5;
outline: none;
} }
.ProseMirror pre { .ProseMirror pre {
@ -344,12 +377,6 @@ li.ProseMirror-selectednode:after {
margin-top: 10px; margin-top: 10px;
} }
.ProseMirror {
padding: 4px 8px 4px 14px;
line-height: 1.2;
outline: none;
}
.ProseMirror p { .ProseMirror p {
margin-bottom: 1em; margin-bottom: 1em;
} }

@ -119,6 +119,15 @@ var H = {
save: function($el, key) { save: function($el, key) {
localStorage.setItem(key, $el.el.value); 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) { load: function($el, key, onlyLoadPopulated) {
var val = localStorage.getItem(key); var val = localStorage.getItem(key);
if (onlyLoadPopulated && val == null) { if (onlyLoadPopulated && val == null) {
@ -127,6 +136,20 @@ var H = {
} }
$el.el.value = val; $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) { set: function(key, value) {
localStorage.setItem(key, value); localStorage.setItem(key, value);
}, },

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

Loading…
Cancel
Save