/- sur=boke, tp=trill-post /+ ui=trill-ui, sr=sortug, plib=trill-utils, kaji, lib=boke |_ [[=thread:tp =post:tp children=full-graph:tp] s=state:sur =bowl:gall] ++ css ^~ %- trip ''' #admin{ display:flex; #editor{ fieldset{ border: none; } input[type=text]{ width: 100%; line-height: 1.5rem; } textarea{ width: 100%; height: 50vh; resize: none; } } #sidebar{ width: 30%; height: 100vh; overflow-y: scroll; } #right{ width: 70%; } .admin-post{ } #comments{ textarea{ width: 100%; height: 10rem; } } } ''' ++ script =/ json-tags=json %- pairs:enjs:format %+ turn ~(tap by tags.s) |= [tag=@t p=(list *)] :+ tag %n (scot %ud (lent p)) =/ json-string %- trip %- en:json:html json-tags ^~ %+ weld """ const jsonString = '{json-string}'; const allTags = JSON.parse(jsonString); """ %- trip ''' console.log(allTags, "tags") const tagInput = document.getElementById("tag-input"); const tagStore = document.getElementById("tag-store"); const chipContainer = document.getElementById("chips"); tagInput.addEventListener("keypress", handleKey); tagInput.addEventListener("keyup", handleBackspace); const chipList = new Set(); function init(){ setTimeout(() => { console.log(tagStore.value, "tagstore") const initTags = tagStore.value.split(","); for (let tag of initTags){ if (tag){ chipList.add(tag); loadChip(tag); } } }, 500) } init(); function chipString(){ const string = [...chipList].reduce((acc, i) => `${acc},${i}`); // const string = JSON.stringify(Array.from(chipList)); tagStore.value = string; } function addChip(itag){ const tag = itag.toLowerCase(); if (!chipList.has(tag) && tag.length > 0 && tag.length < 32) { chipList.add(tag); this.loadChip(tag) tagInput.value = ""; chipString(); } } function removeChip(e){ chipList.delete(e.target.innerText); chipContainer.removeChild(e.target); chipString(); } function loadChip(tag) { const c = document.createElement('div'); c.classList.add("chip"); c.id = tag; c.innerText = tag; c.addEventListener("click", removeChip) chipContainer.insertBefore(c, tagInput); } function handleBackspace(e){ console.log(e.keyCode, "keyup") console.log(e.target.selectionStart, "keyup") if (!(e.keyCode === 8 && e.target.selectionStart == 0)) return const chips = chipContainer.querySelectorAll('.chip'); if (chips.length === 0) return const to_delete = chipContainer.querySelector('.selected-chip'); if (to_delete) removeChip({target: to_delete}); else { const last_chip = chips[chips.length - 1]; last_chip.classList.add("selected-chip"); } } function handleKey(e) { // autocomplete? console.log(e.keyCode, "keycode") console.log(e) if (e.keyIdentifier == 'U+000A' || e.keyIdentifier == 'Enter' || e.keyCode == 13) e.preventDefault(); if (e.keyCode === 13) addChip(e.target.value); } ''' ++ form ^- manx =/ is-edit !.=(*@da id.post) =/ tag-string (tags-to-tape:ui tags.post) =/ post-text (content-to-md:ui contents.post) ;div#editor ;style:"{css}" ;a/"/bianji" ;h3:"编辑器" == ;form =kaji "poke" =action "add-thread" ;* ?. is-edit ~ ;+ ;input(type "hidden", name "editing", value (enc:kaji [~docteg-mothep id.post])); ;fieldset ;label:"title" ;input(type "text", name "title", value (trip title.thread)); == ;fieldset ;div:"Tags" ;div#chips ;input(type "text", placeholder "press enter to input individual tags, click on a tag to delete", enterkeyhint "enter", id "tag-input"); ;input(type "hidden", id "tag-store", name "tags", value tag-string); == == ;fieldset ;textarea(name "text") ; {post-text} == == ;span#error-div; ;input(type "hidden", name "error-div", value "#error-div"); ;input(type "hidden", name "is-blog", value "is"); ;+ ?. is-edit ;fieldset ;input(type "submit", value "Submit"); == ;fieldset.fl ;input(type "submit", value "Edit"); ;button =kaji "poke" =action "del-thread" =name "pid" =payload (enc:kaji pid.thread) ; Delete == == == ;script:"{script}" == ++ comments ;div#comments ;+ ?~ children ;h3:"No comments" ;div ;h3:"{<(houyi:plib children)>} comments" ;* %+ turn (tap:form:tp children) comment == == ++ comment |= [=pid:tp p=full-node:tp] ^- manx =+ [sip id]=pid =/ author (get-name:lib sip) =/ time (datetime-to-tape:string:sr id.p.p "/") =/ id=tape (scow:parsing:sr %ud id) =/ js=tape "$store.replying_to.show('{id}')" :: =/ uncollapse=manx ;span.cp(x-bind "collapseButton"):"[+] ({<(houyi p)>})" :: =/ collapse ;span.cp(x-bind "collapseButton"):"[-]" ;li =id "comment{id}" ;div.comment-meta ;div.row ;a.comment-author/"{author}":"{author}" ; | ;a.comment-time/"{time}":"{time}" ; | ;span.toggle =target "comment-tree-{id}" ; [-] == ;button =kaji "poke" =action "del-post" =name "pid" =payload (scow:parsing:sr %uw (jam pid)) ; Delete == == == ;form.comment-content =kaji "poke" =action "edit-post" ;textarea =name "comment" ; {(content-to-md:ui contents.p.p)} == ;input(type "hidden", name "id", value id); ;input(type "hidden", name "error-div", value "#error-div"); ;input(type "hidden", name "ship", value (scow %p sip)); ;input(type "submit", value "Edit"); == :: ;span.fl(id id, x-bind "ReplyButton"):"reply" ;+ (grandchildren p) == ++ grandchildren |= p=full-node:tp ^- manx :: ?~ children.p ;ul.comment-list; =/ cs=(list [pid:tp full-node:tp]) (tap:form:tp children.p) ;ul.comment-list =id "comment-tree-{(scow:parsing:sr %ud id.p.p)}" ;* (turn cs comment) == ++ post-list ^- manx =/ sorted %+ sort ~(tap by paths.s) |= [[* p1=pid:tp] [* p2=pid:tp]] (gth id.p2 id.p1) ;div#sidebar ;* %+ roll sorted |= [[pat=path =pid:tp] acc=marl] =/ ted (get:torm:tp threads.s pid) ?~ ted acc ?. (~(has in tags.u.ted) 'blog') acc :_ acc ;div.admin-post.fl ;a/"/bianji{(trip (spat pat))}":"{(trip title.u.ted)}" == == ++ $ ^- manx ;div#admin ;+ post-list ;div#right ;+ form ;+ comments == ;script:"{collapsible:js:kaji}" == --