1
1
mirror of https://github.com/aelve/guide.git synced 2024-12-24 21:35:06 +03:00

Create some <textarea>s dynamically

Makes it quite a bit faster on Firefox (see #24)
This commit is contained in:
Artyom 2016-04-19 20:03:54 +03:00
parent e0ff916eea
commit 41230596bf
2 changed files with 112 additions and 22 deletions

View File

@ -44,6 +44,10 @@ allJSFunctions = JS . T.unlines . map fromJS $ [
showOrHideHelp, showHelp, hideHelp,
-- Misc
createAjaxIndicator,
autosizeTextarea,
-- Creating parts of interface
makeTraitEditor,
makeItemNotesEditor,
-- Add methods
addCategory, addItem,
addPro, addCon,
@ -85,12 +89,16 @@ instance JSParams () where
jsParams () = []
instance ToJS a => JSParams [a] where
jsParams = map toJS
instance (ToJS a, ToJS b) => JSParams (a,b) where
instance (ToJS a,ToJS b) => JSParams (a,b) where
jsParams (a,b) = [toJS a, toJS b]
instance (ToJS a, ToJS b, ToJS c) => JSParams (a,b,c) where
instance (ToJS a,ToJS b,ToJS c) => JSParams (a,b,c) where
jsParams (a,b,c) = [toJS a, toJS b, toJS c]
instance (ToJS a, ToJS b, ToJS c, ToJS d) => JSParams (a,b,c,d) where
instance (ToJS a,ToJS b,ToJS c,ToJS d) => JSParams (a,b,c,d) where
jsParams (a,b,c,d) = [toJS a, toJS b, toJS c, toJS d]
instance (ToJS a,ToJS b,ToJS c,ToJS d,ToJS e) => JSParams (a,b,c,d,e) where
jsParams (a,b,c,d,e) = [toJS a, toJS b, toJS c, toJS d, toJS e]
instance (ToJS a,ToJS b,ToJS c,ToJS d,ToJS e,ToJS f) => JSParams (a,b,c,d,e,f) where
jsParams (a,b,c,d,e,f) = [toJS a, toJS b, toJS c, toJS d, toJS e, toJS f]
{- | This hacky class lets you construct and use Javascript functions; you give 'makeJSFunction' function name, function parameters, and function body, and you get a polymorphic value of type @JSFunction a => a@, which you can use either as a complete function definition (if you set @a@ to be @JS@), or as a function that you can give some parameters and it would return a Javascript call:
@ -283,6 +291,82 @@ createAjaxIndicator =
$("#ajax-indicator").hide();
|]
autosizeTextarea :: JSFunction a => a
autosizeTextarea =
makeJSFunction "autosizeTextarea" ["textareaNode"]
[text|
autosize(textareaNode);
autosize.update(textareaNode);
|]
makeTraitEditor :: JSFunction a => a
makeTraitEditor =
makeJSFunction "makeTraitEditor"
["traitNode", "sectionNode", "textareaUid", "content", "itemId", "traitId"]
[text|
$(sectionNode).html("");
area = $("<textarea>", {
"autocomplete" : "off",
"rows" : "5",
"id" : textareaUid,
"class" : "fullwidth",
"text" : content })[0];
area.onkeydown = function () {
if (event.keyCode == 13) {
submitTrait(traitNode, itemId, traitId, area.value);
return false; } };
br = $("<br>")[0];
a = $("<a>", {
"href" : "#",
"text" : "cancel" })[0];
a.onclick = function () {
$(sectionNode).html("");
switchSection(traitNode, "editable");
return false; };
cancelBtn = $("<span>", {"class":"text-button"})[0];
$(cancelBtn).append(a);
$(sectionNode).append(area, br, cancelBtn);
|]
makeItemNotesEditor :: JSFunction a => a
makeItemNotesEditor =
makeJSFunction "makeItemNotesEditor"
["notesNode", "sectionNode", "textareaUid", "content", "itemId"]
[text|
$(sectionNode).html("");
area = $("<textarea>", {
"autocomplete" : "off",
"rows" : "10",
"id" : textareaUid,
"class" : "big fullwidth",
"text" : content })[0];
saveBtn = $("<input>", {
"value" : "Save",
"type" : "button" })[0];
saveBtn.onclick = function () {
submitItemNotes(notesNode, itemId, area.value); };
// Can't use $()-generation here because then the <span> would have
// to be cloned (since we're inserting it multiple times) and I don't
// know how to do that.
space = "<span style='margin-left:6px'></span>";
cancelBtn = $("<input>", {
"value" : "Cancel",
"type" : "button" })[0];
cancelBtn.onclick = function () {
$(sectionNode).html("");
switchSection(notesNode, "expanded"); };
monospace = $("<input>", {
"name" : "monospace",
"type" : "checkbox" })[0];
monospace.onchange = function () {
setMonospace(area, monospace.checked); };
monospaceLabel = $("<label>")[0];
$(monospaceLabel).append(monospace, "monospace editor");
$(sectionNode).append(
area, saveBtn, $(space), cancelBtn, $(space),
"Markdown", $(space), monospaceLabel);
|]
-- | Create a new category.
addCategory :: JSFunction a => a
addCategory =

View File

@ -865,6 +865,7 @@ renderTrait :: MonadIO m => Uid Item -> Trait -> HtmlT m ()
renderTrait itemId trait = do
let thisId = "trait-" <> uidToText (trait^.uid)
this = JS.selectId thisId
editingSectionUid <- randomLongUid
li_ [id_ thisId] $ do
sectionSpan "normal editable" [shown, noScriptShown] $ do
@ -879,15 +880,17 @@ renderTrait itemId trait = do
-- TODO: these 3 icons in a row don't look nice
imgButton "delete trait" "/x.svg" [width_ "12"] $
JS.deleteTrait (itemId, trait^.uid, this)
textareaUid <- randomLongUid
textButton "edit" $
JS.switchSection (this, "editing" :: Text)
JS.makeTraitEditor (this, JS.selectUid editingSectionUid,
textareaUid,
trait^.content.mdText,
itemId, trait^.uid) <>
JS.switchSection (this, "editing" :: Text) <>
JS.autosizeTextarea [JS.selectUid textareaUid]
section "editing" [] $ do
smallMarkdownEditor
[rows_ "5"]
(trait^.content)
(\val -> JS.submitTrait (this, itemId, trait^.uid, val))
(Just (JS.switchSection (this, "editable" :: Text)))
section "editing" [uid_ editingSectionUid] $ do
return ()
-- TODO: automatically provide links to modules in Markdown (and have a
-- database of modules or something)
@ -912,6 +915,7 @@ renderItemNotes :: MonadIO m => Item -> HtmlT m ()
renderItemNotes item = do
let thisId = "item-notes-" <> uidToText (item^.uid)
this = JS.selectId thisId
editingSectionUid <- randomLongUid
div_ [id_ thisId, class_ "item-notes"] $ do
section "collapsed" [shown] $ do
@ -929,12 +933,22 @@ renderItemNotes item = do
renderTOC toc
section "expanded" [noScriptShown] $ do
textareaUid <- randomLongUid
contents <- if item^.notes == ""
then liftIO $ T.readFile "static/item-notes-template.md"
else return (item^.notes.mdText)
let buttons = do
textButton "collapse notes" $
JS.switchSection (this, "collapsed" :: Text)
emptySpan "1em"
textButton "edit notes" $
JS.switchSection (this, "editing" :: Text)
JS.makeItemNotesEditor (
this, JS.selectUid editingSectionUid,
textareaUid,
contents,
item^.uid) <>
JS.switchSection (this, "editing" :: Text) <>
JS.autosizeTextarea [JS.selectUid textareaUid]
buttons
if item^.notes == ""
then p_ "add something!"
@ -944,16 +958,8 @@ renderItemNotes item = do
-- the notes are closed (but don't scroll if it's already visible after
-- the notes have been hidden)
section "editing" [] $ do
contents <- if item^.notes == ""
then liftIO $ renderMarkdownBlock <$>
T.readFile "static/item-notes-template.md"
else return (item^.notes)
markdownEditor
[rows_ "10"]
contents
(\val -> JS.submitItemNotes (this, item^.uid, val))
(JS.switchSection (this, "expanded" :: Text))
section "editing" [uid_ editingSectionUid] $
return ()
-- TODO: a shortcut for editing (when you press Ctrl-something, whatever was
-- selected becomes editable)
@ -1049,7 +1055,7 @@ markdownEditor attr (view mdText -> s) submit cancel = do
"Markdown"
emptySpan "6px"
-- TODO: this jumps around when there's a lot of text, need to somehow
-- prevent jumping
-- prevent jumping (and in JS.makeItemNotesEditor too)
let checkHandler = fromJS $
JS.setMonospace (JS.selectUid textareaUid, JS "this.checked")
label_ $ do