replace textarea with a content-editable div
Mainly because of the sluggish auto-resize "feature" which comes for free when using a content-editable div. If you use a custom CSS, make sure you replace textarea (element with .textarea (class) and set `white-space: pre`.
This commit is contained in:
parent
638ddc6359
commit
09451ff707
@ -27,6 +27,16 @@ a {
|
||||
font-weight: bold;
|
||||
font-family: "Helvetica", Arial, sans-serif;
|
||||
}
|
||||
|
||||
.textarea {
|
||||
white-space: pre;
|
||||
outline: 0px solid transparent;
|
||||
}
|
||||
|
||||
.textarea.placeholder {
|
||||
color: #AAA;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.parent-highlight {
|
||||
@ -82,6 +92,10 @@ a {
|
||||
}
|
||||
}
|
||||
|
||||
> .textarea-wrapper .textarea {
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
|
||||
> div.text {
|
||||
|
||||
p {
|
||||
@ -98,9 +112,10 @@ a {
|
||||
|
||||
}
|
||||
|
||||
> div.textarea-wrapper textarea {
|
||||
> div.textarea-wrapper .textarea {
|
||||
@include fill-parent;
|
||||
@include isso-shadow;
|
||||
min-height: 48px;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
@ -155,12 +170,9 @@ a {
|
||||
> .form-wrapper {
|
||||
@include span-columns(10 of 11);
|
||||
|
||||
textarea {
|
||||
.textarea {
|
||||
@include fill-parent;
|
||||
@include isso-shadow;
|
||||
@include placeholder {
|
||||
color: #AAA;
|
||||
}
|
||||
|
||||
min-height: 48px;
|
||||
font: inherit;
|
||||
|
@ -15,7 +15,7 @@ define(["app/text/html", "app/dom", "app/utils", "app/config", "app/api", "app/m
|
||||
$(".avatar > svg", el).replace(lib.identicons.blank(4, 48));
|
||||
|
||||
// on text area focus, generate identicon from IP address
|
||||
$(".textarea-wrapper > textarea", el).on("focus", function() {
|
||||
$(".textarea-wrapper > .textarea", el).on("focus", function() {
|
||||
if ($(".avatar svg", el).getAttribute("className") === "blank") {
|
||||
$(".avatar svg", el).replace(
|
||||
lib.identicons.generate(lib.pbkdf2(api.remote_addr(), api.salt, 1000, 6), 4, 48));
|
||||
@ -45,8 +45,10 @@ define(["app/text/html", "app/dom", "app/utils", "app/config", "app/api", "app/m
|
||||
el.onsuccess = function() {};
|
||||
|
||||
el.validate = function() {
|
||||
if ($("textarea", this).value.length < 3) {
|
||||
$("textarea", this).focus();
|
||||
if (utils.text($(".textarea", this).innerHTML).length < 3 ||
|
||||
$(".textarea", this).classList.contains("placeholder"))
|
||||
{
|
||||
$(".textarea", this).focus();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -62,14 +64,13 @@ define(["app/text/html", "app/dom", "app/utils", "app/config", "app/api", "app/m
|
||||
api.create($("#isso-thread").getAttribute("data-isso-id"), {
|
||||
author: $("[name=author]", el).value || null,
|
||||
email: $("[name=email]", el).value || null,
|
||||
text: $("textarea", el).value,
|
||||
text: utils.text($(".textarea", el).innerHTML),
|
||||
parent: parent || null
|
||||
}).then(function(comment) {
|
||||
$("[name=author]", el).value = "";
|
||||
$("[name=email]", el).value = "";
|
||||
$("textarea", el).value = "";
|
||||
$("textarea", el).rows = 2;
|
||||
$("textarea", el).blur();
|
||||
$(".textarea", el).innerHTML = "";
|
||||
$(".textarea", el).blur();
|
||||
insert(comment, true);
|
||||
|
||||
if (parent !== null) {
|
||||
@ -79,8 +80,7 @@ define(["app/text/html", "app/dom", "app/utils", "app/config", "app/api", "app/m
|
||||
});
|
||||
});
|
||||
|
||||
// copy'n'paste sluggy automagically dynamic textarea resize
|
||||
lib.fancy.autoresize($("textarea", el), 48);
|
||||
lib.editorify($(".textarea", el));
|
||||
|
||||
return el;
|
||||
};
|
||||
@ -136,7 +136,7 @@ define(["app/text/html", "app/dom", "app/utils", "app/config", "app/api", "app/m
|
||||
function(toggler) {
|
||||
form = footer.insertAfter(new Postbox(comment.id));
|
||||
form.onsuccess = function() { toggler.next(); };
|
||||
$("textarea", form).focus();
|
||||
$(".textarea", form).focus();
|
||||
$("a.reply", footer).textContent = msgs["comment-close"];
|
||||
},
|
||||
function() {
|
||||
@ -186,35 +186,45 @@ define(["app/text/html", "app/dom", "app/utils", "app/config", "app/api", "app/m
|
||||
|
||||
edit.textContent = msgs["comment-save"];
|
||||
edit.insertAfter($.new("a.cancel", msgs["comment-cancel"])).on("click", function() {
|
||||
text.textContent = "";
|
||||
text.className = "text";
|
||||
text.append(comment.text);
|
||||
toggler.canceled = true;
|
||||
toggler.next();
|
||||
});
|
||||
|
||||
toggler.canceled = false;
|
||||
api.view(comment.id, 1).then(function(rv) {
|
||||
var textarea = $.new("textarea", rv.text);
|
||||
lib.fancy.autoresize(textarea, 48);
|
||||
text.className = "textarea-wrapper";
|
||||
var textarea = lib.editorify($.new("div.textarea"));
|
||||
|
||||
textarea.textContent = rv.text;
|
||||
textarea.focus();
|
||||
|
||||
text.classList.remove("text");
|
||||
text.classList.add("textarea-wrapper");
|
||||
|
||||
text.textContent = "";
|
||||
text.append(textarea);
|
||||
textarea.focus();
|
||||
});
|
||||
},
|
||||
function(toggler) {
|
||||
var textarea = $("textarea", text);
|
||||
if (textarea && textarea.value.length < 3) {
|
||||
textarea.focus();
|
||||
toggler.wait();
|
||||
return;
|
||||
} else if (textarea) {
|
||||
api.modify(comment.id, {"text": textarea.value}).then(function(rv) {
|
||||
text.innerHTML = rv.text;
|
||||
text.className = "text";
|
||||
comment.text = rv.text;
|
||||
});
|
||||
var textarea = $(".textarea", text);
|
||||
|
||||
if (! toggler.canceled && textarea !== null) {
|
||||
if (utils.text(textarea.innerHTML).length < 3) {
|
||||
textarea.focus();
|
||||
toggler.wait();
|
||||
return;
|
||||
} else {
|
||||
api.modify(comment.id, {"text": utils.text(textarea.innerHTML)}).then(function(rv) {
|
||||
text.innerHTML = rv.text;
|
||||
comment.text = rv.text;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
text.innerHTML = comment.text;
|
||||
}
|
||||
|
||||
text.classList.remove("textarea-wrapper");
|
||||
text.classList.add("text");
|
||||
|
||||
$("a.cancel", footer).remove();
|
||||
$("a.edit", footer).textContent = msgs["comment-edit"];
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
define(function (require) {
|
||||
return {
|
||||
fancy: require("app/lib/fancy"),
|
||||
editorify: require("app/lib/editor"),
|
||||
identicons: require("app/lib/identicons"),
|
||||
pbkdf2: require("app/lib/pbkdf2"),
|
||||
sha1: require("app/lib/sha1")
|
||||
|
24
isso/js/app/lib/editor.js
Normal file
24
isso/js/app/lib/editor.js
Normal file
@ -0,0 +1,24 @@
|
||||
define(["app/dom", "app/markup"], function($, Mark) {
|
||||
"use strict";
|
||||
|
||||
return function(el) {
|
||||
el.setAttribute("contentEditable", true);
|
||||
|
||||
el.on("focus", function() {
|
||||
if (el.classList.contains("placeholder")) {
|
||||
el.innerHTML = "";
|
||||
el.classList.remove("placeholder");
|
||||
}
|
||||
});
|
||||
|
||||
el.on("blur", function() {
|
||||
if (el.textContent.length === 0) {
|
||||
el.textContent = Mark.up("{{ i18n-postbox-text }}");
|
||||
el.classList.add("placeholder");
|
||||
}
|
||||
});
|
||||
|
||||
return el;
|
||||
};
|
||||
|
||||
});
|
@ -1,20 +0,0 @@
|
||||
define(function() {
|
||||
|
||||
"use strict";
|
||||
|
||||
var autoresize = function(textarea, minheight) {
|
||||
var offset= !window.opera ? (textarea.offsetHeight - textarea.clientHeight) : (textarea.offsetHeight + parseInt(window.getComputedStyle(textarea, null).getPropertyValue('border-top-width')));
|
||||
["keyup", "focus"].forEach(function(event) {
|
||||
textarea.on(event, function() {
|
||||
if ((textarea.scrollHeight + offset ) > minheight) {
|
||||
textarea.style.height = "auto";
|
||||
textarea.style.height = (textarea.scrollHeight + offset ) + 'px';
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
autoresize: autoresize
|
||||
};
|
||||
});
|
@ -4,7 +4,7 @@
|
||||
</div>
|
||||
<div class="form-wrapper">
|
||||
<div class="textarea-wrapper">
|
||||
<textarea name="text" rows="2" placeholder="{{ i18n-postbox-text }}"></textarea>
|
||||
<div class="textarea placeholder" contenteditable="true">{{ i18n-postbox-text }}</div>
|
||||
</div>
|
||||
<section class="auth-section">
|
||||
<p class="input-wrapper">
|
||||
|
@ -1,4 +1,5 @@
|
||||
define(["app/markup"], function(Mark) {
|
||||
"use strict";
|
||||
|
||||
// return `cookie` string if set
|
||||
var cookie = function(cookie) {
|
||||
@ -7,7 +8,7 @@ define(["app/markup"], function(Mark) {
|
||||
|
||||
var ago = function(localTime, date) {
|
||||
|
||||
var secs = ((localTime.getTime() - date.getTime()) / 1000)
|
||||
var secs = ((localTime.getTime() - date.getTime()) / 1000);
|
||||
|
||||
if (isNaN(secs) || secs < 0 ) {
|
||||
secs = 0;
|
||||
@ -39,8 +40,17 @@ define(["app/markup"], function(Mark) {
|
||||
i18n("date-year", Math.ceil(days / 365.25));
|
||||
};
|
||||
|
||||
var text = function(html) {
|
||||
var _ = document.createElement("div");
|
||||
_.innerHTML = html.replace(/<div><br><\/div>/gi, '<br>')
|
||||
.replace(/<div>/gi,'<br>')
|
||||
.replace(/<br>/gi, '\n');
|
||||
return _.textContent.trim();
|
||||
};
|
||||
|
||||
return {
|
||||
cookie: cookie,
|
||||
ago: ago
|
||||
ago: ago,
|
||||
text: text
|
||||
};
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user