Updated article title and section changing UI and logic
This commit is contained in:
parent
250b0b8d41
commit
7afbf8257f
232
components.js
232
components.js
@ -3553,238 +3553,6 @@ customElements.define('sm-switch', class extends HTMLElement {
|
||||
|
||||
})
|
||||
|
||||
const textField = document.createElement('template')
|
||||
textField.innerHTML = `
|
||||
<style>
|
||||
*{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
:host{
|
||||
--accent-color: #4d2588;
|
||||
--text-color: 17, 17, 17;
|
||||
--background-color: 255, 255, 255;
|
||||
}
|
||||
.text-field{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.text{
|
||||
transition: background-color 0.3s;
|
||||
border-bottom: 0.15rem solid transparent;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
word-break: break-word;
|
||||
-moz-hyphens: auto;
|
||||
-webkit-hyphens: auto;
|
||||
hyphens: auto;
|
||||
}
|
||||
.text:focus{
|
||||
outline: none;
|
||||
border-bottom: 0.15rem solid var(--accent-color);
|
||||
}
|
||||
.text:focus-visible{
|
||||
outline: none;
|
||||
background: solid rgba(var(--text-color), 0.06);
|
||||
}
|
||||
.editable{
|
||||
border-bottom: 0.15rem solid rgba(var(--text-color), 0.6);
|
||||
}
|
||||
.edit-button{
|
||||
display: grid;
|
||||
position: relative;
|
||||
margin-left: 0.5rem;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
:host([disabled]) .edit-button{
|
||||
display: none;
|
||||
}
|
||||
.icon{
|
||||
grid-area: 1/-1;
|
||||
cursor: pointer;
|
||||
height: 1.2rem;
|
||||
width: 1.2rem;
|
||||
fill: rgba(var(--text-color), 1);
|
||||
}
|
||||
.hide{
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
||||
<div class="text-field">
|
||||
<div class="text" part="text"></div>
|
||||
<button class="edit-button">
|
||||
<svg class="icon" title="edit" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg>
|
||||
<svg class="icon hide" title="Save" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
`
|
||||
|
||||
customElements.define('text-field', class extends HTMLElement {
|
||||
constructor() {
|
||||
super()
|
||||
this.attachShadow({
|
||||
mode: 'open'
|
||||
}).append(textField.content.cloneNode(true))
|
||||
|
||||
this.textField = this.shadowRoot.querySelector('.text-field')
|
||||
this.textContainer = this.textField.children[0]
|
||||
this.iconsContainer = this.textField.children[1]
|
||||
this.editButton = this.textField.querySelector('.edit-button')
|
||||
this.isTextEditable = false
|
||||
this.isDisabled = false
|
||||
|
||||
this.fireEvent = this.fireEvent.bind(this)
|
||||
this.setEditable = this.setEditable.bind(this)
|
||||
this.setNonEditable = this.setNonEditable.bind(this)
|
||||
this.toggleEditable = this.toggleEditable.bind(this)
|
||||
this.revert = this.revert.bind(this)
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ['disabled', 'value']
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this.text
|
||||
}
|
||||
set value(val) {
|
||||
this.setAttribute('value', val)
|
||||
}
|
||||
set disabled(val) {
|
||||
this.isDisabled = val
|
||||
if (this.isDisabled)
|
||||
this.setAttribute('disabled', '')
|
||||
else
|
||||
this.removeAttribute('disabled')
|
||||
}
|
||||
fireEvent(value) {
|
||||
let event = new CustomEvent('change', {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
composed: true,
|
||||
detail: {
|
||||
value
|
||||
}
|
||||
});
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
|
||||
setEditable() {
|
||||
if (this.isTextEditable) return
|
||||
this.textContainer.contentEditable = true
|
||||
this.textContainer.classList.add('editable')
|
||||
this.textContainer.focus()
|
||||
document.execCommand('selectAll', false, null);
|
||||
this.editButton.children[0].animate(this.rotateOut, this.animOptions).onfinish = () => {
|
||||
this.editButton.children[0].classList.add('hide')
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.editButton.children[1].classList.remove('hide')
|
||||
this.editButton.children[1].animate(this.rotateIn, this.animOptions)
|
||||
}, 100);
|
||||
this.isTextEditable = true
|
||||
}
|
||||
setNonEditable() {
|
||||
if (!this.isTextEditable) return
|
||||
this.textContainer.contentEditable = false
|
||||
this.textContainer.classList.remove('editable')
|
||||
const newValue = this.textContainer.textContent.trim()
|
||||
if (this.text !== newValue && newValue !== '') {
|
||||
this.setAttribute('value', this.textContainer.textContent)
|
||||
this.text = this.textContainer.textContent.trim()
|
||||
this.fireEvent(this.text)
|
||||
} else {
|
||||
this.value = this.text
|
||||
}
|
||||
this.editButton.children[1].animate(this.rotateOut, this.animOptions).onfinish = () => {
|
||||
this.editButton.children[1].classList.add('hide')
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.editButton.children[0].classList.remove('hide')
|
||||
this.editButton.children[0].animate(this.rotateIn, this.animOptions)
|
||||
}, 100);
|
||||
this.isTextEditable = false
|
||||
}
|
||||
toggleEditable() {
|
||||
if (this.isTextEditable)
|
||||
this.setNonEditable()
|
||||
else
|
||||
this.setEditable()
|
||||
}
|
||||
|
||||
revert() {
|
||||
if (this.textContainer.isContentEditable) {
|
||||
this.value = this.text
|
||||
this.setNonEditable()
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.text
|
||||
if (this.hasAttribute('value')) {
|
||||
this.text = this.getAttribute('value')
|
||||
this.textContainer.textContent = this.text
|
||||
}
|
||||
if (this.hasAttribute('disabled'))
|
||||
this.isDisabled = true
|
||||
else
|
||||
this.isDisabled = false
|
||||
|
||||
this.rotateOut = [
|
||||
{
|
||||
transform: 'rotate(0)',
|
||||
opacity: 1
|
||||
},
|
||||
{
|
||||
transform: 'rotate(90deg)',
|
||||
opacity: 0
|
||||
},
|
||||
]
|
||||
this.rotateIn = [
|
||||
{
|
||||
transform: 'rotate(-90deg)',
|
||||
opacity: 0
|
||||
},
|
||||
{
|
||||
transform: 'rotate(0)',
|
||||
opacity: 1
|
||||
},
|
||||
]
|
||||
this.animOptions = {
|
||||
duration: 300,
|
||||
easing: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
|
||||
fill: 'forwards'
|
||||
}
|
||||
if (!this.isDisabled) {
|
||||
this.iconsContainer.classList.remove('hide')
|
||||
this.textContainer.addEventListener('dblclick', this.setEditable)
|
||||
this.editButton.addEventListener('click', this.toggleEditable)
|
||||
}
|
||||
}
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (name === 'disabled') {
|
||||
if (this.hasAttribute('disabled')) {
|
||||
this.textContainer.removeEventListener('dblclick', this.setEditable)
|
||||
this.editButton.removeEventListener('click', this.toggleEditable)
|
||||
this.revert()
|
||||
}
|
||||
else {
|
||||
this.textContainer.addEventListener('dblclick', this.setEditable)
|
||||
this.editButton.addEventListener('click', this.toggleEditable)
|
||||
}
|
||||
} else if (name === 'value') {
|
||||
this.text = newValue
|
||||
this.textContainer.textContent = newValue
|
||||
}
|
||||
}
|
||||
disconnectedCallback() {
|
||||
this.textContainer.removeEventListener('dblclick', this.setEditable)
|
||||
this.editButton.removeEventListener('click', this.toggleEditable)
|
||||
}
|
||||
})
|
||||
const smMenu = document.createElement('template')
|
||||
smMenu.innerHTML = `
|
||||
<style>
|
||||
|
||||
32
css/main.css
32
css/main.css
@ -620,6 +620,7 @@ sm-copy {
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
#current_article_title {
|
||||
@ -671,33 +672,24 @@ sm-copy {
|
||||
}
|
||||
|
||||
#section_list_container {
|
||||
background-color: rgba(var(--text-color), 0.06);
|
||||
margin: 1rem 0;
|
||||
padding: 0 0.8rem;
|
||||
border-radius: 0.5rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.section-card {
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.section-card:not(.section-card--new) {
|
||||
padding: 0.8rem 0;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.section-card--new input {
|
||||
.section-card input {
|
||||
background-color: rgba(var(--text-color), 0.06);
|
||||
padding: 0.8rem;
|
||||
border-radius: 0.3rem;
|
||||
border: none;
|
||||
font-size: inherit;
|
||||
background: inherit;
|
||||
color: inherit;
|
||||
font-weight: inherit;
|
||||
width: 100%;
|
||||
padding: 0.8rem 0.2rem;
|
||||
}
|
||||
.section-card--new input:focus {
|
||||
.section-card input:focus {
|
||||
outline: var(--accent-color) solid;
|
||||
}
|
||||
.section-card .remove {
|
||||
@ -1071,12 +1063,6 @@ sm-copy {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@supports (-webkit-text-stroke: 1px black) {
|
||||
#landing h1 {
|
||||
-webkit-text-stroke: 1px rgba(var(--text-color), 1);
|
||||
-webkit-text-fill-color: rgba(var(--background-color), 1);
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 40rem) {
|
||||
sm-popup {
|
||||
--width: 24rem;
|
||||
@ -1115,10 +1101,6 @@ sm-copy {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#landing h1 {
|
||||
-webkit-text-stroke-width: 0.1rem;
|
||||
}
|
||||
|
||||
#main_header {
|
||||
padding: 1rem 1.5rem;
|
||||
grid-template-columns: auto 1fr auto auto;
|
||||
|
||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -588,6 +588,7 @@ sm-copy {
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
align-content: flex-start;
|
||||
}
|
||||
#current_article_title {
|
||||
font-weight: 700;
|
||||
@ -638,30 +639,22 @@ sm-copy {
|
||||
--body-padding: 1.2rem;
|
||||
}
|
||||
#section_list_container {
|
||||
background-color: rgba(var(--text-color), 0.06);
|
||||
margin: 1rem 0;
|
||||
padding: 0 0.8rem;
|
||||
border-radius: 0.5rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.section-card {
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
&:not(.section-card--new) {
|
||||
padding: 0.8rem 0;
|
||||
user-select: none;
|
||||
}
|
||||
&--new {
|
||||
input {
|
||||
border: none;
|
||||
font-size: inherit;
|
||||
background: inherit;
|
||||
color: inherit;
|
||||
font-weight: inherit;
|
||||
width: 100%;
|
||||
padding: 0.8rem 0.2rem;
|
||||
&:focus {
|
||||
outline: var(--accent-color) solid;
|
||||
}
|
||||
input {
|
||||
background-color: rgba(var(--text-color), 0.06);
|
||||
padding: 0.8rem;
|
||||
border-radius: 0.3rem;
|
||||
border: none;
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
font-weight: inherit;
|
||||
width: 100%;
|
||||
&:focus {
|
||||
outline: var(--accent-color) solid;
|
||||
}
|
||||
}
|
||||
.remove {
|
||||
@ -1011,12 +1004,6 @@ sm-copy {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@supports (-webkit-text-stroke: 1px black) {
|
||||
#landing h1 {
|
||||
-webkit-text-stroke: 1px rgba(var(--text-color), 1);
|
||||
-webkit-text-fill-color: rgba(var(--background-color), 1);
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 40rem) {
|
||||
sm-popup {
|
||||
--width: 24rem;
|
||||
@ -1049,9 +1036,6 @@ sm-copy {
|
||||
.hide-on-desktop {
|
||||
display: none;
|
||||
}
|
||||
#landing h1 {
|
||||
-webkit-text-stroke-width: 0.1rem;
|
||||
}
|
||||
#main_header {
|
||||
padding: 1rem 1.5rem;
|
||||
grid-template-columns: auto 1fr auto auto;
|
||||
|
||||
190
index.html
190
index.html
@ -167,7 +167,7 @@
|
||||
d="M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z" />
|
||||
</svg>
|
||||
</button>
|
||||
<text-field id="current_article_title"></text-field>
|
||||
<h4 id="current_article_title"></h4>
|
||||
<button id="article_outline_button" class="icon-only" title="View article outline"
|
||||
onclick="toggleOutlinePanel()">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px"
|
||||
@ -204,7 +204,7 @@
|
||||
d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z">
|
||||
</path>
|
||||
</svg>
|
||||
Edit sections
|
||||
Edit title & sections
|
||||
</menu-option>
|
||||
<menu-option onclick="setDefaultArticle()">
|
||||
<svg class="icon button__icon--left" xmlns="http://www.w3.org/2000/svg"
|
||||
@ -473,36 +473,44 @@
|
||||
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
|
||||
</svg>
|
||||
</button>
|
||||
<h3>Edit sections</h3>
|
||||
<h3>Edit title & sections</h3>
|
||||
</header>
|
||||
<h5 class="label">Existing sections</h5>
|
||||
<div id="section_list_container" class="observe-empty-state"></div>
|
||||
<p class="empty-state">
|
||||
There are no sections so far, you can add section with button below.
|
||||
</p>
|
||||
<div class="flex space-between align-center">
|
||||
<sm-button id="insert_section_button" onclick="insertEmptySection()">
|
||||
<svg class="icon button__icon--left" xmlns="http://www.w3.org/2000/svg"
|
||||
enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||
<g>
|
||||
<rect fill="none" height="24" width="24" />
|
||||
</g>
|
||||
<g>
|
||||
<g />
|
||||
<section class="grid gap-1-5">
|
||||
<div class="grid gap-0-5">
|
||||
<h5 class="label">Title</h5>
|
||||
<sm-input id="edit_article_title"></sm-input>
|
||||
</div>
|
||||
<div class="grid gap-0-5">
|
||||
<h5 class="label">Sections</h5>
|
||||
<div id="section_list_container" class="observe-empty-state grid"></div>
|
||||
<p class="empty-state">
|
||||
There are no sections so far, you can add section with button below.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex space-between align-center">
|
||||
<sm-button id="insert_section_button" onclick="insertEmptySection()">
|
||||
<svg class="icon button__icon--left" xmlns="http://www.w3.org/2000/svg"
|
||||
enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||
<g>
|
||||
<path
|
||||
d="M17,19.22H5V7h7V5H5C3.9,5,3,5.9,3,7v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-7h-2V19.22z" />
|
||||
<path d="M19,2h-2v3h-3c0.01,0.01,0,2,0,2h3v2.99c0.01,0.01,2,0,2,0V7h3V5h-3V2z" />
|
||||
<rect height="2" width="8" x="7" y="9" />
|
||||
<polygon points="7,12 7,14 15,14 15,12 12,12" />
|
||||
<rect height="2" width="8" x="7" y="15" />
|
||||
<rect fill="none" height="24" width="24" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
Insert section
|
||||
</sm-button>
|
||||
<sm-button variant="primary" onclick="saveSectionEdit()">Save</sm-button>
|
||||
</div>
|
||||
<g>
|
||||
<g />
|
||||
<g>
|
||||
<path
|
||||
d="M17,19.22H5V7h7V5H5C3.9,5,3,5.9,3,7v12c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-7h-2V19.22z" />
|
||||
<path d="M19,2h-2v3h-3c0.01,0.01,0,2,0,2h3v2.99c0.01,0.01,2,0,2,0V7h3V5h-3V2z" />
|
||||
<rect height="2" width="8" x="7" y="9" />
|
||||
<polygon points="7,12 7,14 15,14 15,12 12,12" />
|
||||
<rect height="2" width="8" x="7" y="15" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
Insert section
|
||||
</sm-button>
|
||||
<sm-button variant="primary" onclick="saveSectionEdit()">Save</sm-button>
|
||||
</div>
|
||||
</section>
|
||||
</sm-popup>
|
||||
<sm-popup id="contributors_popup">
|
||||
<header slot="header" class="popup__header">
|
||||
@ -594,7 +602,7 @@
|
||||
</template>
|
||||
<template id="section_template">
|
||||
<div class="heading flex align-center">
|
||||
<text-field></text-field>
|
||||
<h4 class="section-title"></h4>
|
||||
</div>
|
||||
<section class="article-section">
|
||||
<div class="content-card content-card--empty">
|
||||
@ -1343,7 +1351,7 @@
|
||||
break
|
||||
}
|
||||
if (noOfContributors < 2 && !contributors.hasOwnProperty(myFloID)) {
|
||||
contentCard.querySelector('.content__author').textContent = `2 Contributors`
|
||||
contentCard.querySelector('.content__author').textContent = `${myFloID} and 1 more`
|
||||
}
|
||||
floGlobals.currentArticle.uniqueEntries[entry.origin].iterations.push(genDataVC)
|
||||
}
|
||||
@ -1462,14 +1470,6 @@
|
||||
animateTo(getRef('article_name_wrapper'), slideInRight, animOptions)
|
||||
}
|
||||
}
|
||||
} else if (e.target.closest('text-field')) {
|
||||
const heading = e.target.closest('.heading');
|
||||
floGlobals.appObjects[floGlobals.currentArticle.id].sections[heading.dataset.index].title = e.target.value.trim()
|
||||
floCloudAPI.updateObjectData(floGlobals.currentArticle.id)
|
||||
.then((res) => {
|
||||
notify('Updated heading', 'success')
|
||||
})
|
||||
.catch(err => console.error(err))
|
||||
}
|
||||
})
|
||||
|
||||
@ -1724,14 +1724,6 @@
|
||||
currentElement.remove()
|
||||
}
|
||||
})
|
||||
getRef('current_article_title').addEventListener("change", e => {
|
||||
floGlobals.appObjects.cc.articleList[floGlobals.currentArticle.id].title = e.target.value.trim()
|
||||
floCloudAPI.updateObjectData('cc')
|
||||
.then((res) => {
|
||||
notify('Renamed article', 'success')
|
||||
})
|
||||
.catch(err => console.error(err))
|
||||
})
|
||||
getRef('article_wrapper').addEventListener("focusin", e => {
|
||||
if (e.target.closest('.content__area')) {
|
||||
const target = e.target.closest('.content__area')
|
||||
@ -1872,24 +1864,10 @@
|
||||
frag.append(render.section(sectionID, sections[sectionID], index))
|
||||
index += 1
|
||||
}
|
||||
if (!floGlobals.isSubAdmin) {
|
||||
getRef('current_article_title').setAttribute('disabled', '')
|
||||
}
|
||||
getRef('current_article_title').value = title
|
||||
getRef('current_article_title').textContent = title
|
||||
getRef('article_wrapper').innerHTML = ''
|
||||
getRef('article_wrapper').append(frag)
|
||||
|
||||
getRef('article_outline').innerHTML = ''
|
||||
floGlobals.appObjects[floGlobals.currentArticle.id].sections.forEach(section => {
|
||||
frag.append(createElement('button', {
|
||||
attributes: { 'data-section-id': section.id },
|
||||
className: 'outline-button',
|
||||
textContent: section.title,
|
||||
}))
|
||||
})
|
||||
getRef('article_outline').append(frag)
|
||||
|
||||
|
||||
render.sectionOutline()
|
||||
},
|
||||
articleLink(details, isDefaultArticle) {
|
||||
const { uid, timestamp, title } = details
|
||||
@ -1964,18 +1942,15 @@
|
||||
}
|
||||
return clone
|
||||
},
|
||||
section(sectionID, { title, uniqueEntries }, index) {
|
||||
section(sectionID, { title, uniqueEntries }) {
|
||||
const section = getRef('section_template').content.cloneNode(true)
|
||||
const frag = document.createDocumentFragment()
|
||||
section.children[0].dataset.index = index
|
||||
section.children[0].dataset.sectionId = sectionID
|
||||
section.children[1].dataset.sectionId = sectionID
|
||||
if (floGlobals.isSubAdmin) {
|
||||
section.querySelector('.content-card--empty').remove()
|
||||
} else {
|
||||
section.querySelector('text-field').setAttribute('disabled', '')
|
||||
}
|
||||
section.querySelector('text-field').setAttribute('value', title)
|
||||
section.querySelector('.section-title').textContent = title
|
||||
floGlobals.currentArticle.sections[sectionID].uniqueEntries.slice(0, maxCardsPerSection).forEach(entry => {
|
||||
const contentCard = render.contentCard(entry)
|
||||
if (contentCard)
|
||||
@ -1994,14 +1969,27 @@
|
||||
return section
|
||||
},
|
||||
sectionCard(details) {
|
||||
const { title } = details
|
||||
const { title, id } = details
|
||||
return createElement('div', {
|
||||
className: 'section-card flex align-center',
|
||||
attributes: { 'data-section-id': id },
|
||||
innerHTML: `
|
||||
<svg class="icon button__icon--left" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><path d="M9,18h12v-2H9V18z M3,6v2h18V6H3z M9,13h12v-2H9V13z"/></g></svg>
|
||||
${title}
|
||||
<input placeholder="Section title" value="${title}"/>
|
||||
`
|
||||
})
|
||||
},
|
||||
sectionOutline() {
|
||||
const frag = document.createDocumentFragment()
|
||||
getRef('article_outline').innerHTML = ''
|
||||
floGlobals.appObjects[floGlobals.currentArticle.id].sections.forEach(section => {
|
||||
frag.append(createElement('button', {
|
||||
attributes: { 'data-section-id': section.id },
|
||||
className: 'outline-button',
|
||||
textContent: section.title,
|
||||
}))
|
||||
})
|
||||
getRef('article_outline').append(frag)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2174,6 +2162,7 @@
|
||||
getRef('sort_content_list').addEventListener('change', sortSectionEntries)
|
||||
function renderSectionList() {
|
||||
if (!floGlobals.isSubAdmin) return
|
||||
getRef('edit_article_title').value = floGlobals.appObjects.cc.articleList[floGlobals.currentArticle.id].title
|
||||
const frag = document.createDocumentFragment()
|
||||
floGlobals.appObjects[floGlobals.currentArticle.id].sections.forEach(section => {
|
||||
frag.append(render.sectionCard(section))
|
||||
@ -2183,7 +2172,7 @@
|
||||
}
|
||||
function insertEmptySection() {
|
||||
const emptySection = createElement('div', {
|
||||
className: 'section-card section-card--new flex align-center',
|
||||
className: 'section-card flex align-center',
|
||||
innerHTML: `
|
||||
<svg class="icon button__icon--left" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><path d="M9,18h12v-2H9V18z M3,6v2h18V6H3z M9,13h12v-2H9V13z"/></g></svg>
|
||||
<input placeholder="New section title"/>
|
||||
@ -2206,29 +2195,58 @@
|
||||
|
||||
function saveSectionEdit() {
|
||||
if (floGlobals.isSubAdmin) {
|
||||
const newSections = []
|
||||
getRef('section_list_container').querySelectorAll('.section-card--new').forEach(section => {
|
||||
const newArticleTitle = getRef('edit_article_title').value.trim()
|
||||
if (newArticleTitle !== '') {
|
||||
if (floGlobals.appObjects.cc.articleList[floGlobals.currentArticle.id].title !== newArticleTitle) {
|
||||
floGlobals.appObjects.cc.articleList[floGlobals.currentArticle.id].title = newArticleTitle
|
||||
floCloudAPI.updateObjectData('cc')
|
||||
.then((res) => {
|
||||
getRef('current_article_title').textContent = newArticleTitle
|
||||
notify('Renamed article', 'success')
|
||||
}).catch(err => {
|
||||
notify(err, 'error')
|
||||
})
|
||||
|
||||
}
|
||||
} else {
|
||||
getRef('edit_article_title').value = floGlobals.appObjects.cc.articleList[floGlobals.currentArticle.id].title
|
||||
}
|
||||
const changedSections = [];
|
||||
[...getRef('section_list_container').children].forEach(section => {
|
||||
const title = section.querySelector('input').value.trim()
|
||||
const sectionID = section.dataset.sectionId
|
||||
if (title !== '')
|
||||
newSections.push({
|
||||
id: floCrypto.randString(16, true),
|
||||
changedSections.push({
|
||||
id: sectionID || floCrypto.randString(16, true),
|
||||
title
|
||||
})
|
||||
})
|
||||
if (newSections.length) {
|
||||
newSections.forEach(elem => {
|
||||
floGlobals.appObjects[floGlobals.currentArticle.id].sections.push(elem)
|
||||
})
|
||||
const didAddSection = changedSections.length > floGlobals.appObjects[floGlobals.currentArticle.id].sections.length
|
||||
let didTitlesChange = false
|
||||
if (!didAddSection) {
|
||||
didTitlesChange = floGlobals.appObjects[floGlobals.currentArticle.id].sections.some(({ title }, index) => title !== changedSections[index].title)
|
||||
}
|
||||
if (didAddSection || didTitlesChange) {
|
||||
floGlobals.appObjects[floGlobals.currentArticle.id].sections = changedSections
|
||||
floCloudAPI.updateObjectData(floGlobals.currentArticle.id)
|
||||
.then((res) => {
|
||||
const frag = document.createDocumentFragment()
|
||||
const currentSectionCount = getRef('section_list_container').querySelectorAll('.section-card:not(.section-card--new)').length
|
||||
let index = currentSectionCount
|
||||
newSections.forEach(elem => {
|
||||
render.sectionOutline()
|
||||
const frag = document.createDocumentFragment();
|
||||
const currentSections = {}
|
||||
getRef('article_wrapper').querySelectorAll('.heading').forEach(heading => {
|
||||
currentSections[heading.dataset.sectionId] = {
|
||||
title: heading.textContent,
|
||||
ref: heading
|
||||
}
|
||||
})
|
||||
changedSections.forEach(elem => {
|
||||
const { title, id } = elem
|
||||
floGlobals.currentArticle.sections[id] = { title, uniqueEntries: [] }
|
||||
frag.append(render.section(id, floGlobals.currentArticle.sections[id], index))
|
||||
index += 1
|
||||
if (currentSections.hasOwnProperty(id)) {
|
||||
currentSections[id].ref.textContent = title
|
||||
} else {
|
||||
floGlobals.currentArticle.sections[id] = { title, uniqueEntries: [] }
|
||||
frag.append(render.section(id, floGlobals.currentArticle.sections[id]))
|
||||
}
|
||||
})
|
||||
getRef('article_wrapper').append(frag)
|
||||
notify('Sections updated', 'success')
|
||||
|
||||
Loading…
Reference in New Issue
Block a user