Feature and performance update
-- Added content scoring with mark feature -- Improved performance of version history rendering by eliminating unchanged text from history entry
This commit is contained in:
parent
18d9de223f
commit
0441960eb9
@ -1835,7 +1835,6 @@ stripSelect.innerHTML = `
|
|||||||
--accent-color: #4d2588;
|
--accent-color: #4d2588;
|
||||||
--text-color: 17, 17, 17;
|
--text-color: 17, 17, 17;
|
||||||
--background-color: 255, 255, 255;
|
--background-color: 255, 255, 255;
|
||||||
--gap: 0.5rem;
|
|
||||||
padding: 1rem 0;
|
padding: 1rem 0;
|
||||||
}
|
}
|
||||||
.hide{
|
.hide{
|
||||||
@ -1855,13 +1854,13 @@ stripSelect.innerHTML = `
|
|||||||
:host([multiline]) .strip-select{
|
:host([multiline]) .strip-select{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0.5rem;
|
gap: var(--gap, 0.5rem);
|
||||||
overflow: auto hidden;
|
overflow: auto hidden;
|
||||||
}
|
}
|
||||||
:host(:not([multiline])) .strip-select{
|
:host(:not([multiline])) .strip-select{
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
gap: var(--gap);
|
gap: var(--gap, 0.5rem);
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
overflow: auto hidden;
|
overflow: auto hidden;
|
||||||
@ -2099,10 +2098,7 @@ stripOption.innerHTML = `
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
:host{
|
:host{
|
||||||
--border-radius: 2rem;
|
|
||||||
--background-color: inherit;
|
--background-color: inherit;
|
||||||
--active-option-color: inherit;
|
|
||||||
--active-option-background-color: rgba(var(--text-color), .2);
|
|
||||||
}
|
}
|
||||||
.strip-option{
|
.strip-option{
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -2111,12 +2107,12 @@ stripOption.innerHTML = `
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
padding: var(--padding, 0.4rem 0.6rem);
|
padding: var(--padding, 0.4rem 0.6rem);
|
||||||
transition: background 0.3s;
|
transition: background 0.3s;
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius, 2rem);
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
}
|
}
|
||||||
:host([active]) .strip-option{
|
:host([active]) .strip-option{
|
||||||
color: var(--active-option-color);
|
color: var(--active-option-color, inherit);
|
||||||
background-color: var(--active-option-background-color);
|
background-color: var(--active-background-color, rgba(var(--text-color), 0.06));
|
||||||
}
|
}
|
||||||
:host(:focus-within){
|
:host(:focus-within){
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|||||||
38
css/main.css
38
css/main.css
@ -479,6 +479,16 @@ strip-option {
|
|||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strip-select {
|
||||||
|
--gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
strip-option {
|
||||||
|
font-weight: 500;
|
||||||
|
--border-radius: 0.3rem;
|
||||||
|
--active-option-color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
sm-checkbox {
|
sm-checkbox {
|
||||||
--height: 1rem;
|
--height: 1rem;
|
||||||
--width: 1rem;
|
--width: 1rem;
|
||||||
@ -873,6 +883,34 @@ sm-copy {
|
|||||||
border-radius: 0.3rem;
|
border-radius: 0.3rem;
|
||||||
padding: 0.2rem 0.3rem;
|
padding: 0.2rem 0.3rem;
|
||||||
color: rgba(var(--text-color), 0.8);
|
color: rgba(var(--text-color), 0.8);
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content__author {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.3rem;
|
||||||
|
grid-template-columns: auto -webkit-max-content;
|
||||||
|
grid-template-columns: auto max-content;
|
||||||
|
}
|
||||||
|
.content__author div:first-of-type {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.content__author div:last-of-type {
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-ms-flex: 1;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content__score {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin-left: 0.2rem;
|
||||||
|
line-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filled-star {
|
||||||
|
fill: var(--yellow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.actionable-button {
|
.actionable-button {
|
||||||
|
|||||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -417,6 +417,14 @@ sm-option,
|
|||||||
strip-option{
|
strip-option{
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
strip-select{
|
||||||
|
--gap: 0;
|
||||||
|
}
|
||||||
|
strip-option{
|
||||||
|
font-weight: 500;
|
||||||
|
--border-radius: 0.3rem;
|
||||||
|
--active-option-color: var(--accent-color);
|
||||||
|
}
|
||||||
sm-checkbox {
|
sm-checkbox {
|
||||||
--height: 1rem;
|
--height: 1rem;
|
||||||
--width: 1rem;
|
--width: 1rem;
|
||||||
@ -756,6 +764,28 @@ sm-copy {
|
|||||||
border-radius: 0.3rem;
|
border-radius: 0.3rem;
|
||||||
padding: 0.2rem 0.3rem;
|
padding: 0.2rem 0.3rem;
|
||||||
color: rgba(var(--text-color), 0.8);
|
color: rgba(var(--text-color), 0.8);
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
.content__author{
|
||||||
|
display: grid;
|
||||||
|
gap: 0.3rem;
|
||||||
|
grid-template-columns: auto max-content;
|
||||||
|
div:first-of-type{
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
div:last-of-type{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.content__score{
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin-left: 0.2rem;
|
||||||
|
line-height: 100%;
|
||||||
|
}
|
||||||
|
.filled-star{
|
||||||
|
fill: var(--yellow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.actionable-button {
|
.actionable-button {
|
||||||
|
|||||||
197
index.html
197
index.html
@ -590,6 +590,30 @@
|
|||||||
<sm-button class="danger" onclick="signOut()">Sign out</sm-button>
|
<sm-button class="danger" onclick="signOut()">Sign out</sm-button>
|
||||||
</section>
|
</section>
|
||||||
</sm-popup>
|
</sm-popup>
|
||||||
|
<sm-popup id="scoring_popup">
|
||||||
|
<header slot="header" class="popup__header">
|
||||||
|
<button class="popup__header__close" onclick="hidePopup()">
|
||||||
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||||
|
fill="#000000">
|
||||||
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||||
|
<path
|
||||||
|
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>Update score</h3>
|
||||||
|
</header>
|
||||||
|
<sm-form>
|
||||||
|
<sm-input id="update_score_field" class="outlined" placeholder="Score" type="number" step="0.1" min="1"
|
||||||
|
max="100" error-text="Value must be between 1-100" autofocus animate required hiderequired></sm-input>
|
||||||
|
<div id="inc_section" class="flex">
|
||||||
|
<button class="button" onclick="incScore(0.1)">+ 0.1</button>
|
||||||
|
<button class="button" onclick="incScore(1)">+ 1</button>
|
||||||
|
<button class="button" onclick="incScore(5)">+ 5</button>
|
||||||
|
<sm-button id="get_new_score" variant="primary" class="justify-right" onclick="updateScore()" disabled>
|
||||||
|
Update</sm-button>
|
||||||
|
</div>
|
||||||
|
</sm-form>
|
||||||
|
</sm-popup>
|
||||||
<template id="contributor_template">
|
<template id="contributor_template">
|
||||||
<div class="contributor grid">
|
<div class="contributor grid">
|
||||||
<svg class="icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg class="icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
@ -622,7 +646,7 @@
|
|||||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
d="M14.6243 7.99154C13.9395 8.14279 13.4165 8.69672 13.3047 9.38904C13.2248 9.88365 13.3664 10.3773 13.6735 10.7498L9.29125 15.0941C8.93718 15.4451 8.48852 15.6853 8.00011 15.7854L6.12418 16.1699L9.19811 13.1381C9.53438 12.8064 9.53812 12.265 9.20646 11.9287C8.8748 11.5924 8.33333 11.5887 7.99706 11.9203L4.97835 14.8977L5.47976 12.451C5.50451 12.3303 5.55656 12.2168 5.63191 12.1192L6.49083 11.0073C9.58386 7.00317 14.32 4.72705 19.2553 4.71054L16.3569 7.60884L14.6243 7.99154ZM2.79008 17.0559L3.8042 12.1076C3.88132 11.7313 4.0435 11.3776 4.27833 11.0736L5.13724 9.96172C8.89964 5.09105 14.861 2.53305 20.8954 3.07051C21.5971 3.133 22.2997 3.23735 23 3.38478L17.2133 9.1713L14.9932 9.66167L15.4238 9.91837C15.9039 10.2046 15.9849 10.8668 15.588 11.2603L10.4954 16.3088C9.90529 16.8938 9.15752 17.2941 8.34351 17.461L3.88965 18.3738L2.45572 19.788C2.11945 20.1197 1.57798 20.116 1.24632 19.7797C0.91466 19.4434 0.918397 18.9019 1.25467 18.5703L2.79008 17.0559Z" />
|
d="M14.6243 7.99154C13.9395 8.14279 13.4165 8.69672 13.3047 9.38904C13.2248 9.88365 13.3664 10.3773 13.6735 10.7498L9.29125 15.0941C8.93718 15.4451 8.48852 15.6853 8.00011 15.7854L6.12418 16.1699L9.19811 13.1381C9.53438 12.8064 9.53812 12.265 9.20646 11.9287C8.8748 11.5924 8.33333 11.5887 7.99706 11.9203L4.97835 14.8977L5.47976 12.451C5.50451 12.3303 5.55656 12.2168 5.63191 12.1192L6.49083 11.0073C9.58386 7.00317 14.32 4.72705 19.2553 4.71054L16.3569 7.60884L14.6243 7.99154ZM2.79008 17.0559L3.8042 12.1076C3.88132 11.7313 4.0435 11.3776 4.27833 11.0736L5.13724 9.96172C8.89964 5.09105 14.861 2.53305 20.8954 3.07051C21.5971 3.133 22.2997 3.23735 23 3.38478L17.2133 9.1713L14.9932 9.66167L15.4238 9.91837C15.9039 10.2046 15.9849 10.8668 15.588 11.2603L10.4954 16.3088C9.90529 16.8938 9.15752 17.2941 8.34351 17.461L3.88965 18.3738L2.45572 19.788C2.11945 20.1197 1.57798 20.116 1.24632 19.7797C0.91466 19.4434 0.918397 18.9019 1.25467 18.5703L2.79008 17.0559Z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span class="content__author"></span>
|
<div class="content__author flex align-center"></div>
|
||||||
</Button>
|
</Button>
|
||||||
<sm-checkbox class="content__checkbox" aria-label="Select content"></sm-checkbox>
|
<sm-checkbox class="content__checkbox" aria-label="Select content"></sm-checkbox>
|
||||||
</div>
|
</div>
|
||||||
@ -637,15 +661,6 @@
|
|||||||
d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.25 2.52.77-1.28-3.52-2.09V8z" />
|
d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.25 2.52.77-1.28-3.52-2.09V8z" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button title="Give score">
|
|
||||||
<svg class="icon button__icon--left" xmlns="http://www.w3.org/2000/svg" height="24px"
|
|
||||||
viewBox="0 0 24 24" width="24px" fill="#000000">
|
|
||||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
|
||||||
<path
|
|
||||||
d="M12 7.13l.97 2.29.47 1.11 1.2.1 2.47.21-1.88 1.63-.91.79.27 1.18.56 2.41-2.12-1.28-1.03-.64-1.03.62-2.12 1.28.56-2.41.27-1.18-.91-.79-1.88-1.63 2.47-.21 1.2-.1.47-1.11.97-2.27M12 2L9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2z" />
|
|
||||||
</svg>
|
|
||||||
<span class="content__score">0</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="submit-entry hide-completely">Submit</button>
|
<button class="submit-entry hide-completely">Submit</button>
|
||||||
</div>
|
</div>
|
||||||
@ -655,7 +670,6 @@
|
|||||||
<li class="history-entry grid gap-1">
|
<li class="history-entry grid gap-1">
|
||||||
<div class="flex align-center space-between">
|
<div class="flex align-center space-between">
|
||||||
<time class="entry__time"></time>
|
<time class="entry__time"></time>
|
||||||
<span class="entry__score"></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div class="label flex align-center">
|
<div class="label flex align-center">
|
||||||
@ -1215,7 +1229,8 @@
|
|||||||
floGlobals.appObjects[uid] = {
|
floGlobals.appObjects[uid] = {
|
||||||
public: true,
|
public: true,
|
||||||
editors: [],
|
editors: [],
|
||||||
sections
|
sections,
|
||||||
|
preview: {}
|
||||||
}
|
}
|
||||||
Promise.all([
|
Promise.all([
|
||||||
floCloudAPI.updateObjectData('cc'),
|
floCloudAPI.updateObjectData('cc'),
|
||||||
@ -1310,14 +1325,19 @@
|
|||||||
submitButton.disabled = true
|
submitButton.disabled = true
|
||||||
floCloudAPI.sendGeneralData(entry, `${floGlobals.currentArticle.id}_gd`)
|
floCloudAPI.sendGeneralData(entry, `${floGlobals.currentArticle.id}_gd`)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
console.log(res)
|
let genDataVC
|
||||||
|
// Add result to general data
|
||||||
|
for (genDataVC in res) {
|
||||||
|
floGlobals.generalData[`${floGlobals.currentArticle.id}_gd|${floGlobals.adminID}|${floGlobals.application}`][genDataVC] = res[genDataVC]
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(genDataVC)
|
||||||
submitButton.classList.add('hide-completely')
|
submitButton.classList.add('hide-completely')
|
||||||
notify('sent data', 'success')
|
notify('sent data', 'success')
|
||||||
const iterationData = { ...entry, timestamp, editor: myFloID }
|
|
||||||
if (isUniqueEntry) {
|
if (isUniqueEntry) {
|
||||||
contentArea.innerHTML = ''
|
contentArea.innerHTML = ''
|
||||||
floGlobals.currentArticle.sections[sectionID].uniqueEntries.push(entry.origin)
|
floGlobals.currentArticle.sections[sectionID].uniqueEntries.push(entry.origin)
|
||||||
floGlobals.currentArticle.uniqueEntries[entry.origin] = { iterations: [iterationData] }
|
floGlobals.currentArticle.uniqueEntries[entry.origin] = { iterations: [genDataVC] }
|
||||||
// Insert new content card based on set filter
|
// Insert new content card based on set filter
|
||||||
const newCard = render.contentCard(entry.origin)
|
const newCard = render.contentCard(entry.origin)
|
||||||
if (getRef('sort_content_list').value === 'time') {
|
if (getRef('sort_content_list').value === 'time') {
|
||||||
@ -1360,7 +1380,7 @@
|
|||||||
if (noOfContributors < 2) {
|
if (noOfContributors < 2) {
|
||||||
contentCard.querySelector('.content__author').textContent = `2 Contributors`
|
contentCard.querySelector('.content__author').textContent = `2 Contributors`
|
||||||
}
|
}
|
||||||
floGlobals.currentArticle.uniqueEntries[entry.origin].iterations.push(iterationData)
|
floGlobals.currentArticle.uniqueEntries[entry.origin].iterations.push(genDataVC)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(err => console.log(err))
|
.catch(err => console.log(err))
|
||||||
@ -1373,7 +1393,7 @@
|
|||||||
}
|
}
|
||||||
} else if (e.target.closest('.version-history-button')) {
|
} else if (e.target.closest('.version-history-button')) {
|
||||||
const entryUid = e.target.closest('.content-card').dataset.uid
|
const entryUid = e.target.closest('.content-card').dataset.uid
|
||||||
if (versionHistory.isOpen && entryUid === versionHistory.entryUid)
|
if (floGlobals.versionHistory.isOpen && entryUid === floGlobals.versionHistory.entryUid)
|
||||||
hideVersionHistory()
|
hideVersionHistory()
|
||||||
else
|
else
|
||||||
showVersionHistory(entryUid)
|
showVersionHistory(entryUid)
|
||||||
@ -1409,6 +1429,17 @@
|
|||||||
})
|
})
|
||||||
floGlobals.currentArticle.sections[sectionID].expanded = true
|
floGlobals.currentArticle.sections[sectionID].expanded = true
|
||||||
}
|
}
|
||||||
|
} else if (e.target.closest('.score-button') && isSubAdmin) {
|
||||||
|
floGlobals.versionHistory.currentEntry = e.target.closest('.content-card').dataset.vectorClock
|
||||||
|
getRef('update_score_field').value = e.target.closest('.score-button').children[1].textContent
|
||||||
|
showPopup('scoring_popup')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
getRef('version_timeline').addEventListener('click', e => {
|
||||||
|
if (e.target.closest('.score-button') && isSubAdmin) {
|
||||||
|
floGlobals.versionHistory.currentEntry = e.target.closest('.history-entry').dataset.vectorClock
|
||||||
|
getRef('update_score_field').value = e.target.closest('.score-button').children[1].textContent
|
||||||
|
showPopup('scoring_popup')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
getRef('article_wrapper').addEventListener("paste", e => {
|
getRef('article_wrapper').addEventListener("paste", e => {
|
||||||
@ -1606,7 +1637,7 @@
|
|||||||
}
|
}
|
||||||
function sharePreview() {
|
function sharePreview() {
|
||||||
if (isSubAdmin) {
|
if (isSubAdmin) {
|
||||||
if (floGlobals.appObjects[pagesData.params.articleID].preview) {
|
if (floGlobals.appObjects[pagesData.params.articleID]?.preview?.id) {
|
||||||
floGlobals.appObjects[pagesData.params.articleID].preview.content = DOMPurify.sanitize(getRef('preview__body').innerHTML)
|
floGlobals.appObjects[pagesData.params.articleID].preview.content = DOMPurify.sanitize(getRef('preview__body').innerHTML)
|
||||||
} else {
|
} else {
|
||||||
floGlobals.appObjects[pagesData.params.articleID].preview = {
|
floGlobals.appObjects[pagesData.params.articleID].preview = {
|
||||||
@ -1757,6 +1788,31 @@
|
|||||||
function formatDoc(sCmd, sValue) {
|
function formatDoc(sCmd, sValue) {
|
||||||
document.execCommand(sCmd, false, sValue);
|
document.execCommand(sCmd, false, sValue);
|
||||||
}
|
}
|
||||||
|
function incScore(value) {
|
||||||
|
let currentScore = parseFloat(getRef('update_score_field').value)
|
||||||
|
if (!currentScore) {
|
||||||
|
currentScore = 0
|
||||||
|
}
|
||||||
|
if (currentScore + value <= 100) {
|
||||||
|
currentScore += value;
|
||||||
|
getRef('update_score_field').value = parseFloat(currentScore.toFixed(1))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
notify(`You can't give score more than 100.`, 'error')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function updateScore() {
|
||||||
|
const newScore = parseFloat(getRef('update_score_field').value)
|
||||||
|
const mark = {
|
||||||
|
[floGlobals.versionHistory.currentEntry]: newScore
|
||||||
|
}
|
||||||
|
scores[floGlobals.versionHistory.currentEntry] = newScore
|
||||||
|
document.querySelectorAll(`[data-vector-clock="${floGlobals.versionHistory.currentEntry}"] .content__score`).forEach(scoreElem => scoreElem.textContent = newScore)
|
||||||
|
floCloudAPI.markApplicationData(mark).then(res => {
|
||||||
|
notify('Score updated', 'success')
|
||||||
|
hidePopup()
|
||||||
|
}).catch(err => notify(err, 'error'))
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
floGlobals.currentArticle = {}
|
floGlobals.currentArticle = {}
|
||||||
@ -1797,6 +1853,28 @@
|
|||||||
}
|
}
|
||||||
mobileQuery.addListener(handleMobileChange)
|
mobileQuery.addListener(handleMobileChange)
|
||||||
handleMobileChange(mobileQuery)
|
handleMobileChange(mobileQuery)
|
||||||
|
function getScoreElement(score) {
|
||||||
|
let scoreElement
|
||||||
|
if (isSubAdmin) {
|
||||||
|
scoreElement = createElement('button', {
|
||||||
|
className: 'score-button',
|
||||||
|
attributes: { 'title': 'Score this content' }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
scoreElement = createElement('div', {
|
||||||
|
className: 'flex align-center',
|
||||||
|
attributes: { 'title': 'Score' }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
scoreElement.innerHTML = `
|
||||||
|
${score ?
|
||||||
|
`<svg class="icon filled-star" 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="M0,0h24v24H0V0z" fill="none"/><path d="M0,0h24v24H0V0z" fill="none"/></g><g><path d="M12,17.27L18.18,21l-1.64-7.03L22,9.24l-7.19-0.61L12,2L9.19,8.63L2,9.24l5.46,4.73L5.82,21L12,17.27z"/></g></svg> ` :
|
||||||
|
`<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <path d="M0 0h24v24H0V0z" fill="none" /> <path d="M12 7.13l.97 2.29.47 1.11 1.2.1 2.47.21-1.88 1.63-.91.79.27 1.18.56 2.41-2.12-1.28-1.03-.64-1.03.62-2.12 1.28.56-2.41.27-1.18-.91-.79-1.88-1.63 2.47-.21 1.2-.1.47-1.11.97-2.27M12 2L9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2z" /> </svg>`
|
||||||
|
}
|
||||||
|
<div class="content__score">${score}</div>
|
||||||
|
`
|
||||||
|
return scoreElement
|
||||||
|
}
|
||||||
const render = {
|
const render = {
|
||||||
article(id) {
|
article(id) {
|
||||||
floGlobals.currentArticle.id = id
|
floGlobals.currentArticle.id = id
|
||||||
@ -1841,32 +1919,30 @@
|
|||||||
return link
|
return link
|
||||||
},
|
},
|
||||||
contentCard(id, version = 0) {
|
contentCard(id, version = 0) {
|
||||||
const { data, contributors, score = 0 } = getIterationDetails(id)
|
const { data, contributors, score = 0, vectorClock } = getIterationDetails(id)
|
||||||
const clone = getRef('content_card_template').content.cloneNode(true).firstElementChild;
|
const clone = getRef('content_card_template').content.cloneNode(true).firstElementChild;
|
||||||
clone.dataset.uid = id
|
clone.dataset.uid = id
|
||||||
|
clone.dataset.vectorClock = vectorClock
|
||||||
if (!isSubAdmin) {
|
if (!isSubAdmin) {
|
||||||
clone.querySelector('.content__area').setAttribute('contentEditable', true)
|
clone.querySelector('.content__area').setAttribute('contentEditable', true)
|
||||||
}
|
}
|
||||||
clone.querySelector('.content__area').innerHTML = DOMPurify.sanitize(data)
|
clone.querySelector('.content__area').innerHTML = DOMPurify.sanitize(data)
|
||||||
let noOfContributors = 0
|
let noOfContributors = 0
|
||||||
let firstContributor
|
let latestContributor
|
||||||
for (const contributor in contributors) {
|
for (const contributor in contributors) {
|
||||||
noOfContributors++
|
noOfContributors++
|
||||||
if (noOfContributors === 1)
|
latestContributor = contributor
|
||||||
firstContributor = contributor
|
|
||||||
}
|
}
|
||||||
if (noOfContributors === 1) {
|
clone.querySelector('.content__author').innerHTML = `<div>${latestContributor}</div> ${noOfContributors === 1 ? '' : `<div> and ${noOfContributors - 1} more`}</div>`
|
||||||
clone.querySelector('.content__author').textContent = firstContributor
|
clone.querySelector('.content__options').append(getScoreElement(score));
|
||||||
} else {
|
|
||||||
clone.querySelector('.content__author').textContent = `${noOfContributors} contributors`
|
|
||||||
}
|
|
||||||
clone.querySelector('.content__score').textContent = score;
|
|
||||||
return clone
|
return clone
|
||||||
},
|
},
|
||||||
historyEntry(details, oldText) {
|
historyEntry(details, oldText) {
|
||||||
const { editor, timestamp, data } = details
|
const { editor, timestamp, data, score, vectorClock } = details
|
||||||
const clone = getRef('history_entry_template').content.cloneNode(true).firstElementChild;
|
const clone = getRef('history_entry_template').content.cloneNode(true).firstElementChild;
|
||||||
|
clone.dataset.vectorClock = vectorClock
|
||||||
clone.querySelector('.entry__time').textContent = getFormattedTime(timestamp)
|
clone.querySelector('.entry__time').textContent = getFormattedTime(timestamp)
|
||||||
|
clone.querySelector('.entry__time').after(getScoreElement(score))
|
||||||
clone.querySelector('.entry__author').textContent = editor
|
clone.querySelector('.entry__author').textContent = editor
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
const [removedAt, addedWords, addedAt] = data
|
const [removedAt, addedWords, addedAt] = data
|
||||||
@ -1892,7 +1968,12 @@
|
|||||||
}
|
}
|
||||||
} else return word
|
} else return word
|
||||||
})
|
})
|
||||||
clone.querySelector('.entry__changes').innerHTML = DOMPurify.sanitize(final.join(' '))
|
clone.querySelector('.entry__changes').innerHTML = DOMPurify.sanitize(final.join(' '));
|
||||||
|
[...clone.querySelector('.entry__changes').children].forEach(element => {
|
||||||
|
if (element.tagName === 'P' && !element.querySelector('.added, .removed')) {
|
||||||
|
element.remove()
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
clone.querySelector('.entry__changes').innerHTML = DOMPurify.sanitize(data)
|
clone.querySelector('.entry__changes').innerHTML = DOMPurify.sanitize(data)
|
||||||
}
|
}
|
||||||
@ -1952,29 +2033,42 @@
|
|||||||
})
|
})
|
||||||
floGlobals.currentArticle['uniqueEntries'] = {}
|
floGlobals.currentArticle['uniqueEntries'] = {}
|
||||||
for (const key in generalData) {
|
for (const key in generalData) {
|
||||||
const { message: { section, data, origin, hash }, senderID } = generalData[key]
|
const { section, origin } = generalData[key].message
|
||||||
if (!floGlobals.currentArticle.uniqueEntries.hasOwnProperty(origin)) { // check if general data has origin that's already defined
|
if (!floGlobals.currentArticle.uniqueEntries.hasOwnProperty(origin)) { // check if general data has origin that's already defined
|
||||||
floGlobals.currentArticle.uniqueEntries[origin] = {
|
floGlobals.currentArticle.uniqueEntries[origin] = {
|
||||||
iterations: []
|
iterations: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
floGlobals.currentArticle.sections[section].uniqueEntries.add(origin)
|
floGlobals.currentArticle.sections[section].uniqueEntries.add(origin)
|
||||||
floGlobals.currentArticle.uniqueEntries[origin]['iterations'].push({
|
floGlobals.currentArticle.uniqueEntries[origin]['iterations'].push(generalData[key].vectorClock)
|
||||||
timestamp: generalData[key].time,
|
|
||||||
data,
|
|
||||||
editor: senderID,
|
|
||||||
hash,
|
|
||||||
score: floCrypto.randInt(0, 100) // to do: get score from mark feature
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
for (const sectionID in floGlobals.currentArticle.sections) {
|
for (const sectionID in floGlobals.currentArticle.sections) {
|
||||||
floGlobals.currentArticle.sections[sectionID].uniqueEntries = [...floGlobals.currentArticle.sections[sectionID].uniqueEntries].reverse()
|
floGlobals.currentArticle.sections[sectionID].uniqueEntries = [...floGlobals.currentArticle.sections[sectionID].uniqueEntries].reverse()
|
||||||
}
|
}
|
||||||
for (const entry in floGlobals.currentArticle.uniqueEntries) {
|
for (const entry in floGlobals.currentArticle.uniqueEntries) {
|
||||||
floGlobals.currentArticle.uniqueEntries[entry]['iterations'].sort((a, b) => a.timestamp - b.timestamp)
|
floGlobals.currentArticle.uniqueEntries[entry]['iterations'].sort((a, b) => getGenData(a).timestamp - getGenData(b).timestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getGenData(vectorClock) {
|
||||||
|
const { message: { section, origin, data, hash }, senderID, time } = floGlobals.generalData[`${floGlobals.currentArticle.id}_gd|${floGlobals.adminID}|${floGlobals.application}`][vectorClock]
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
editor: senderID,
|
||||||
|
timestamp: time,
|
||||||
|
vectorClock,
|
||||||
|
score: getScore(vectorClock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const scores = {}
|
||||||
|
function getScore(vc) {
|
||||||
|
if (!scores[vc])
|
||||||
|
scores[vc] = floCrypto.randInt(0, 100)
|
||||||
|
return scores[vc]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let currentOptionsPanel = ''
|
let currentOptionsPanel = ''
|
||||||
function toggleOptionsPanel(type) {
|
function toggleOptionsPanel(type) {
|
||||||
const animInOptions = {
|
const animInOptions = {
|
||||||
@ -2062,7 +2156,7 @@
|
|||||||
floGlobals.currentArticle.sections[sectionID].uniqueEntries.sort((a, b) => {
|
floGlobals.currentArticle.sections[sectionID].uniqueEntries.sort((a, b) => {
|
||||||
const arrayA = floGlobals.currentArticle.uniqueEntries[a].iterations
|
const arrayA = floGlobals.currentArticle.uniqueEntries[a].iterations
|
||||||
const arrayB = floGlobals.currentArticle.uniqueEntries[b].iterations
|
const arrayB = floGlobals.currentArticle.uniqueEntries[b].iterations
|
||||||
return arrayB[arrayB.length - 1][sortByScore ? 'score' : 'timestamp'] - arrayA[arrayA.length - 1][sortByScore ? 'score' : 'timestamp']
|
return getGenData(arrayB[arrayB.length - 1])[sortByScore ? 'score' : 'timestamp'] - getGenData(arrayA[arrayA.length - 1])[sortByScore ? 'score' : 'timestamp']
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for (const sectionID in floGlobals.currentArticle.sections) {
|
for (const sectionID in floGlobals.currentArticle.sections) {
|
||||||
@ -2213,45 +2307,48 @@
|
|||||||
const contributors = {}
|
const contributors = {}
|
||||||
const limit = targetIndex || floGlobals.currentArticle.uniqueEntries[uid].iterations.length - 1
|
const limit = targetIndex || floGlobals.currentArticle.uniqueEntries[uid].iterations.length - 1
|
||||||
for (let i = 0; i <= limit; i++) {
|
for (let i = 0; i <= limit; i++) {
|
||||||
const { data, editor, timestamp } = floGlobals.currentArticle.uniqueEntries[uid].iterations[i]
|
const { data, editor, timestamp } = getGenData(floGlobals.currentArticle.uniqueEntries[uid].iterations[i])
|
||||||
merged = i ? updateString(merged, data) : data
|
merged = i ? updateString(merged, data) : data
|
||||||
contributors[editor] = timestamp
|
contributors[editor] = timestamp
|
||||||
}
|
}
|
||||||
|
const { hash, score } = getGenData(floGlobals.currentArticle.uniqueEntries[uid].iterations[limit]);
|
||||||
return {
|
return {
|
||||||
data: merged,
|
data: merged,
|
||||||
contributors,
|
contributors,
|
||||||
hash: floGlobals.currentArticle.uniqueEntries[uid].iterations[limit].hash,
|
hash,
|
||||||
score: floGlobals.currentArticle.uniqueEntries[uid].iterations[limit].score
|
score,
|
||||||
|
vectorClock: floGlobals.currentArticle.uniqueEntries[uid].iterations[limit]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const versionHistory = {
|
floGlobals.versionHistory = {
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
entryUid: ''
|
entryUid: ''
|
||||||
}
|
}
|
||||||
function showVersionHistory(uid) {
|
function showVersionHistory(uid) {
|
||||||
versionHistory.entryUid = uid
|
floGlobals.versionHistory.entryUid = uid
|
||||||
const { iterations } = floGlobals.currentArticle.uniqueEntries[uid]
|
const { iterations } = floGlobals.currentArticle.uniqueEntries[uid]
|
||||||
const frag = document.createDocumentFragment()
|
const frag = document.createDocumentFragment()
|
||||||
let mergedChanges
|
let mergedChanges
|
||||||
iterations.forEach((iter, index) => {
|
iterations.forEach((vectorClock, index) => {
|
||||||
|
const iter = getGenData(vectorClock)
|
||||||
frag.prepend(render.historyEntry(iter, mergedChanges))
|
frag.prepend(render.historyEntry(iter, mergedChanges))
|
||||||
mergedChanges = index ? updateString(mergedChanges, iter.data) : iter.data
|
mergedChanges = index ? updateString(mergedChanges, iter.data) : iter.data
|
||||||
})
|
})
|
||||||
getRef('version_timeline').innerHTML = ''
|
getRef('version_timeline').innerHTML = ''
|
||||||
getRef('version_timeline').append(frag)
|
getRef('version_timeline').append(frag)
|
||||||
if (!versionHistory.isOpen) {
|
if (!floGlobals.versionHistory.isOpen) {
|
||||||
getRef('version_history_panel').classList.remove('hide-completely')
|
getRef('version_history_panel').classList.remove('hide-completely')
|
||||||
getRef('main_page').classList.add('active-sidebar')
|
getRef('main_page').classList.add('active-sidebar')
|
||||||
versionHistory.isOpen = true
|
floGlobals.versionHistory.isOpen = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideVersionHistory() {
|
function hideVersionHistory() {
|
||||||
if (versionHistory.isOpen) {
|
if (floGlobals.versionHistory.isOpen) {
|
||||||
getRef('version_history_panel').classList.add('hide-completely')
|
getRef('version_history_panel').classList.add('hide-completely')
|
||||||
getRef('version_timeline').innerHTML = ''
|
getRef('version_timeline').innerHTML = ''
|
||||||
getRef('main_page').classList.remove('active-sidebar')
|
getRef('main_page').classList.remove('active-sidebar')
|
||||||
versionHistory.isOpen = false
|
floGlobals.versionHistory.isOpen = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user