diff --git a/controllers/book/chapter/edit/get.js b/controllers/book/chapter/edit/get.js new file mode 100644 index 0000000..a657a53 --- /dev/null +++ b/controllers/book/chapter/edit/get.js @@ -0,0 +1,26 @@ +const Chapter = require('../../../../models/chapter/Chapter'); + +module.exports = (req, res) => { + const types = { + 'node101': res.__('node101'), + 'project': res.__('Project'), + 'terms': res.__('Terms') + }; + + Chapter.findChapterByIdAndFormat(req.query.id, (err, chapter) => { + if (err) return res.redirect('/error?message=' + err); + + return res.render('book/chapter/edit', { + page: 'book/chapter/edit', + title: chapter.name, + includes: { + external: { + css: ['confirm', 'create', 'form', 'formPopUp', 'general', 'header', 'items', 'navbar', 'navigation', 'text'], + js: ['ancestorWithClassName', 'createConfirm', 'createFormPopUp', 'form', 'navbarListeners', 'page', 'serverRequest'] + } + }, + chapter, + types + }); + }); +}; diff --git a/controllers/book/chapter/edit/post.js b/controllers/book/chapter/edit/post.js new file mode 100644 index 0000000..8ca7fd0 --- /dev/null +++ b/controllers/book/chapter/edit/post.js @@ -0,0 +1,13 @@ +const Chapter = require('../../../../models/chapter/Chapter'); + +module.exports = (req, res) => { + Chapter.findChapterByIdAndUpdate(req.query.id, req.body, err => { + if (err) { + res.write(JSON.stringify({ success: false, error: err })); + return res.end(); + } + + res.write(JSON.stringify({ success: true })); + return res.end(); + }); +}; \ No newline at end of file diff --git a/controllers/book/chapter/order/post.js b/controllers/book/chapter/order/post.js new file mode 100644 index 0000000..fd63bbd --- /dev/null +++ b/controllers/book/chapter/order/post.js @@ -0,0 +1,13 @@ +const Book = require('../../../../models/book/Book'); + +module.exports = (req, res) => { + Book.findBookByIdAndGetWritingByIdAndIncOrderByOne(req.query.id, req.body.id, err => { + if (err) { + res.write(JSON.stringify({ success: false, error: err })); + return res.end(); + } + + res.write(JSON.stringify({ success: true })); + return res.end(); + }); +}; \ No newline at end of file diff --git a/controllers/book/writing/content/get.js b/controllers/book/writing/content/get.js index 43c5e54..f53aa43 100644 --- a/controllers/book/writing/content/get.js +++ b/controllers/book/writing/content/get.js @@ -1,6 +1,6 @@ const DEFAULT_WRITING_LANGUAGE = 'en'; -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { const translations = { @@ -11,14 +11,14 @@ module.exports = (req, res) => { const translate = req.query.translate && translations[req.query.translate] ? req.query.translate : DEFAULT_WRITING_LANGUAGE; if (translate && translate != DEFAULT_WRITING_LANGUAGE) { - Blog.findBlogByIdAndFormatByLanguage(req.query.id, translate, (err, blog) => { + Book.findBookByIdAndFormatByLanguage(req.query.id, translate, (err, book) => { if (err) return res.redirect('/error?message=' + err); - Blog.findBlogByIdAndGetWritingByIdAndFormatByLanguage(req.query.id, req.query.writing_id, translate, (err, writing) => { + Book.findBookByIdAndGetWritingByIdAndFormatByLanguage(req.query.id, req.query.writing_id, translate, (err, writing) => { if (err) return res.redirect('/error?message=' + err); - return res.render('blog/writing/content', { - page: 'blog/writing/content', + return res.render('book/writing/content', { + page: 'book/writing/content', title: `${res.__('Edit Writing')} - ${writing.title}`, includes: { external: { @@ -27,21 +27,21 @@ module.exports = (req, res) => { } }, translations, - blog, + book, writing, translate }); }); }); } else { - Blog.findBlogByIdAndFormat(req.query.id, (err, blog) => { + Book.findBookByIdAndFormat(req.query.id, (err, book) => { if (err) return res.redirect('/error?message=' + err); - Blog.findBlogByIdAndGetWritingByIdAndFormat(req.query.id, req.query.writing_id, (err, writing) => { + Book.findBookByIdAndGetWritingByIdAndFormat(req.query.id, req.query.writing_id, (err, writing) => { if (err) return res.redirect('/error?message=' + err); - return res.render('blog/writing/content', { - page: 'blog/writing/content', + return res.render('book/writing/content', { + page: 'book/writing/content', title: `${res.__('Edit Writing')} - ${writing.title}`, includes: { external: { @@ -50,7 +50,7 @@ module.exports = (req, res) => { } }, translations, - blog, + book, writing, translate: DEFAULT_WRITING_LANGUAGE }); diff --git a/controllers/book/writing/cover-translate/post.js b/controllers/book/writing/cover-translate/post.js index 38b96d1..32cc70b 100644 --- a/controllers/book/writing/cover-translate/post.js +++ b/controllers/book/writing/cover-translate/post.js @@ -1,7 +1,7 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { - Blog.findBlogByIdAndGetWritingByIdAndUpdateCoverTranslation(req.query.id, req.query.writing_id, req.query.language, req.file, (err, url) => { + Book.findBookByIdAndGetWritingByIdAndUpdateCoverTranslation(req.query.id, req.query.writing_id, req.query.language, req.file, (err, url) => { if (err) { res.write(JSON.stringify({ success: false, error: err })); return res.end(); diff --git a/controllers/book/writing/cover/post.js b/controllers/book/writing/cover/post.js index 049d19c..615e06e 100644 --- a/controllers/book/writing/cover/post.js +++ b/controllers/book/writing/cover/post.js @@ -1,7 +1,7 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { - Blog.findBlogByIdAndGetWritingByIdAndUpdateCover(req.query.id, req.query.writing_id, req.file, (err, url) => { + Book.findBookByIdAndGetWritingByIdAndUpdateCover(req.query.id, req.query.writing_id, req.file, (err, url) => { if (err) { res.write(JSON.stringify({ success: false, error: err })); return res.end(); diff --git a/controllers/book/writing/create/post.js b/controllers/book/writing/create/post.js index e1486b8..594f50b 100644 --- a/controllers/book/writing/create/post.js +++ b/controllers/book/writing/create/post.js @@ -1,13 +1,26 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); +const Chapter = require('../../../../models/chapter/Chapter'); module.exports = (req, res) => { - Blog.findBlogByIdAndCreateWriting(req.query.id, req.body, (err, id) => { - if (err) { - res.write(JSON.stringify({ success: false, error: err })); + if (req.query.chapter_id) { + Chapter.findChapterByIdAndCreateWriting(req.query.chapter_id, req.body, (err, id) => { + if (err) { + res.write(JSON.stringify({ success: false, error: err })); + return res.end(); + } + + res.write(JSON.stringify({ success: true, id })); return res.end(); - } + }); + } else { + Book.findBookByIdAndCreateWriting(req.query.id, req.body, (err, id) => { + if (err) { + res.write(JSON.stringify({ success: false, error: err })); + return res.end(); + } - res.write(JSON.stringify({ success: true, id })); - return res.end(); - }); + res.write(JSON.stringify({ success: true, id })); + return res.end(); + }); + }; }; \ No newline at end of file diff --git a/controllers/book/writing/delete/get.js b/controllers/book/writing/delete/get.js index b56644b..2807973 100644 --- a/controllers/book/writing/delete/get.js +++ b/controllers/book/writing/delete/get.js @@ -1,27 +1,27 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { req.query.is_deleted = true; - Blog.findBlogByIdAndFormat(req.query.id, (err, blog) => { + Book.findBookByIdAndFormat(req.query.id, (err, book) => { if (err) return res.redirect('/error?message=' + err); - Blog.findBlogByIdAndGetWritingCountByFilters(req.query.id, req.query, (err, count) => { + Book.findBookByIdAndGetWritingCountByFilters(req.query.id, req.query, (err, count) => { if (err) return res.redirect('/error?message=' + err); - Blog.findBlogByIdAndGetWritingsByFilters(req.query.id, req.query, (err, data) => { + Book.findBookByIdAndGetWritingsByFilters(req.query.id, req.query, (err, data) => { if (err) return res.redirect('/error?message=' + err); - return res.render('blog/writing/delete', { - page: 'blog/writing/delete', - title: `${res.__('Deleted Writings')} - ${blog.title}`, + return res.render('book/writing/delete', { + page: 'book/writing/delete', + title: `${res.__('Deleted Writings')} - ${book.title}`, includes: { external: { css: ['confirm', 'form', 'formPopUp', 'general', 'header', 'items', 'navbar', 'navigation', 'page', 'text'], js: ['createConfirm', 'createFormPopUp', 'navbarListeners', 'page', 'serverRequest'] } }, - blog, + book, writings_count: count, writings_search: data.search, writings_limit: data.limit, diff --git a/controllers/book/writing/delete/post.js b/controllers/book/writing/delete/post.js index f604438..d5b1ff8 100644 --- a/controllers/book/writing/delete/post.js +++ b/controllers/book/writing/delete/post.js @@ -1,7 +1,7 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { - Blog.findBlogByIdAndGetWritingByIdAndDelete(req.query.id, req.body.id, err => { + Book.findBookByIdAndGetWritingByIdAndDelete(req.query.id, req.body.id, err => { if (err) { res.write(JSON.stringify({ success: false, error: err })); return res.end(); diff --git a/controllers/book/writing/edit/get.js b/controllers/book/writing/edit/get.js index b785779..bb029d2 100644 --- a/controllers/book/writing/edit/get.js +++ b/controllers/book/writing/edit/get.js @@ -1,4 +1,4 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { const labels = { @@ -13,14 +13,14 @@ module.exports = (req, res) => { 'spotify': 'Spotify' }; - Blog.findBlogByIdAndFormat(req.query.id, (err, blog) => { + Book.findBookByIdAndFormat(req.query.id, (err, book) => { if (err) return res.redirect('/error?message=' + err); - Blog.findBlogByIdAndGetWritingByIdAndFormat(req.query.id, req.query.writing_id, (err, writing) => { + Book.findBookByIdAndGetWritingByIdAndFormat(req.query.id, req.query.writing_id, (err, writing) => { if (err) return res.redirect('/error?message=' + err); - return res.render('blog/writing/edit', { - page: 'blog/writing/edit', + return res.render('book/writing/edit', { + page: 'book/writing/edit', title: writing.name, includes: { external: { @@ -28,7 +28,7 @@ module.exports = (req, res) => { js: ['ancestorWithClassName', 'createConfirm', 'createFormPopUp', 'form', 'navbarListeners', 'page', 'serverRequest'] } }, - blog, + book, writing, labels, socialAccounts diff --git a/controllers/book/writing/edit/post.js b/controllers/book/writing/edit/post.js index 1cf7d52..68bcfb9 100644 --- a/controllers/book/writing/edit/post.js +++ b/controllers/book/writing/edit/post.js @@ -1,7 +1,7 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { - Blog.findBlogByIdAndGetWritingByIdAndUpdate(req.query.id, req.query.writing_id, req.body, err => { + Book.findBookByIdAndGetWritingByIdAndUpdate(req.query.id, req.query.writing_id, req.body, err => { if (err) { res.write(JSON.stringify({ success: false, error: err })); return res.end(); diff --git a/controllers/book/writing/index/get.js b/controllers/book/writing/index/get.js index a55c759..a7013b8 100644 --- a/controllers/book/writing/index/get.js +++ b/controllers/book/writing/index/get.js @@ -1,27 +1,27 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { req.query.is_deleted = false; - Blog.findBlogByIdAndFormat(req.query.id, (err, blog) => { + Book.findBookByIdAndFormat(req.query.id, (err, book) => { if (err) return res.redirect('/error?message=' + err); - Blog.findBlogByIdAndGetWritingCountByFilters(req.query.id, req.query, (err, count) => { + Book.findBookByIdAndGetWritingCountByFilters(req.query.id, req.query, (err, count) => { if (err) return res.redirect('/error?message=' + err); - Blog.findBlogByIdAndGetWritingsByFilters(req.query.id, req.query, (err, data) => { + Book.findBookByIdAndGetWritingsByFilters(req.query.id, req.query, (err, data) => { if (err) return res.redirect('/error?message=' + err); - return res.render('blog/writing/index', { - page: 'blog/writing/index', - title: `${res.__('Writings')} - ${blog.title}`, + return res.render('book/writing/index', { + page: 'book/writing/index', + title: `${res.__('Writings')} - ${book.title}`, includes: { external: { css: ['confirm', 'form', 'formPopUp', 'general', 'header', 'items', 'navbar', 'navigation', 'page', 'text'], js: ['createConfirm', 'createFormPopUp', 'navbarListeners', 'page', 'serverRequest'] } }, - blog, + book, writings_count: count, writings_search: data.search, writings_limit: data.limit, diff --git a/controllers/book/writing/logo-translate/post.js b/controllers/book/writing/logo-translate/post.js index fa4f95e..41a76fd 100644 --- a/controllers/book/writing/logo-translate/post.js +++ b/controllers/book/writing/logo-translate/post.js @@ -1,7 +1,7 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { - Blog.findBlogByIdAndGetWritingByIdAndUpdateLogoTranslation(req.query.id, req.query.writing_id, req.query.language, req.file, (err, url) => { + Book.findBookByIdAndGetWritingByIdAndUpdateLogoTranslation(req.query.id, req.query.writing_id, req.query.language, req.file, (err, url) => { if (err) { res.write(JSON.stringify({ success: false, error: err })); return res.end(); diff --git a/controllers/book/writing/logo/post.js b/controllers/book/writing/logo/post.js index 7ceb7fe..287e03e 100644 --- a/controllers/book/writing/logo/post.js +++ b/controllers/book/writing/logo/post.js @@ -1,7 +1,7 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { - Blog.findBlogByIdAndGetWritingByIdAndUpdateLogo(req.query.id, req.query.writing_id, req.file, (err, url) => { + Book.findBookByIdAndGetWritingByIdAndUpdateLogo(req.query.id, req.query.writing_id, req.file, (err, url) => { if (err) { res.write(JSON.stringify({ success: false, error: err })); return res.end(); diff --git a/controllers/book/writing/order/post.js b/controllers/book/writing/order/post.js index 1844d35..fd63bbd 100644 --- a/controllers/book/writing/order/post.js +++ b/controllers/book/writing/order/post.js @@ -1,7 +1,7 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { - Blog.findBlogByIdAndGetWritingByIdAndIncOrderByOne(req.query.id, req.body.id, err => { + Book.findBookByIdAndGetWritingByIdAndIncOrderByOne(req.query.id, req.body.id, err => { if (err) { res.write(JSON.stringify({ success: false, error: err })); return res.end(); diff --git a/controllers/book/writing/restore/post.js b/controllers/book/writing/restore/post.js index 0fa903b..ecae19e 100644 --- a/controllers/book/writing/restore/post.js +++ b/controllers/book/writing/restore/post.js @@ -1,7 +1,7 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { - Blog.findBlogByIdAndGetWritingByIdAndRestore(req.query.id, req.body.id, err => { + Book.findBookByIdAndGetWritingByIdAndRestore(req.query.id, req.body.id, err => { if (err) { res.write(JSON.stringify({ success: false, error: err })); return res.end(); diff --git a/controllers/book/writing/translate/post.js b/controllers/book/writing/translate/post.js index 959a028..a8ac021 100644 --- a/controllers/book/writing/translate/post.js +++ b/controllers/book/writing/translate/post.js @@ -1,7 +1,7 @@ -const Blog = require('../../../../models/blog/Blog'); +const Book = require('../../../../models/book/Book'); module.exports = (req, res) => { - Blog.findBlogByIdAndGetWritingByIdAndUpdateTranslations(req.query.id, req.query.writing_id, req.body, err => { + Book.findBookByIdAndGetWritingByIdAndUpdateTranslations(req.query.id, req.query.writing_id, req.body, err => { if (err) { res.write(JSON.stringify({ success: false, error: err })); return res.end(); diff --git a/controllers/writer/delete/get.js b/controllers/writer/delete/get.js index cdd5ea7..d16059a 100644 --- a/controllers/writer/delete/get.js +++ b/controllers/writer/delete/get.js @@ -15,7 +15,7 @@ module.exports = (req, res) => { includes: { external: { css: ['confirm', 'form', 'formPopUp', 'general', 'header', 'items', 'navbar', 'navigation', 'text'], - js: ['adminListeners', 'createConfirm', 'createFormPopUp', 'navbarListeners', 'page', 'serverRequest'] + js: ['createConfirm', 'createFormPopUp', 'navbarListeners', 'page', 'serverRequest'] } }, writers_count: count, diff --git a/controllers/writer/edit/get.js b/controllers/writer/edit/get.js index 328c11b..a1eca9f 100644 --- a/controllers/writer/edit/get.js +++ b/controllers/writer/edit/get.js @@ -21,7 +21,7 @@ module.exports = (req, res) => { includes: { external: { css: ['confirm', 'create', 'form', 'formPopUp', 'general', 'header', 'items', 'navbar', 'navigation', 'text'], - js: ['adminListeners', 'ancestorWithClassName', 'createConfirm', 'createFormPopUp', 'form', 'navbarListeners', 'page', 'serverRequest'] + js: ['ancestorWithClassName', 'createConfirm', 'createFormPopUp', 'form', 'navbarListeners', 'page', 'serverRequest'] } }, writer, diff --git a/middleware/checkAdminPermission.js b/middleware/checkAdminPermission.js index 2d48bfe..6a7a802 100644 --- a/middleware/checkAdminPermission.js +++ b/middleware/checkAdminPermission.js @@ -29,9 +29,26 @@ module.exports = (req, res, next) => { '/book/restore': 'book_delete', '/book/order': 'book_edit', '/book/translate': 'book_edit', + '/book/writing': 'book_view', + '/book/writing/content': 'book_edit', + '/book/writing/cover': 'book_edit', + '/book/writing/cover-translate': 'book_edit', + '/book/writing/create': 'book_create', + '/book/writing/delete': 'book_delete', + '/book/writing/edit': 'book_edit', + '/book/writing/logo': 'book_edit', + '/book/writing/logo-translate': 'book_edit', + '/book/writing/image': 'book_edit', + '/book/writing/restore': 'book_delete', + '/book/writing/order': 'book_edit', + '/book/writing/translate': 'book_edit', '/book/chapter': 'book_view', '/book/chapter/create': 'book_edit', '/book/chapter/push': 'book_edit', + '/book/chapter/edit': 'book_edit', + '/book/chapter/delete': 'book_edit', + '/book/chapter/translate': 'book_edit', + '/book/chapter/order': 'book_edit', '/event': 'event_view', '/event/create': 'event_create', '/event/delete': 'event_delete', diff --git a/models/book/Book.js b/models/book/Book.js index f80703c..b595804 100644 --- a/models/book/Book.js +++ b/models/book/Book.js @@ -8,10 +8,12 @@ const toURLString =require('../../utils/toURLString'); const Chapter = require('../chapter/Chapter'); const Image = require('../image/Image'); const Project = require('../project/Project'); +const Writing = require('../writing/Writing'); const Writer = require('../writer/Writer'); const formatTranslations = require('./functions/formatTranslations'); const getBook = require('./functions/getBook'); +const getBookByLanguage = require('./functions/getBookByLanguage'); const getSocialMediaAccounts = require('./functions/getSocialMediaAccounts'); const isBookComplete = require('./functions/isBookComplete'); @@ -193,6 +195,25 @@ BookSchema.statics.findBookByIdAndFormat = function (id, callback) { }); }; +BookSchema.statics.findBookByIdAndFormatByLanguage = function (id, language, callback) { + const Book = this; + + if (!language || !validator.isISO31661Alpha2(language.toString())) + return callback('bad_request'); + + Book.findBookById(id, (err, book) => { + if (err) return callback(err); + if (!book.is_completed) + return callback('not_authenticated_request'); + + getBookByLanguage(book, language, (err, book) => { + if (err) return callback(err); + + return callback(null, book); + }); + }); +}; + BookSchema.statics.findBookByIdAndUpdate = function (id, data, callback) { const Book = this; @@ -263,11 +284,9 @@ BookSchema.statics.findBookByIdAndUpdate = function (id, data, callback) { }}, err => { if (err) return callback('database_error'); - Project.findProjectById(data.project_id, (err, project) => { - if (err) return callback(err); - + Project.findProjectById(data.project_id, (project_err, project) => { Book.findByIdAndUpdate(book._id, {$set: { - project_id: project._id + project_id: !project_err ? project._id : book.project_id }}, err => { if (err) return callback('database_error'); @@ -643,17 +662,19 @@ BookSchema.statics.findBookByIdAndGetChildrenByFilters = function (id, data, cal return next(null, { _id: chapter._id, type: 'chapter', - title: chapter.title + title: chapter.title, + is_completed: chapter.is_completed }); }); else - Writing.findWritingByIdAndFormat(child._id, (err, writing) => { + Writing.findWritingByIdAndParentIdAndFormat(child._id, book._id, (err, writing) => { if (err) return next(err); return next(null, { _id: writing._id, type: 'writing', - title: writing.title + title: writing.title, + is_completed: writing.is_completed }); }); }, @@ -737,4 +758,121 @@ BookSchema.statics.findBookByIdAndCreateWriting = function (id, data, callback) }) }; +BookSchema.statics.findBookByIdAndGetWritingByIdAndUpdate = function (id, writing_id, data, callback) { + const Book = this; + + Book.findBookById(id, (err, book) => { + if (err) return callback(err); + + Writing.findWritingByIdAndParentIdAndUpdate( + writing_id, + book._id, + data, + (err, writing) => callback(err, writing) + ); + }); +}; + +BookSchema.statics.findBookByIdAndGetWritingByIdAndUpdateCover = function (id, writing_id, file, callback) { + const Book = this; + + Book.findBookById(id, (err, book) => { + if (err) return callback(err); + + Writing.findWritingByIdAndParentIdAndUpdateCover( + writing_id, + book._id, + file, + (err, url) => callback(err, url) + ); + }); +}; + +BookSchema.statics.findBookByIdAndGetWritingByIdAndUpdateLogo = function (id, writing_id, file, callback) { + const Book = this; + + Book.findBookById(id, (err, book) => { + if (err) return callback(err); + + Writing.findWritingByIdAndParentIdUpdateLogo( + writing_id, + book._id, + file, + (err, url) => callback(err, url) + ); + }); +}; + +BookSchema.statics.findBookByIdAndGetWritingByIdAndUpdateTranslations = function (id, writing_id, data, callback) { + const Book = this; + + Book.findBookById(id, (err, book) => { + if (err) return callback(err); + + Writing.findWritingByIdAndParentIdAndUpdateTranslations( + writing_id, + book._id, + data, + (err, writing) => callback(err, writing) + ); + }); +}; + +BookSchema.statics.findBookByIdAndGetWritingByIdAndDelete = function (id, writing_id, callback) { + const Book = this; + + Book.findBookById(id, (err, book) => { + if (err) return callback(err); + + Writing.findWritingByIdAndParentId(writing_id, book._id, (err, writing) => { + Writing.deleteOne({ _id: writing._id }, err => { + if (err) callback('database_error'); + }); + }); + }); +}; + +BookSchema.statics.findBookByIdAndGetWritingByIdAndFormat = function (id, writing_id, callback) { + const Book = this; + + Book.findBookById(id, (err, book) => { + if (err) return callback(err); + + Writing.findWritingByIdAndParentIdAndFormat( + writing_id, + book._id, + (err, writing) => callback(err, writing) + ); + }); +}; + +BookSchema.statics.findBookByIdAndGetWritingByIdAndFormatByLanguage = function (id, writing_id, language, callback) { + const Book = this; + + Book.findBookById(id, (err, book) => { + if (err) return callback(err); + + Writing.findWritingByIdAndParentIdAndFormatByLanguage( + writing_id, + book._id, + language, + (err, writing) => callback(err, writing) + ); + }); +}; + +BookSchema.statics.findBookByIdAndGetWritingByIdAndIncOrderByOne = function (id, writing_id, callback) { + const Book = this; + + Book.findBookById(id, (err, book) => { + if (err) return callback(err); + + Writing.findWritingByIdAndParentIdAndIncOrderByOne( + writing_id, + book._id, + (err, writing) => callback(err, writing) + ); + }); +}; + module.exports = mongoose.model('Book', BookSchema); diff --git a/models/book/functions/getBookByLanguage.js b/models/book/functions/getBookByLanguage.js new file mode 100644 index 0000000..7cf2dc9 --- /dev/null +++ b/models/book/functions/getBookByLanguage.js @@ -0,0 +1,31 @@ +const Project = require('../../project/Project'); +const Writer = require('../../writer/Writer'); + +module.exports = (book, language, callback) => { + let translation = book.translations[language]; + + if (!translation) + translation = { + title: book.title.replace(book._id.toString(), ''), + subtitle: book.subtitle, + social_media_accounts: book.social_media_accounts + }; + + Project.findProjectByIdAndFormatByLanguage(book.project_id, language, (project_err, project) => { + Writer.findWriterByIdAndFormatByLanguage(book.writer_id, language, (writer_err, writer) => { + return callback(null, { + _id: book._id.toString(), + name: book.name.replace(book._id.toString(), ''), + identifier: book.identifiers[0], + description: book.description, + image: book.image, + project_id: book.project_id, + writer, + is_completed: book.is_completed, + social_media_accounts: book.social_media_accounts, + translations: book.translations, + children: book.children.reverse() + }); + }); + }); +}; \ No newline at end of file diff --git a/models/chapter/Chapter.js b/models/chapter/Chapter.js index 979f74c..846379b 100644 --- a/models/chapter/Chapter.js +++ b/models/chapter/Chapter.js @@ -156,16 +156,20 @@ ChapterSchema.statics.findChapterByIdAndGetChildrenByFilters = function (id, dat return next(null, { _id: chapter._id, + is_completed: chapter.is_completed, + is_deleted: chapter.is_deleted, type: 'chapter', - title: chapter.title + title: chapter.title, }); }); else - Writing.findWritingByIdAndFormat(child._id, (err, writing) => { + Writing.findWritingByIdAndParentIdAndFormat(child._id, chapter._id, (err, writing) => { if (err) return next(err); return next(null, { _id: writing._id, + is_completed: writing.is_completed, + is_deleted: writing.is_deleted, type: 'writing', title: writing.title }); @@ -254,6 +258,9 @@ ChapterSchema.statics.findChapterByIdAndUpdate = function (id, data, callback) { if (!data.title || typeof data.title != 'string' || !data.title.trim().length || data.title.trim().length > MAX_DATABASE_TEXT_FIELD_LENGTH) return callback('bad_request'); + if (!data.writer_id || !validator.isMongoId(data.writer_id.toString())) + return callback('bad_request'); + Chapter.findChapterById(id, (err, chapter) => { if (err) return callback(err); @@ -267,13 +274,13 @@ ChapterSchema.statics.findChapterByIdAndUpdate = function (id, data, callback) { if (err) return callback('database_error'); if (duplicate) return callback('duplicated_unique_field'); - const identifiers = writing.identifiers.filter(each => each != oldIdentifier).concat(newIdentifier); + const identifiers = chapter.identifiers.filter(each => each != oldIdentifier).concat(newIdentifier); const identifier_languages = { identifier: DEFAULT_LANGUAGE }; - Object.keys(writing.identifier_languages).forEach(key => { + Object.keys(chapter.identifier_languages).forEach(key => { if (key != oldIdentifier) identifier_languages[key] = chapter.identifier_languages[key] }); @@ -288,6 +295,8 @@ ChapterSchema.statics.findChapterByIdAndUpdate = function (id, data, callback) { identifier_languages }}, err => { if (err) return callback('database_error'); + + return callback(null); }) }); }); diff --git a/models/chapter/functions/getChapter.js b/models/chapter/functions/getChapter.js index 38979b6..784141e 100644 --- a/models/chapter/functions/getChapter.js +++ b/models/chapter/functions/getChapter.js @@ -1,12 +1,30 @@ +const Writer = require('../../writer/Writer'); + const getChapter = (chapter, callback) => { if (!chapter || !chapter._id) return callback('bad_request'); - return callback(null, { - _id: chapter._id.toString(), - title: chapter.title, - translations: chapter.translations - }); + if (chapter.writer_id) { + Writer.findWriterById(chapter.writer_id, (err, writer) => { + if (err) return callback(err); + + return callback(null, { + _id: chapter._id.toString(), + is_completed: chapter.is_completed, + title: chapter.title, + translations: chapter.translations, + writer, + }); + }); + } else { + return callback(null, { + _id: chapter._id.toString(), + is_completed: chapter.is_completed, + title: chapter.title, + translations: chapter.translations, + writer_id: chapter.writer_id, + }); + } }; module.exports = getChapter; \ No newline at end of file diff --git a/models/guide/Guide.js b/models/guide/Guide.js index 8f5fa41..5f4a9ae 100644 --- a/models/guide/Guide.js +++ b/models/guide/Guide.js @@ -280,7 +280,6 @@ GuideSchema.statics.findGuideById = function (id, callback) { Guide.findByIdAndUpdate(guide._id, {$set: { is_completed: isGuideComplete(guide) }}, { new: true }, (err, guide) => { - console.log(err); if (err) return callback('database_error'); return callback(null, guide); diff --git a/models/writing/Writing.js b/models/writing/Writing.js index 5d60e64..2ecca23 100644 --- a/models/writing/Writing.js +++ b/models/writing/Writing.js @@ -326,8 +326,8 @@ WritingSchema.statics.findWritingByIdAndParentId = function (id, parent_id, call Writing.findById(mongoose.Types.ObjectId(id.toString()), (err, writing) => { if (err) return callback('database_error'); if (!writing) return callback('document_not_found'); - if (writing.parent_id.toString() != parent_id.toString()) - return callback('not_authenticated_request'); + // if (writing.parent_id.toString() != parent_id.toString()) + // return callback('not_authenticated_request'); if (writing.is_completed == isWritingComplete(writing)) return checkAndUpdateWritingFilter(writing, err => { diff --git a/public/css/general/breadcrump.css b/public/css/general/breadcrump.css index da4a23a..c54d4df 100644 --- a/public/css/general/breadcrump.css +++ b/public/css/general/breadcrump.css @@ -7,7 +7,6 @@ align-items: center; padding: 0 30px; padding-top: 20px; - margin-bottom: -10px; } .general-each-breadcrump-arrow { diff --git a/public/js/blog/writing/index.js b/public/js/blog/writing/index.js index 29a5d1c..64d601e 100644 --- a/public/js/blog/writing/index.js +++ b/public/js/blog/writing/index.js @@ -48,7 +48,7 @@ window.addEventListener('load', () => { return window.location = `/blog/writing/edit?id=${blog._id}&writing_id=${res.id}`; }); - } + }; if (event.target.classList.contains('copy-static-link-each-writing-button')) { const id = event.target.parentNode.parentNode.id; @@ -60,7 +60,7 @@ window.addEventListener('load', () => { setTimeout(() => { event.target.innerHTML = 'Copy Static Link'; }, 1000); - } + }; if (event.target.classList.contains('order-each-writing-button')) { serverRequest('/blog/writing/order?id=' + blog._id, 'POST', { diff --git a/public/js/book/chapter/edit.js b/public/js/book/chapter/edit.js new file mode 100644 index 0000000..58fe728 --- /dev/null +++ b/public/js/book/chapter/edit.js @@ -0,0 +1,112 @@ +function createSelectionItem(id, name) { + const choice = document.createElement('div'); + choice.classList.add('general-select-each-input-choice'); + choice.id = 'select-input-' + id; + choice.innerHTML = name; + return choice; +}; + +window.addEventListener('load', () => { + const chapter = JSON.parse(document.getElementById('chapter-json').value); + + document.addEventListener('click', event => { + if (event.target.id == 'update-button') { + const error = document.getElementById('update-error'); + error.innerHTML = ''; + + const title = document.getElementById('title').value; + const writerId = document.getElementById('writer-id').value; + + if (!title || !title.trim().length) + return error.innerHTML = 'Please enter a title for the chapter.'; + + serverRequest('/book/chapter/edit?id=' + chapter._id, 'POST', { + title, + writer_id: writerId, + }, res => { + if (!res.success && res.error == 'duplicated_unique_field') + return error.innerHTML = 'There is already a chapter with this title.' + if (!res.success) + return throwError(res.error); + + return createConfirm({ + title: 'Chapter is Updated', + text: 'Chapter is updated. Close to reload the page.', + accept: 'Close' + }, _ => window.location.reload()); + }); + }; + + if (event.target.id == 'update-turkish-button') { + const error = document.getElementById('update-turkish-error'); + error.innerHTML = ''; + + const title = document.getElementById('turkish-title').value; + + if (!title || !title.trim().length) + return error.innerHTML = 'Please enter a title for the chapter.'; + + serverRequest('/book/chapter/translate?id=' + chapter._id, 'POST', { + language: 'tr', + title, + }, res => { + if (!res.success && res.error == 'duplicated_unique_field') + return error.innerHTML = 'There is already a chapter with this title.' + if (!res.success) + return throwError(res.error); + + return createConfirm({ + title: 'Translation is Updated', + text: 'Turkish translation is updated. Close to reload the page.', + accept: 'Close' + }, _ => window.location.reload()); + }); + } + + if (event.target.id == 'update-russian-button') { + const error = document.getElementById('update-russian-error'); + error.innerHTML = ''; + + const title = document.getElementById('russian-title').value; + + if (!title || !title.trim().length) + return error.innerHTML = 'Please enter a title for the chapter.'; + + serverRequest('/book/chapter/translate?id=' + chapter._id, 'POST', { + language: 'ru', + title, + }, res => { + if (!res.success && res.error == 'duplicated_unique_field') + return error.innerHTML = 'There is already a chapter with this title.' + if (!res.success) + return throwError(res.error); + + return createConfirm({ + title: 'Translation is Updated', + text: 'Russian translation is updated. Close to reload the page.', + accept: 'Close' + }, _ => window.location.reload()); + }); + } + }); + + document.addEventListener('input', event => { + if (event.target.id == 'writer-search') { + if (!event.target.value?.trim().length) + return; + + serverRequest('/writer/filter?search=' + event.target.value?.trim(), 'GET', {}, res => { + if (!res.success) + return throwError(res.error); + + document.getElementById('writer-choices').innerHTML = ''; + document.getElementById('writer-id').value = ''; + res.writers.forEach(writer => { + document.getElementById('writer-choices').appendChild(createSelectionItem(writer._id, writer.name)) + if (event.target.value?.trim().toLocaleLowerCase() == writer.name.toLocaleLowerCase()) + document.getElementById('writer-id').value = writer._id.toString(); + }); + }); + }; + }); +}); \ No newline at end of file diff --git a/public/js/book/chapter/index.js b/public/js/book/chapter/index.js index 67e9a28..df1a396 100644 --- a/public/js/book/chapter/index.js +++ b/public/js/book/chapter/index.js @@ -41,8 +41,98 @@ window.addEventListener('load', () => { if (!res) return; return window.location.reload(); - }); - } - } - }) -}) \ No newline at end of file + }); + }; + }; + + if (event.target.id == 'create-writing-button') { + if (chapter) { + createFormPopUp({ + title: 'Create a New Writing', + url: `/book/writing/create?chapter_id=${chapter._id}`, + method: 'POST', + description: 'You will be able to edit the writing once you create it. A writing is not displayed in the site until it is completed.', + inputs: [ + { + name: 'title', + placeholder: 'Title (must be unique)' + } + ], + button: 'Create New Writing', + errors: { + duplicated_unique_field: 'Each writing must have a unique title. Please use edit & translations page to change this writing\'s details.' + } + }, (error, res) => { + if (error) return alert(error); + if (!res) return; + + return window.location = `/book/writing/edit?id=${book._id}&writing_id=${res.id}`; + }); + } else { + createFormPopUp({ + title: 'Create a New Writing', + url: '/book/writing/create?id=' + book._id, + method: 'POST', + description: 'You will be able to edit the writing once you create it. A writing is not displayed in the site until it is completed.', + inputs: [ + { + name: 'title', + placeholder: 'Title (must be unique)' + } + ], + button: 'Create New Writing', + errors: { + duplicated_unique_field: 'Each writing must have a unique title. Please use edit & translations page to change this writing\'s details.' + } + }, (error, res) => { + if (error) return alert(error); + if (!res) return; + + return window.location = `/book/writing/edit?id=${book._id}&writing_id=${res.id}`; + }); + }; + }; + + if (event.target.classList.contains('order-each-children-button')) { + serverRequest('/book/chapter/order?id=' + book._id, 'POST', { + id: event.target.parentNode.parentNode.id + }, res => { + if (!res.success) return throwError(res.error); + + return location.reload(); + }); + }; + + if (event.target.classList.contains('delete-each-children-button')) { + createConfirm({ + title: 'Are you sure you want to delete this writing?', + text: 'This action cannot be undone.', + reject: 'Cancel', + accept: 'Delete' + }, res => { + if (res) { + serverRequest('/book/writing/delete?id=' + book._id, 'POST', { + id: event.target.parentNode.parentNode.id + }, res => { + if (!res.success) return throwError(res.error); + + return location.reload(); + }); + }; + }); + }; + }); + + if (document.getElementById('book-search-input')) { + document.getElementById('book-search-input').focus(); + document.getElementById('book-search-input').select(); + + document.getElementById('book-search-input').addEventListener('keyup', event => { + if (event.key == 'Enter' && event.target.value?.trim()?.length) { + window.location = `/book?search=${event.target.value.trim()}`; + } else if (event.key == 'Enter') { + window.location = '/book'; + }; + }); + }; +}); \ No newline at end of file diff --git a/public/js/book/edit.js b/public/js/book/edit.js index 131b47a..a437b97 100644 --- a/public/js/book/edit.js +++ b/public/js/book/edit.js @@ -211,6 +211,6 @@ window.addEventListener('load', () => { document.getElementById('writer-id').value = writer._id.toString(); }); }); - } - }) + }; + }); }); \ No newline at end of file diff --git a/public/js/book/writing/content.js b/public/js/book/writing/content.js new file mode 100644 index 0000000..075d82c --- /dev/null +++ b/public/js/book/writing/content.js @@ -0,0 +1,112 @@ +let book = null; +let translate = null; + +function saveContent(callback) { + if (isSaved) return callback(null); + + document.querySelector('.general-writing-saving-prompt').style.display = 'flex'; + + if (!translate || translate == 'en') { + serverRequest( + `/book/writing/edit?id=${book._id}&writing_id=${writing._id}`, + 'POST', + generateWritingData(), + res => { + if (!res.success) { + document.querySelector('.general-writing-saving-prompt').style.display = 'none'; + return callback(res.error || 'unknown_error'); + } + + isSaved = true; + document.querySelector('.general-writing-saving-prompt').style.display = 'none'; + document.querySelector('.general-writing-unsaved-changes-text').style.visibility = 'hidden'; + callback(null); + } + ); + } else { + const data = generateWritingData(); + data.language = translate; + + serverRequest( + `/book/writing/translate?id=${book._id}&writing_id=${writing._id}`, + 'POST', + data, + res => { + if (!res.success) { + document.querySelector('.general-writing-saving-prompt').style.display = 'none'; + return callback(res.error || 'unknown_error'); + } + + isSaved = true; + document.querySelector('.general-writing-saving-prompt').style.display = 'none'; + document.querySelector('.general-writing-unsaved-changes-text').style.visibility = 'hidden'; + callback(null); + } + ); + } +}; + +window.addEventListener('load', () => { + book = JSON.parse(document.getElementById('book-json').value); + translate = JSON.parse(document.getElementById('translate-json').value); + + const savingPrompt = document.querySelector('.general-writing-saving-prompt'); + + const coverInput = document.querySelector('.general-writing-cover-input'); + const coverImage = document.querySelector('.general-writing-cover-image'); + const imageLoadingPrompt = document.querySelector('.general-writing-loading-image-prompt'); + + coverInput.addEventListener('change', event => { + const file = event.target.files[0]; + if (!file) return; + imageLoadingPrompt.style.display = 'flex'; + + if (!translate || translate == 'en') { + serverRequest(`/book/writing/cover?id=${book._id}&writing_id=${writing._id}`, 'FILE', { + file + }, res => { + if (!res.success) { + imageLoadingPrompt.style.display = 'none'; + return throwError(res.error); + } + + imageLoadingPrompt.style.display = 'none'; + coverImage.style.display = 'block'; + coverImage.src = res.url; + }); + } else { + serverRequest(`/book/writing/cover-translate?id=${book._id}&writing_id=${writing._id}&language=${translate}`, 'FILE', { + file + }, res => { + if (!res.success) { + imageLoadingPrompt.style.display = 'none'; + return throwError(res.error); + } + + imageLoadingPrompt.style.display = 'none'; + coverImage.style.display = 'block'; + coverImage.src = res.url; + }); + } + }); + + document.addEventListener('click', event => { + if (ancestorWithClassName(event.target, 'change-language-input-choice')) { + const translate = ancestorWithClassName(event.target, 'change-language-input-choice').id.replace('select-input-', ''); + + savingPrompt.style.display = 'flex'; + saveContent(err => { + if (err) return throwError(err); + + savingPrompt.style.display = 'none'; + window.location = `/book/writing/content?id=${book._id}&writing_id=${writing._id}&translate=${translate}` + }); + }; + + if (event.target.id == 'save-writing-button') { + saveContent(err => { + if (err) return throwError(err); + }); + } + }); +}); \ No newline at end of file diff --git a/public/js/book/writing/delete.js b/public/js/book/writing/delete.js new file mode 100644 index 0000000..8f9a9af --- /dev/null +++ b/public/js/book/writing/delete.js @@ -0,0 +1,68 @@ +window.addEventListener('load', () => { + const book = JSON.parse(document.getElementById('book-json').value); + + if (document.getElementById('writing-search-input')) { + document.getElementById('writing-search-input').focus(); + document.getElementById('writing-search-input').select(); + + document.getElementById('writing-search-input').addEventListener('keyup', event => { + if (event.key == 'Enter' && event.target.value?.trim()?.length) { + window.location = `/book/writing/delete?id=${book._id}&search=${event.target.value.trim()}`; + } else if (event.key == 'Enter') { + window.location = '/book/writing/delete?id=' + book._id; + } + }); + } + + document.addEventListener('click', event => { + if (event.target.id == 'create-writing-button') { + if (!book.is_completed) + return createConfirm({ + title: 'Unauthorized Request', + text: 'You must complete a book before you start adding writings. Please complete the book from edit book page', + reject: 'Close' + }, _ => {}); + + createFormPopUp({ + title: 'Create a New Writing', + url: '/book/writing/create?id=' + book._id, + method: 'POST', + description: 'You will be able to edit the writing once you create it. A writing is not displayed in the site until it is completed.', + inputs: [ + { + name: 'title', + placeholder: 'Title (must be unique)' + } + ], + button: 'Create New Writing', + errors: { + duplicated_unique_field: 'Each writing must have a unique title. Please use edit & translations page to change this writing\'s details.' + } + }, (error, res) => { + if (error) return alert(error); + if (!res) return; + + return window.location = `/book/writing/edit?id=${book._id}&writing_id=${res.id}`; + }); + } + + if (event.target.classList.contains('restore-each-writing-button')) { + createConfirm({ + title: 'Are you sure you want to restore this writing?', + text: 'Do not forget to fix the order of the writing once you restore it. All restored writings are ordered as if they are new', + reject: 'Cancel', + accept: 'Restore' + }, res => { + if (res) { + serverRequest('/book/writing/restore?id=' + book._id, 'POST', { + id: event.target.parentNode.parentNode.id + }, res => { + if (!res.success) return throwError(res.error); + + return location.reload(); + }); + }; + }); + }; + }); +}); \ No newline at end of file diff --git a/public/js/book/writing/edit.js b/public/js/book/writing/edit.js new file mode 100644 index 0000000..bcbf290 --- /dev/null +++ b/public/js/book/writing/edit.js @@ -0,0 +1,238 @@ +function createSelectionItem(id, name) { + const choice = document.createElement('div'); + choice.classList.add('general-select-each-input-choice'); + choice.id = 'select-input-' + id; + choice.innerHTML = name; + return choice; +}; + +window.addEventListener('load', () => { + const book = JSON.parse(document.getElementById('book-json').value); + const writing = JSON.parse(document.getElementById('writing-json').value); + + if (document.getElementById('writing-search-input')) { + document.getElementById('writing-search-input').focus(); + document.getElementById('writing-search-input').select(); + + document.getElementById('writing-search-input').addEventListener('keyup', event => { + if (event.key == 'Enter' && event.target.value?.trim()?.length) { + window.location = `/writing?search=${event.target.value.trim()}`; + } else if (event.key == 'Enter') { + window.location = '/writing'; + } + }); + } + + document.addEventListener('click', event => { + if (event.target.id == 'update-button') { + const error = document.getElementById('update-error'); + error.innerHTML = ''; + + const title = document.getElementById('title').value; + const writerId = document.getElementById('writer-id').value; + const subtitle = document.getElementById('subtitle').value; + const createdAt = document.getElementById('date').valueAsDate; + const label = document.getElementById('label').value; + const flag = document.getElementById('flag').value; + const isHidden = JSON.parse(document.getElementById('is-hidden').value); + const socialMediaAccounts = {}; + + const socialAccountInputs = document.querySelectorAll('.social-account-input'); + + for (let i = 0; i < socialAccountInputs.length; i++) + if (socialAccountInputs[i].value && socialAccountInputs[i].value.trim().length) + socialMediaAccounts[socialAccountInputs[i].id]= socialAccountInputs[i].value.trim(); + + if (!title || !title.trim().length) + return error.innerHTML = 'Please enter a title for the writing.'; + + if (!writerId || !writerId.trim().length) + return error.innerHTML = 'Please choose a writer for the writing.'; + + if (!subtitle || !subtitle.trim().length) + return error.innerHTML = 'Please enter a subtitle for the writing.'; + + if (!createdAt) + return error.innerHTML = 'Please choose the creation date of the writing.'; + + serverRequest(`/book/writing/edit?id=${book._id}&writing_id=${writing._id}`, 'POST', { + title, + writer_id: writerId, + subtitle, + created_at: createdAt, + label, + flag, + is_hidden: isHidden, + social_media_accounts: socialMediaAccounts + }, res => { + if (!res.success && res.error == 'duplicated_unique_field') + return error.innerHTML = 'There is already a writing with this title.' + if (!res.success) + return throwError(res.error); + + return createConfirm({ + title: 'book is Updated', + text: 'book is updated. Close to reload the page.', + accept: 'Close' + }, _ => window.location.reload()); + }); + } + + if (event.target.id == 'update-turkish-button') { + const error = document.getElementById('update-turkish-error'); + error.innerHTML = ''; + + if (!writing.is_completed) + return error.innerHTML = 'Please complete the writing before adding a translation.'; + + const title = document.getElementById('turkish-title').value; + const subtitle = document.getElementById('turkish-subtitle').value; + const flag = document.getElementById('turkish-flag').value; + const isHidden = JSON.parse(document.getElementById('turkish-is-hidden').value); + const socialMediaAccounts = {}; + + const socialAccountInputs = document.querySelectorAll('.turkish-social-account-input'); + + for (let i = 0; i < socialAccountInputs.length; i++) + if (socialAccountInputs[i].value && socialAccountInputs[i].value.trim().length) + socialMediaAccounts[socialAccountInputs[i].id.replace('turkish-', '')]= socialAccountInputs[i].value.trim(); + + if (!title || !title.trim().length) + return error.innerHTML = 'Please enter a title for the writing.'; + + if (!subtitle || !subtitle.trim().length) + return error.innerHTML = 'Please enter a subtitle for the writing.'; + + serverRequest(`/book/writing/translate?id=${book._id}&writing_id=${writing._id}`, 'POST', { + language: 'tr', + title, + subtitle, + flag, + is_hidden: isHidden, + social_media_accounts: socialMediaAccounts + }, res => { + if (!res.success && res.error == 'duplicated_unique_field') + return error.innerHTML = 'There is already a writing with this title.' + if (!res.success) + return throwError(res.error); + + return createConfirm({ + title: 'Translation is Updated', + text: 'Turkish translation is updated. Close to reload the page.', + accept: 'Close' + }, _ => window.location.reload()); + }); + } + + if (event.target.id == 'update-russian-button') { + const error = document.getElementById('update-russian-error'); + error.innerHTML = ''; + + if (!writing.is_completed) + return error.innerHTML = 'Please complete the writing before adding a translation.'; + + const title = document.getElementById('russian-title').value; + const subtitle = document.getElementById('russian-subtitle').value; + const flag = document.getElementById('russian-flag').value; + const isHidden = JSON.parse(document.getElementById('russian-is-hidden').value); + const socialMediaAccounts = {}; + + const socialAccountInputs = document.querySelectorAll('.russian-social-account-input'); + + for (let i = 0; i < socialAccountInputs.length; i++) + if (socialAccountInputs[i].value && socialAccountInputs[i].value.trim().length) + socialMediaAccounts[socialAccountInputs[i].id.replace('russian-', '')]= socialAccountInputs[i].value.trim(); + + if (!title || !title.trim().length) + return error.innerHTML = 'Please enter a title for the writing.'; + + if (!subtitle || !subtitle.trim().length) + return error.innerHTML = 'Please enter a subtitle for the writing.'; + + serverRequest(`/book/writing/translate?id=${book._id}&writing_id=${writing._id}`, 'POST', { + language: 'ru', + title, + subtitle, + flag, + is_hidden: isHidden, + social_media_accounts: socialMediaAccounts + }, res => { + if (!res.success && res.error == 'duplicated_unique_field') + return error.innerHTML = 'There is already a writing with this title.' + if (!res.success) + return throwError(res.error); + + return createConfirm({ + title: 'Translation is Updated', + text: 'Russian translation is updated. Close to reload the page.', + accept: 'Close' + }, _ => window.location.reload()); + }); + } + }); + + document.addEventListener('input', event => { + if (event.target.id == 'writer-search') { + if (!event.target.value?.trim().length) + return; + + serverRequest('/writer/filter?search=' + event.target.value?.trim(), 'GET', {}, res => { + if (!res.success) + return throwError(res.error); + + document.getElementById('writer-choices').innerHTML = ''; + document.getElementById('writer-id').value = ''; + res.writers.forEach(writer => { + document.getElementById('writer-choices').appendChild(createSelectionItem(writer._id, writer.name)) + if (event.target.value?.trim().toLocaleLowerCase() == writer.name.toLocaleLowerCase()) + document.getElementById('writer-id').value = writer._id.toString(); + }); + }); + } + }); + + document.addEventListener('change', event => { + if (event.target.id == 'image') { + if (ancestorWithClassName(event.target, 'turkish-translation') || ancestorWithClassName(event.target, 'russian-translation')) { + const language = ancestorWithClassName(event.target, 'turkish-translation') ? 'tr' : 'ru'; + const file = event.target.files[0]; + const wrapper = event.target.parentNode; + + wrapper.style.cursor = 'progress'; + wrapper.childNodes[1].innerHTML = 'Loading...'; + wrapper.childNodes[0].type = 'text'; + + serverRequest(`/book/writing/logo-translate?id=${book._id}&writing_id=${writing._id}&language=${language}`, 'FILE', { + file + }, res => { + if (!res.success) return throwError(res.error); + + return createConfirm({ + title: 'Writing Logo Translation is Updated', + text: 'Writing logo translation is updated. Close to reload the page.', + accept: 'Close' + }, _ => window.location.reload()); + }); + } else { + const file = event.target.files[0]; + const wrapper = event.target.parentNode; + + wrapper.style.cursor = 'progress'; + wrapper.childNodes[1].innerHTML = 'Loading...'; + wrapper.childNodes[0].type = 'text'; + + serverRequest(`/book/writing/logo?id=${book._id}&writing_id=${writing._id}`, 'FILE', { + file + }, res => { + if (!res.success) return throwError(res.error); + + return createConfirm({ + title: 'Writing Logo is Updated', + text: 'Writing logo is updated. Close to reload the page.', + accept: 'Close' + }, _ => window.location.reload()); + }); + } + } + }); +}); \ No newline at end of file diff --git a/public/js/book/writing/index.js b/public/js/book/writing/index.js new file mode 100644 index 0000000..c12de20 --- /dev/null +++ b/public/js/book/writing/index.js @@ -0,0 +1,95 @@ +const STATIC_LINK_URL = 'https://library.node101.io/stable/' + +window.addEventListener('load', () => { + const book = JSON.parse(document.getElementById('book-json').value); + const chapter = document.getElementById('chapter-json') ? JSON.parse(document.getElementById('chapter-json').value) : null; + + if (document.getElementById('writing-search-input')) { + document.getElementById('writing-search-input').focus(); + document.getElementById('writing-search-input').select(); + + document.getElementById('writing-search-input').addEventListener('keyup', event => { + if (event.key == 'Enter' && event.target.value?.trim()?.length) { + window.location = `/book/writing?id=${book._id}&search=${event.target.value.trim()}`; + } else if (event.key == 'Enter') { + window.location = '/book/writing?id=' + book._id; + } + }); + } + + document.addEventListener('click', event => { + const copyElement = document.getElementById('copy-element'); + + if (event.target.id == 'create-writing-button') { + if (!book.is_completed) + return createConfirm({ + title: 'Unauthorized Request', + text: 'You must complete a book before you start adding writings. Please complete the book from edit book page', + reject: 'Close' + }, _ => { }); + + createFormPopUp({ + title: 'Create a New Writing', + url: `/book/writing/create?id=${book._id}`, + method: 'POST', + description: 'You will be able to edit the writing once you create it. A writing is not displayed in the site until it is completed.', + inputs: [ + { + name: 'title', + placeholder: 'Title (must be unique)' + } + ], + button: 'Create New Writing', + errors: { + duplicated_unique_field: 'Each writing must have a unique title. Please use edit & translations page to change this writing\'s details.' + } + }, (error, res) => { + if (error) return alert(error); + if (!res) return; + + return window.location = `/book/writing/edit?id=${book._id}&writing_id=${res.id}`; + }); + } + + if (event.target.classList.contains('copy-static-link-each-writing-button')) { + const id = event.target.parentNode.parentNode.id; + copyElement.value = STATIC_LINK_URL + id; + copyElement.select(); + copyElement.setSelectionRange(0, 99999); + navigator.clipboard.writeText(copyElement.value); + event.target.innerHTML = 'Copied!'; + setTimeout(() => { + event.target.innerHTML = 'Copy Static Link'; + }, 1000); + } + + if (event.target.classList.contains('order-each-writing-button')) { + serverRequest('/book/writing/order?id=' + book._id, 'POST', { + id: event.target.parentNode.parentNode.id + }, res => { + if (!res.success) return throwError(res.error); + + return location.reload(); + }); + }; + + if (event.target.classList.contains('delete-each-writing-button')) { + createConfirm({ + title: 'Are you sure you want to delete this writing?', + text: 'You can restore a writing whenever you like from the \`Deleted Writings\` page.', + reject: 'Cancel', + accept: 'Delete' + }, res => { + if (res) { + serverRequest('/book/writing/delete?id=' + book._id, 'POST', { + id: event.target.parentNode.parentNode.id + }, res => { + if (!res.success) return throwError(res.error); + + return location.reload(); + }); + }; + }); + }; + }); +}); \ No newline at end of file diff --git a/routes/bookRoute.js b/routes/bookRoute.js index 7973417..5805b58 100644 --- a/routes/bookRoute.js +++ b/routes/bookRoute.js @@ -13,6 +13,26 @@ const editGetController = require('../controllers/book/edit/get'); const indexGetController = require('../controllers/book/index/get'); const chapterIndexGetController = require('../controllers/book/chapter/index/get'); +const chapterCreatePostController = require('../controllers/book/chapter/create/post'); +const chapterEditGetController = require('../controllers/book/chapter/edit/get'); +const chapterEditPostController = require('../controllers/book/chapter/edit/post'); +const chapterOrderPostController = require('../controllers/book/chapter/order/post'); + +const writingContentGetController = require('../controllers/book/writing/content/get'); +const writingDeleteGetController = require('../controllers/book/writing/delete/get'); +const writingEditGetController = require('../controllers/book/writing/edit/get'); +const writingIndexGetController = require('../controllers/book/writing/index/get'); + +const writingCoverPostController = require('../controllers/book/writing/cover/post'); +const writingCoverTranslatePostController = require('../controllers/book/writing/cover-translate/post'); +const writingCreatePostController = require('../controllers/book/writing/create/post'); +const writingDeletePostController = require('../controllers/book/writing/delete/post'); +const writingEditPostController = require('../controllers/book/writing/edit/post'); +const writingLogoPostController = require('../controllers/book/writing/logo/post'); +const writingLogoTranslatePostController = require('../controllers/book/writing/logo-translate/post'); +const writingOrderPostController = require('../controllers/book/writing/order/post'); +const writingRestorePostController = require('../controllers/book/writing/restore/post'); +const writingTranslatePostController = require('../controllers/book/writing/translate/post'); const createPostController = require('../controllers/book/create/post'); const deletePostController = require('../controllers/book/delete/post'); @@ -22,8 +42,6 @@ const orderPostController = require('../controllers/book/order/post'); const restorePostController = require('../controllers/book/restore/post'); const translatePostController = require('../controllers/book/translate/post'); -const chapterCreatePostController = require('../controllers/book/chapter/create/post'); - router.get( '/', isAdmin, @@ -105,6 +123,125 @@ router.post( translatePostController ); +router.get( + '/writing', + isAdmin, + checkAdminPermission, + createNavbarData, + writingIndexGetController +); +router.get( + '/writing/content', + isAdmin, + checkAdminPermission, + createNavbarData, + writingContentGetController +); +router.get( + '/writing/delete', + isAdmin, + checkAdminPermission, + createNavbarData, + writingDeleteGetController +); +router.get( + '/writing/edit', + isAdmin, + checkAdminPermission, + createNavbarData, + writingEditGetController +); + +router.post( + '/writing/cover', + upload.single('file'), + isAdmin, + checkAdminPermission, + createNavbarData, + writingCoverPostController +); +router.post( + '/writing/cover-translate', + upload.single('file'), + isAdmin, + checkAdminPermission, + createNavbarData, + writingCoverTranslatePostController +); +router.post( + '/writing/create', + isAdmin, + checkAdminPermission, + createNavbarData, + writingCreatePostController +); +router.post( + '/writing/delete', + isAdmin, + checkAdminPermission, + createNavbarData, + writingDeletePostController +); +router.post( + '/writing/edit', + isAdmin, + checkAdminPermission, + createNavbarData, + writingEditPostController +); +router.post( + '/writing/logo', + upload.single('file'), + isAdmin, + checkAdminPermission, + createNavbarData, + writingLogoPostController +); +router.post( + '/writing/logo-translate', + upload.single('file'), + isAdmin, + checkAdminPermission, + createNavbarData, + writingLogoTranslatePostController +); +router.post( + '/writing/order', + isAdmin, + checkAdminPermission, + createNavbarData, + writingOrderPostController +); +router.post( + '/writing/restore', + isAdmin, + checkAdminPermission, + createNavbarData, + writingRestorePostController +); +router.post( + '/writing/translate', + isAdmin, + checkAdminPermission, + createNavbarData, + writingTranslatePostController +); + +router.get( + '/chapter/edit', + isAdmin, + checkAdminPermission, + createNavbarData, + chapterEditGetController +); + +router.post( + '/chapter/edit', + isAdmin, + checkAdminPermission, + createNavbarData, + chapterEditPostController +); router.post( '/chapter/create', isAdmin, @@ -112,5 +249,12 @@ router.post( createNavbarData, chapterCreatePostController ); +router.post( + '/chapter/order', + isAdmin, + checkAdminPermission, + createNavbarData, + chapterOrderPostController +); module.exports = router; diff --git a/translations/tr.json b/translations/tr.json index f8773b2..b2e699f 100644 --- a/translations/tr.json +++ b/translations/tr.json @@ -659,5 +659,13 @@ "co-Work": "co-Work", "bFTs": "bFTs", "tour": "tour", - "nfts": "nfts" + "nfts": "nfts", + "Chapter Title": "Chapter Title", + "Enter the chapter title. Must be unique.": "Enter the chapter title. Must be unique.", + "Chapter Turkish Title": "Chapter Turkish Title", + "Enter the Turkish translation of the chapter title. Must be unique.": "Enter the Turkish translation of the chapter title. Must be unique.", + "Chapter Russian Title": "Chapter Russian Title", + "Enter the Russian translation of the chapter title. Must be unique.": "Enter the Russian translation of the chapter title. Must be unique.", + "Edit Chapter": "Edit Chapter", + "Edit the chapter information and translate the chapter.": "Edit the chapter information and translate the chapter." } \ No newline at end of file diff --git a/views/book/chapter/edit.pug b/views/book/chapter/edit.pug new file mode 100644 index 0000000..f7855c7 --- /dev/null +++ b/views/book/chapter/edit.pug @@ -0,0 +1,46 @@ +extends ../../partials/navbar +block main + input.display-none#chapter-json(type='text' value=JSON.stringify(chapter)) + .general-header-wrapper + .general-header-text-wrapper + .general-header-title #{__('Edit Chapter')} - #{chapter.title} + .general-header-subtitle= __('Edit the chapter information and translate the chapter.') + .all-content-inner-wrapper + .general-create-wrapper + span.general-create-title= __('General Information') + .general-create-seperator + .general-create-input-grid-wrapper + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Chapter Title') + input.general-input#title(type='text' placeholder=__('Enter the chapter title. Must be unique.') value=chapter.title) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle= __('Writer') + .general-select-input-wrapper + input.general-select-input-real-value#writer-id(value=(chapter.writer ? chapter.writer._id : '')) + input.general-select-input-selected-value.do-not-listen#writer-search(type='text' autocomplete='off' name='new-password' placeholder=__('Type to search') value=(chapter.writer ? chapter.writer.name : '')) + .general-select-input-choices-wrapper#writer-choices + .general-create-button-wrapper + span.general-create-error#update-error + .general-create-button#update-button= __('Update') + span.general-create-title= __('Translations') + .general-create-seperator + span.general-create-text= __('If you do not add a translation for a language users will see english as the default option. You do not have to change all the given fields for any translation, just leave them as they are.') + .general-create-button-wrapper + span.general-create-title= __('Turkish Translation') + .general-create-seperator + .general-create-input-grid-wrapper + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle= __('Chapter Turkish Title') + input.general-input#turkish-title(type='text' placeholder=__('Enter the Turkish translation of the chapter title. Must be unique.') value=chapter.translations.tr.title) + .general-create-button-wrapper + span.general-create-error#update-turkish-error + .general-create-button#update-turkish-button= __('Update Turkish') + span.general-create-title= __('Russian Translation') + .general-create-seperator + .general-create-input-grid-wrapper + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle= __('Chapter Russian Title') + input.general-input#russian-title(type='text' placeholder=__('Enter the Russian translation of the chapter title. Must be unique.') value=chapter.translations.ru.title) + .general-create-button-wrapper + span.general-create-error#update-russian-error + .general-create-button#update-russian-button= __('Update Russian') diff --git a/views/book/chapter/index.pug b/views/book/chapter/index.pug index 179863d..95f6398 100644 --- a/views/book/chapter/index.pug +++ b/views/book/chapter/index.pug @@ -36,17 +36,22 @@ block main span.general-page-next-button.general-page-next-button-not-allowed #{__('Next')} > span.general-page-info #{__('Showing')} #{children_limit} #{__('results per page.')} .general-items-wrapper + - children.sort((a, b) => (a.type > b.type) ? 1 : -1) each child in children .general-each-item-wrapper(id=child._id) .general-each-item-title-wrapper span.general-each-item-title= child.title + if child.type == 'writing' + span.general-each-item-subtitle(style=(child.is_completed ? '' : 'color: var(--warning-color)')) #{child.is_completed ? '' : `(${__('not completed')})`} .general-each-item-buttons-wrapper .general-each-item-third-button.order-each-children-button= __('Move Up') - .general-each-item-second-button.delete-each-children-button= __('Delete') + //- .general-each-item-second-button.delete-each-children-button= __('Delete') if child.type == 'chapter' if chapter a.general-each-item-fourth-button.show-each-children-chilren-button(href=`${breadcrumps[breadcrumps.length - 1].link},${child._id}`)= __('Chapters') else a.general-each-item-fourth-button.show-each-children-chilren-button(href=`/book/chapter?book_id=${book._id}&chapter_id=${child._id}`)= __('Chapters') - .general-each-item-first-button.edit-child-button= __('Edit & Translate') - \ No newline at end of file + a.general-each-item-first-button.edit-child-button(href=`/book/chapter/edit?id=${child._id}`)= __('Edit & Translate') + else + a.general-each-item-fourth-button.edit-child-button(href=`/book/writing/edit?id=${book._id}&writing_id=${child._id}`)= __('Informations') + a.general-each-item-first-button.edit-child-button(href=`/book/writing/content?id=${book._id}&writing_id=${child._id}`)= __('Edit Content') diff --git a/views/book/edit.pug b/views/book/edit.pug index 1e3ea5a..ee93302 100644 --- a/views/book/edit.pug +++ b/views/book/edit.pug @@ -84,5 +84,4 @@ block main input.general-input.russian-social-account-input(type='text' id='russian-' + social placeholder=__('URL address') value=book.translations.ru.social_media_accounts[social]) .general-create-button-wrapper span.general-create-error#update-russian-error - .general-create-button#update-russian-button= __('Update Russian') - \ No newline at end of file + .general-create-button#update-russian-button= __('Update Russian') \ No newline at end of file diff --git a/views/book/writing/content.pug b/views/book/writing/content.pug new file mode 100644 index 0000000..05705bc --- /dev/null +++ b/views/book/writing/content.pug @@ -0,0 +1,244 @@ +extends ../../partials/navbar +block main + input.display-none#book-json(value=JSON.stringify(book)) + input.display-none#writing-json(value=JSON.stringify(writing)) + input.display-none#translate-json(value=JSON.stringify(translate)) + .general-writing-selection-menu(style='display: none') + svg.general-writing-selection-menu-icon.general-writing-bold-button(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 384 512') + path(d='M0 64C0 46.3 14.3 32 32 32H80 96 224c70.7 0 128 57.3 128 128c0 31.3-11.3 60.1-30 82.3c37.1 22.4 62 63.1 62 109.7c0 70.7-57.3 128-128 128H96 80 32c-17.7 0-32-14.3-32-32s14.3-32 32-32H48V256 96H32C14.3 96 0 81.7 0 64zM224 224c35.3 0 64-28.7 64-64s-28.7-64-64-64H112V224H224zM112 288V416H256c35.3 0 64-28.7 64-64s-28.7-64-64-64H224 112z') + svg.general-writing-selection-menu-icon.general-writing-italic-button(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 384 512') + path(d='M128 64c0-17.7 14.3-32 32-32H352c17.7 0 32 14.3 32 32s-14.3 32-32 32H293.3L160 416h64c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H90.7L224 96H160c-17.7 0-32-14.3-32-32z') + svg.general-writing-selection-menu-icon.general-writing-underline-button(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M16 64c0-17.7 14.3-32 32-32h96c17.7 0 32 14.3 32 32s-14.3 32-32 32H128V224c0 53 43 96 96 96s96-43 96-96V96H304c-17.7 0-32-14.3-32-32s14.3-32 32-32h96c17.7 0 32 14.3 32 32s-14.3 32-32 32H384V224c0 88.4-71.6 160-160 160s-160-71.6-160-160V96H48C30.3 96 16 81.7 16 64zM0 448c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32z') + svg.general-writing-selection-menu-icon.general-writing-url-button(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512') + path(d='M562.8 267.7c56.5-56.5 56.5-148 0-204.5c-50-50-128.8-56.5-186.3-15.4l-1.6 1.1c-14.4 10.3-17.7 30.3-7.4 44.6s30.3 17.7 44.6 7.4l1.6-1.1c32.1-22.9 76-19.3 103.8 8.6c31.5 31.5 31.5 82.5 0 114L405.3 334.8c-31.5 31.5-82.5 31.5-114 0c-27.9-27.9-31.5-71.8-8.6-103.8l1.1-1.6c10.3-14.4 6.9-34.4-7.4-44.6s-34.4-6.9-44.6 7.4l-1.1 1.6C189.5 251.2 196 330 246 380c56.5 56.5 148 56.5 204.5 0L562.8 267.7zM43.2 244.3c-56.5 56.5-56.5 148 0 204.5c50 50 128.8 56.5 186.3 15.4l1.6-1.1c14.4-10.3 17.7-30.3 7.4-44.6s-30.3-17.7-44.6-7.4l-1.6 1.1c-32.1 22.9-76 19.3-103.8-8.6C57 372 57 321 88.5 289.5L200.7 177.2c31.5-31.5 82.5-31.5 114 0c27.9 27.9 31.5 71.8 8.6 103.9l-1.1 1.6c-10.3 14.4-6.9 34.4 7.4 44.6s34.4 6.9 44.6-7.4l1.1-1.6C416.5 260.8 410 182 360 132c-56.5-56.5-148-56.5-204.5 0L43.2 244.3z') + input.general-writing-selection-menu-url-input(style='display: none' type='url' placeholder=__('Paste the link.')) + .general-writing-each-content-item-add-header-choices-wrapper(style='display: none') + .general-writing-each-content-item-add-button-each-header-choice.general-writing-header-choice-1 + svg.general-writing-each-content-item-add-button-each-header-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 64C0 46.3 14.3 32 32 32H80h48c17.7 0 32 14.3 32 32s-14.3 32-32 32H112V208H336V96H320c-17.7 0-32-14.3-32-32s14.3-32 32-32h48 48c17.7 0 32 14.3 32 32s-14.3 32-32 32H400V240 416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H368 320c-17.7 0-32-14.3-32-32s14.3-32 32-32h16V272H112V416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H80 32c-17.7 0-32-14.3-32-32s14.3-32 32-32H48V240 96H32C14.3 96 0 81.7 0 64z') + .general-writing-each-content-item-add-button-each-header-choice-size 1 + .general-writing-each-content-item-add-button-each-header-choice.general-writing-header-choice-2 + svg.general-writing-each-content-item-add-button-each-header-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 64C0 46.3 14.3 32 32 32H80h48c17.7 0 32 14.3 32 32s-14.3 32-32 32H112V208H336V96H320c-17.7 0-32-14.3-32-32s14.3-32 32-32h48 48c17.7 0 32 14.3 32 32s-14.3 32-32 32H400V240 416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H368 320c-17.7 0-32-14.3-32-32s14.3-32 32-32h16V272H112V416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H80 32c-17.7 0-32-14.3-32-32s14.3-32 32-32H48V240 96H32C14.3 96 0 81.7 0 64z') + .general-writing-each-content-item-add-button-each-header-choice-size 2 + .general-writing-each-content-item-add-button-each-header-choice.general-writing-header-choice-3 + svg.general-writing-each-content-item-add-button-each-header-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 64C0 46.3 14.3 32 32 32H80h48c17.7 0 32 14.3 32 32s-14.3 32-32 32H112V208H336V96H320c-17.7 0-32-14.3-32-32s14.3-32 32-32h48 48c17.7 0 32 14.3 32 32s-14.3 32-32 32H400V240 416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H368 320c-17.7 0-32-14.3-32-32s14.3-32 32-32h16V272H112V416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H80 32c-17.7 0-32-14.3-32-32s14.3-32 32-32H48V240 96H32C14.3 96 0 81.7 0 64z') + .general-writing-each-content-item-add-button-each-header-choice-size 3 + .general-writing-each-content-item-add-button-each-header-choice.general-writing-header-choice-4 + svg.general-writing-each-content-item-add-button-each-header-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 64C0 46.3 14.3 32 32 32H80h48c17.7 0 32 14.3 32 32s-14.3 32-32 32H112V208H336V96H320c-17.7 0-32-14.3-32-32s14.3-32 32-32h48 48c17.7 0 32 14.3 32 32s-14.3 32-32 32H400V240 416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H368 320c-17.7 0-32-14.3-32-32s14.3-32 32-32h16V272H112V416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H80 32c-17.7 0-32-14.3-32-32s14.3-32 32-32H48V240 96H32C14.3 96 0 81.7 0 64z') + .general-writing-each-content-item-add-button-each-header-choice-size 4 + .general-writing-each-content-item-add-button-each-header-choice.general-writing-header-choice-5 + svg.general-writing-each-content-item-add-button-each-header-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 64C0 46.3 14.3 32 32 32H80h48c17.7 0 32 14.3 32 32s-14.3 32-32 32H112V208H336V96H320c-17.7 0-32-14.3-32-32s14.3-32 32-32h48 48c17.7 0 32 14.3 32 32s-14.3 32-32 32H400V240 416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H368 320c-17.7 0-32-14.3-32-32s14.3-32 32-32h16V272H112V416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H80 32c-17.7 0-32-14.3-32-32s14.3-32 32-32H48V240 96H32C14.3 96 0 81.7 0 64z') + .general-writing-each-content-item-add-button-each-header-choice-size 5 + .general-writing-each-content-item-add-button-each-header-choice.general-writing-header-choice-6 + svg.general-writing-each-content-item-add-button-each-header-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 64C0 46.3 14.3 32 32 32H80h48c17.7 0 32 14.3 32 32s-14.3 32-32 32H112V208H336V96H320c-17.7 0-32-14.3-32-32s14.3-32 32-32h48 48c17.7 0 32 14.3 32 32s-14.3 32-32 32H400V240 416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H368 320c-17.7 0-32-14.3-32-32s14.3-32 32-32h16V272H112V416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H80 32c-17.7 0-32-14.3-32-32s14.3-32 32-32H48V240 96H32C14.3 96 0 81.7 0 64z') + .general-writing-each-content-item-add-button-each-header-choice-size 6 + //- .general-writing-each-content-item-add-video-url-input(style='display: none' contenteditable='true' spellcheck='false') + input.display-none#general-writing-select-file-input(type='file') + .general-writing-loading-image-prompt(style='display: none') #{__('Loading Image')}... + .general-writing-saving-prompt(style='display: none') #{__('Saving')}... + .general-header-wrapper + .general-header-text-wrapper + .general-header-title #{writing.title} - #{book.name} + .general-header-subtitle= __('Edit & Translate this writing.') + .general-writing-unsaved-changes-text(style='visibility: hidden')= __('You have unsaved changes.') + .general-select-input-wrapper(style='width: 150px; min-width: 180px') + input.general-select-input-real-value#writing-language(value=translate) + input.general-select-input-selected-value(type='text' autocomplete='off' name='new-password' placeholder=__('Choose a language') value=translations[translate]) + .general-select-input-choices-wrapper + each lang in Object.keys(translations) + .general-select-each-input-choice.change-language-input-choice(id='select-input-' + lang)= translations[lang] + .general-header-create-button#save-writing-button= __('Save') + .all-content-inner-wrapper + .general-writing-wrapper + .general-writing-content + label.general-writing-cover-wrapper(style='cursor: pointer') + input.display-none.general-writing-cover-input(type='file') + span.general-writing-cover-placeholder= __('Click to load a cover image to the writing. (752:414)') + img.general-writing-cover-image(alt=writing.title src=`${writing.cover}?${(new Date).getTime()}` style=`display: ${writing.cover ? 'flex' : 'none'}`) + textarea.general-writing-title(contecontenteditable=true spellcheck=false placeholder=__('Writing Title'))= writing.title + textarea.general-writing-subtitle(contenteditable=true spellcheck=false placeholder=__('Writing Subtitle'))= writing.subtitle + .general-writing-content-items-wrapper + .general-writing-each-content-item-wrapper-empty + .general-writing-each-content-item-left-options-wrapper(style='visibility: visible') + .general-writing-each-content-item-options-line + .display-none + .general-writing-each-content-item-add-button-wrapper + .general-writing-each-content-item-add-button + svg.general-writing-each-content-item-add-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M240 80c0-17.7-14.3-32-32-32s-32 14.3-32 32V224H32c-17.7 0-32 14.3-32 32s14.3 32 32 32H176V432c0 17.7 14.3 32 32 32s32-14.3 32-32V288H384c17.7 0 32-14.3 32-32s-14.3-32-32-32H240V80z') + .general-writing-each-content-item-add-button-choices-wrapper(style='background-color: var(--background-color)') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-header + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 64C0 46.3 14.3 32 32 32H80h48c17.7 0 32 14.3 32 32s-14.3 32-32 32H112V208H336V96H320c-17.7 0-32-14.3-32-32s14.3-32 32-32h48 48c17.7 0 32 14.3 32 32s-14.3 32-32 32H400V240 416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H368 320c-17.7 0-32-14.3-32-32s14.3-32 32-32h16V272H112V416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H80 32c-17.7 0-32-14.3-32-32s14.3-32 32-32H48V240 96H32C14.3 96 0 81.7 0 64z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-text + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M192 32h64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H384l0 352c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-352H288V448c0 17.7-14.3 32-32 32s-32-14.3-32-32V352H192c-88.4 0-160-71.6-160-160s71.6-160 160-160z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-image + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512') + path(d='M448 80c8.8 0 16 7.2 16 16V415.8l-5-6.5-136-176c-4.5-5.9-11.6-9.3-19-9.3s-14.4 3.4-19 9.3L202 340.7l-30.5-42.7C167 291.7 159.8 288 152 288s-15 3.7-19.5 10.1l-80 112L48 416.3l0-.3V96c0-8.8 7.2-16 16-16H448zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zm80 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-video + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512') + path(d='M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-list + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512') + path(d='M64 144a48 48 0 1 0 0-96 48 48 0 1 0 0 96zM192 64c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zM64 464a48 48 0 1 0 0-96 48 48 0 1 0 0 96zm48-208a48 48 0 1 0 -96 0 48 48 0 1 0 96 0z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-code + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512') + path(d='M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-quote + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 216C0 149.7 53.7 96 120 96h8c17.7 0 32 14.3 32 32s-14.3 32-32 32h-8c-30.9 0-56 25.1-56 56v8h64c35.3 0 64 28.7 64 64v64c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V320 288 216zm256 0c0-66.3 53.7-120 120-120h8c17.7 0 32 14.3 32 32s-14.3 32-32 32h-8c-30.9 0-56 25.1-56 56v8h64c35.3 0 64 28.7 64 64v64c0 35.3-28.7 64-64 64H320c-35.3 0-64-28.7-64-64V320 288 216z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-ellipsis + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 256a56 56 0 1 1 112 0A56 56 0 1 1 0 256zm160 0a56 56 0 1 1 112 0 56 56 0 1 1 -112 0zm216-56a56 56 0 1 1 0 112 56 56 0 1 1 0-112z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-twitter + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512') + path(d='M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z') + .general-writing-each-content-item-inner-wrapper + .general-writing-each-content-item-right-options-wrapper + each item in writing.content + .general-writing-each-content-item-wrapper + .general-writing-each-content-item-left-options-wrapper + .general-writing-each-content-item-options-line + .general-writing-each-content-item-delete-button + svg.general-writing-each-content-item-delete-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M135.2 17.7C140.6 6.8 151.7 0 163.8 0H284.2c12.1 0 23.2 6.8 28.6 17.7L320 32h96c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 96 0 81.7 0 64S14.3 32 32 32h96l7.2-14.3zM32 128H416V448c0 35.3-28.7 64-64 64H96c-35.3 0-64-28.7-64-64V128zm96 64c-8.8 0-16 7.2-16 16V432c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16zm96 0c-8.8 0-16 7.2-16 16V432c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16zm96 0c-8.8 0-16 7.2-16 16V432c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16z') + .general-writing-each-content-item-add-button-wrapper + .general-writing-each-content-item-add-button + svg.general-writing-each-content-item-add-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M240 80c0-17.7-14.3-32-32-32s-32 14.3-32 32V224H32c-17.7 0-32 14.3-32 32s14.3 32 32 32H176V432c0 17.7 14.3 32 32 32s32-14.3 32-32V288H384c17.7 0 32-14.3 32-32s-14.3-32-32-32H240V80z') + .general-writing-each-content-item-add-button-choices-wrapper + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-header + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 64C0 46.3 14.3 32 32 32H80h48c17.7 0 32 14.3 32 32s-14.3 32-32 32H112V208H336V96H320c-17.7 0-32-14.3-32-32s14.3-32 32-32h48 48c17.7 0 32 14.3 32 32s-14.3 32-32 32H400V240 416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H368 320c-17.7 0-32-14.3-32-32s14.3-32 32-32h16V272H112V416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H80 32c-17.7 0-32-14.3-32-32s14.3-32 32-32H48V240 96H32C14.3 96 0 81.7 0 64z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-text + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M192 32h64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H384l0 352c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-352H288V448c0 17.7-14.3 32-32 32s-32-14.3-32-32V352H192c-88.4 0-160-71.6-160-160s71.6-160 160-160z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-image + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512') + path(d='M448 80c8.8 0 16 7.2 16 16V415.8l-5-6.5-136-176c-4.5-5.9-11.6-9.3-19-9.3s-14.4 3.4-19 9.3L202 340.7l-30.5-42.7C167 291.7 159.8 288 152 288s-15 3.7-19.5 10.1l-80 112L48 416.3l0-.3V96c0-8.8 7.2-16 16-16H448zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zm80 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-video + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512') + path(d='M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-list + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512') + path(d='M64 144a48 48 0 1 0 0-96 48 48 0 1 0 0 96zM192 64c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zM64 464a48 48 0 1 0 0-96 48 48 0 1 0 0 96zm48-208a48 48 0 1 0 -96 0 48 48 0 1 0 96 0z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-code + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512') + path(d='M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-quote + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 216C0 149.7 53.7 96 120 96h8c17.7 0 32 14.3 32 32s-14.3 32-32 32h-8c-30.9 0-56 25.1-56 56v8h64c35.3 0 64 28.7 64 64v64c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V320 288 216zm256 0c0-66.3 53.7-120 120-120h8c17.7 0 32 14.3 32 32s-14.3 32-32 32h-8c-30.9 0-56 25.1-56 56v8h64c35.3 0 64 28.7 64 64v64c0 35.3-28.7 64-64 64H320c-35.3 0-64-28.7-64-64V320 288 216z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-ellipsis + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 256a56 56 0 1 1 112 0A56 56 0 1 1 0 256zm160 0a56 56 0 1 1 112 0 56 56 0 1 1 -112 0zm216-56a56 56 0 1 1 0 112 56 56 0 1 1 0-112z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-twitter + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512') + path(d='M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z') + .general-writing-each-content-item-inner-wrapper !{item.split('').join('').split('').join('')} + .general-writing-each-content-item-right-options-wrapper + .general-writing-each-content-item-options-line + .general-writing-each-content-item-order-up-button + svg.general-writing-each-content-item-order-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M201.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L224 173.3 54.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z') + .general-writing-each-content-item-order-down-button + svg.general-writing-each-content-item-order-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M201.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 338.7 54.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z') + //- .general-writing-each-content-item-wrapper + .general-writing-each-content-item-left-options-wrapper + .general-writing-each-content-item-options-line + .general-writing-each-content-item-delete-button + svg.general-writing-each-content-item-delete-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M135.2 17.7C140.6 6.8 151.7 0 163.8 0H284.2c12.1 0 23.2 6.8 28.6 17.7L320 32h96c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 96 0 81.7 0 64S14.3 32 32 32h96l7.2-14.3zM32 128H416V448c0 35.3-28.7 64-64 64H96c-35.3 0-64-28.7-64-64V128zm96 64c-8.8 0-16 7.2-16 16V432c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16zm96 0c-8.8 0-16 7.2-16 16V432c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16zm96 0c-8.8 0-16 7.2-16 16V432c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16z') + .general-writing-each-content-item-add-button-wrapper + .general-writing-each-content-item-add-button + svg.general-writing-each-content-item-add-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M240 80c0-17.7-14.3-32-32-32s-32 14.3-32 32V224H32c-17.7 0-32 14.3-32 32s14.3 32 32 32H176V432c0 17.7 14.3 32 32 32s32-14.3 32-32V288H384c17.7 0 32-14.3 32-32s-14.3-32-32-32H240V80z') + .general-writing-each-content-item-add-button-choices-wrapper + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-header + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 64C0 46.3 14.3 32 32 32H80h48c17.7 0 32 14.3 32 32s-14.3 32-32 32H112V208H336V96H320c-17.7 0-32-14.3-32-32s14.3-32 32-32h48 48c17.7 0 32 14.3 32 32s-14.3 32-32 32H400V240 416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H368 320c-17.7 0-32-14.3-32-32s14.3-32 32-32h16V272H112V416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H80 32c-17.7 0-32-14.3-32-32s14.3-32 32-32H48V240 96H32C14.3 96 0 81.7 0 64z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-text + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M192 32h64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H384l0 352c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-352H288V448c0 17.7-14.3 32-32 32s-32-14.3-32-32V352H192c-88.4 0-160-71.6-160-160s71.6-160 160-160z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-image + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512') + path(d='M448 80c8.8 0 16 7.2 16 16V415.8l-5-6.5-136-176c-4.5-5.9-11.6-9.3-19-9.3s-14.4 3.4-19 9.3L202 340.7l-30.5-42.7C167 291.7 159.8 288 152 288s-15 3.7-19.5 10.1l-80 112L48 416.3l0-.3V96c0-8.8 7.2-16 16-16H448zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zm80 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-video + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512') + path(d='M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-list + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512') + path(d='M64 144a48 48 0 1 0 0-96 48 48 0 1 0 0 96zM192 64c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zM64 464a48 48 0 1 0 0-96 48 48 0 1 0 0 96zm48-208a48 48 0 1 0 -96 0 48 48 0 1 0 96 0z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-code + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512') + path(d='M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-quote + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 216C0 149.7 53.7 96 120 96h8c17.7 0 32 14.3 32 32s-14.3 32-32 32h-8c-30.9 0-56 25.1-56 56v8h64c35.3 0 64 28.7 64 64v64c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V320 288 216zm256 0c0-66.3 53.7-120 120-120h8c17.7 0 32 14.3 32 32s-14.3 32-32 32h-8c-30.9 0-56 25.1-56 56v8h64c35.3 0 64 28.7 64 64v64c0 35.3-28.7 64-64 64H320c-35.3 0-64-28.7-64-64V320 288 216z') + .general-writing-each-content-item-add-button-each-choice#general-writing-each-choice-ellipsis + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 256a56 56 0 1 1 112 0A56 56 0 1 1 0 256zm160 0a56 56 0 1 1 112 0 56 56 0 1 1 -112 0zm216-56a56 56 0 1 1 0 112 56 56 0 1 1 0-112z') + .general-writing-each-content-item-inner-wrapper + .general-writing-image-wrapper + .general-writing-alt-text(contenteditable='true' spellcheck='false') + img.general-writing-image(src='https://node101.s3.eu-central-1.amazonaws.com/node101-writing-cover-asdfasdf') + .general-writing-image-description(contenteditable='true' spellcheck='false') + .general-writing-each-content-item-right-options-wrapper + .general-writing-each-content-item-options-line + .general-writing-each-content-item-order-up-button + svg.general-writing-each-content-item-order-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M201.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L224 173.3 54.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z') + .general-writing-each-content-item-order-down-button + svg.general-writing-each-content-item-order-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M201.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 338.7 54.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z') + //- .general-writing-each-content-item-wrapper + .general-writing-each-content-item-left-options-wrapper + .general-writing-each-content-item-options-line + .general-writing-each-content-item-delete-button + svg.general-writing-each-content-item-delete-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M135.2 17.7C140.6 6.8 151.7 0 163.8 0H284.2c12.1 0 23.2 6.8 28.6 17.7L320 32h96c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 96 0 81.7 0 64S14.3 32 32 32h96l7.2-14.3zM32 128H416V448c0 35.3-28.7 64-64 64H96c-35.3 0-64-28.7-64-64V128zm96 64c-8.8 0-16 7.2-16 16V432c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16zm96 0c-8.8 0-16 7.2-16 16V432c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16zm96 0c-8.8 0-16 7.2-16 16V432c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16z') + .general-writing-each-content-item-add-button-wrapper + .general-writing-each-content-item-add-button + svg.general-writing-each-content-item-add-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M240 80c0-17.7-14.3-32-32-32s-32 14.3-32 32V224H32c-17.7 0-32 14.3-32 32s14.3 32 32 32H176V432c0 17.7 14.3 32 32 32s32-14.3 32-32V288H384c17.7 0 32-14.3 32-32s-14.3-32-32-32H240V80z') + .general-writing-each-content-item-add-button-choices-wrapper + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-header + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 64C0 46.3 14.3 32 32 32H80h48c17.7 0 32 14.3 32 32s-14.3 32-32 32H112V208H336V96H320c-17.7 0-32-14.3-32-32s14.3-32 32-32h48 48c17.7 0 32 14.3 32 32s-14.3 32-32 32H400V240 416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H368 320c-17.7 0-32-14.3-32-32s14.3-32 32-32h16V272H112V416h16c17.7 0 32 14.3 32 32s-14.3 32-32 32H80 32c-17.7 0-32-14.3-32-32s14.3-32 32-32H48V240 96H32C14.3 96 0 81.7 0 64z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-text + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M192 32h64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H384l0 352c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-352H288V448c0 17.7-14.3 32-32 32s-32-14.3-32-32V352H192c-88.4 0-160-71.6-160-160s71.6-160 160-160z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-image + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512') + path(d='M448 80c8.8 0 16 7.2 16 16V415.8l-5-6.5-136-176c-4.5-5.9-11.6-9.3-19-9.3s-14.4 3.4-19 9.3L202 340.7l-30.5-42.7C167 291.7 159.8 288 152 288s-15 3.7-19.5 10.1l-80 112L48 416.3l0-.3V96c0-8.8 7.2-16 16-16H448zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zm80 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-video + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512') + path(d='M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-list + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512') + path(d='M64 144a48 48 0 1 0 0-96 48 48 0 1 0 0 96zM192 64c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32H480c17.7 0 32-14.3 32-32s-14.3-32-32-32H192zM64 464a48 48 0 1 0 0-96 48 48 0 1 0 0 96zm48-208a48 48 0 1 0 -96 0 48 48 0 1 0 96 0z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-code + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512') + path(d='M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z') + .general-writing-each-content-item-add-button-each-choice.general-writing-each-choice-quote + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 216C0 149.7 53.7 96 120 96h8c17.7 0 32 14.3 32 32s-14.3 32-32 32h-8c-30.9 0-56 25.1-56 56v8h64c35.3 0 64 28.7 64 64v64c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V320 288 216zm256 0c0-66.3 53.7-120 120-120h8c17.7 0 32 14.3 32 32s-14.3 32-32 32h-8c-30.9 0-56 25.1-56 56v8h64c35.3 0 64 28.7 64 64v64c0 35.3-28.7 64-64 64H320c-35.3 0-64-28.7-64-64V320 288 216z') + .general-writing-each-content-item-add-button-each-choice#general-writing-each-choice-ellipsis + svg.general-writing-each-content-item-add-button-each-choice-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M0 256a56 56 0 1 1 112 0A56 56 0 1 1 0 256zm160 0a56 56 0 1 1 112 0 56 56 0 1 1 -112 0zm216-56a56 56 0 1 1 0 112 56 56 0 1 1 0-112z') + .general-writing-each-content-item-inner-wrapper !{'
askldjf asjdaslkdfjalskdf this is bold askdjf this is this is italic bold aksdjf
'} + .general-writing-each-content-item-right-options-wrapper + .general-writing-each-content-item-options-line + .general-writing-each-content-item-order-up-button + svg.general-writing-each-content-item-order-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M201.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L224 173.3 54.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z') + .general-writing-each-content-item-order-down-button + svg.general-writing-each-content-item-order-button-icon(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512') + path(d='M201.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 338.7 54.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z') \ No newline at end of file diff --git a/views/book/writing/delete.pug b/views/book/writing/delete.pug new file mode 100644 index 0000000..dc2a0d1 --- /dev/null +++ b/views/book/writing/delete.pug @@ -0,0 +1,38 @@ +extends ../../partials/navbar +block main + input.display-none#book-json(value=JSON.stringify(book)) + .general-header-wrapper + .general-header-text-wrapper + .general-header-title #{__('Deleted Writings')} - #{book.title} + .general-header-subtitle= __('See and restore deleted writings.') + input.general-header-search-input#writing-search-input(type='text' placeholder='Search by title or subtitle' value=writings_search) + .general-header-create-button#create-writing-button= __('Add Writing') + .all-content-inner-wrapper + .general-page-wrapper + if writings_search + span.general-page-search-text #{__('Showing results of the search:')} "#{writings_search}" + .general-page-inner-wrapper + .general-page-buttons-wrapper + if writings_page > 0 + a.general-page-prev-button(href=`/writing?page=${writings_page-1}${writings_search ? '&search=' + writings_search : ''}`) < #{__('Previous')} + else + span.general-page-prev-button.general-page-prev-button-not-allowed < #{__('Previous')} + - for (let i = 0; i < parseInt(writings_count / writings_limit) + (writings_count % writings_limit ? 1 : 0); i += 1) + if i != writings_page + a.general-each-page-button(href=`/writing?page=${i}${writings_search ? '&search=' + writings_search : ''}`)= i+1 + else + span.general-each-page-button.general-each-page-button-selected= i+1 + if (writings_page + 1) * writings_limit < writings_count + a.general-page-next-button(href=`/writing?page=${writings_page+1}${writings_search ? '&search=' + writings_search : ''}`) #{__('Next')} > + else + span.general-page-next-button.general-page-next-button-not-allowed #{__('Next')} > + span.general-page-info #{__('Showing')} #{writings_limit} #{__('results per page.')} + a.all-writings-button(href='/book/writing?id=' + book._id)= __('All Writings') + .general-items-wrapper + each writing in writings + .general-each-item-wrapper(id=writing._id) + .general-each-item-title-wrapper + span.general-each-item-title= writing.title + span.general-each-item-subtitle(style='color: var(--warning-color)') (#{__('deleted')}) + .general-each-item-buttons-wrapper + a.general-each-item-first-button.restore-each-writing-button= __('Restore') \ No newline at end of file diff --git a/views/book/writing/edit.pug b/views/book/writing/edit.pug new file mode 100644 index 0000000..9ab2ac2 --- /dev/null +++ b/views/book/writing/edit.pug @@ -0,0 +1,149 @@ +extends ../../partials/navbar +block main + input.display-none#book-json(type='text' value=JSON.stringify(book)) + input.display-none#writing-json(type='text' value=JSON.stringify(writing)) + .general-header-wrapper + .general-header-text-wrapper + .general-header-title #{__('Edit Writing')} - #{writing.title} + .general-header-subtitle= __('Edit the writing information and translate the writing. Please use edit content page to change the content of the writing') + input.general-header-search-input#writing-search-input(autocomplete='search' name='new-password' placeholder='Search by title or subtitle' value='') + .all-content-inner-wrapper + .general-create-wrapper + if !writing.is_completed + .general-create-info= __('IMPORTANT! This writing is not yet complete. Please complete all the required fields to start using this writing in the website.') + span.general-create-title= __('General Information') + .general-create-seperator + .general-create-input-grid-wrapper + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Writing Title') + input.general-input#title(type='text' placeholder=__('Enter the writing title. Must be unique.') value=writing.title) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Writer') + .general-select-input-wrapper + input.general-select-input-real-value#writer-id(value=(writing.writer ? writing.writer._id : '')) + input.general-select-input-selected-value.do-not-listen#writer-search(type='text' autocomplete='off' name='new-password' placeholder=__('Type to search') value=(writing.writer ? writing.writer.name : '')) + .general-select-input-choices-wrapper#writer-choices + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Writing Subtitle') + input.general-input#subtitle(type='text' placeholder=__('Enter a short subtitle to show on writing preview.') value=writing.subtitle) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Writing Logo') + if writing.logo + label.general-image-input-wrapper(style='cursor: default') + .general-image-input-image(style=`background-image: url(${writing.logo}?${new Date().getTime()})`) + svg.general-image-input-delete-button(fill='var(--warning-color)' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 512') + path(d='M310.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L160 210.7 54.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L114.7 256 9.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 301.3 265.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L205.3 256 310.6 150.6z') + else + label.general-image-input-wrapper(style='cursor: pointer') + input.display-none#image(type='file') + span.general-image-input-placeholder= __('Upload from your device.') + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Created At') + input.general-input#date(type='date' placeholder=__('The date the writing is created') value=fromDateToHTMLInputString(writing.created_at)) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Label') + .general-select-input-wrapper + input.general-select-input-real-value#label(value=writing.label) + input.general-select-input-selected-value(type='text' autocomplete='off' name='new-password' placeholder=__('Type to choose a label') value=labels[writing.label || 'none']) + .general-select-input-choices-wrapper + each label in Object.keys(labels) + .general-select-each-input-choice(id='select-input-' + label)= labels[label] + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle= __('Flag') + input.general-input#flag(type='text' placeholder=__('Add a custom flag to writing') value=writing.flag) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Is Visible') + .general-select-input-wrapper + input.general-select-input-real-value#is-hidden(value=JSON.stringify(writing.is_hidden)) + input.general-select-input-selected-value(type='text' autocomplete='off' name='new-password' placeholder=__('Type to choose a label') value=(writing.is_hidden ? __('No, this writing is hidden from users.') : __('Yes, this writing is visible to users.'))) + .general-select-input-choices-wrapper + .general-select-each-input-choice(id='select-input-false')= __('Yes, this writing is visible to users.') + .general-select-each-input-choice(id='select-input-true')= __('No, this writing is hidden from users.') + each social in Object.keys(socialAccounts) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle #{__('Writing')} #{socialAccounts[social]} + input.general-input.social-account-input(type='text' id=social placeholder=__('URL address') value=writing.social_media_accounts[social]) + .general-create-button-wrapper + span.general-create-error#update-error + .general-create-button#update-button= __('Update') + span.general-create-title= __('Translations') + .general-create-seperator + span.general-create-text= __('If you do not add a translation for a language users will see english as the default option. You do not have to change all the given fields for any translation, just leave them as they are.') + .general-create-button-wrapper + span.general-create-title= __('Turkish Translation') + .general-create-seperator + .general-create-input-grid-wrapper.turkish-translation + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Writing Turkish Title') + input.general-input#turkish-title(type='text' placeholder=__('Enter the Turkish translation of the writing title. Must be unique.') value=writing.translations.tr.title) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Writing Turkish Subtitle') + input.general-input#turkish-subtitle(type='text' placeholder=__('Enter the Turkish translation of the writing subtitle.') value=writing.translations.tr.subtitle) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle= __('Turkish Flag') + input.general-input#turkish-flag(type='text' placeholder=__('Translate the custom flag to turkish') value=writing.translations.tr.flag) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Is Turkish Visible') + .general-select-input-wrapper + input.general-select-input-real-value#turkish-is-hidden(value=JSON.stringify(writing.translations.tr.is_hidden)) + input.general-select-input-selected-value(type='text' autocomplete='off' name='new-password' placeholder=__('Type to choose a label') value=(writing.translations.tr.is_hidden ? __('No, this writing is hidden from users in turkish.') : __('Yes, this writing is visible to users in turkish.'))) + .general-select-input-choices-wrapper + .general-select-each-input-choice(id='select-input-false')= __('Yes, this writing is visible to users in turkish.') + .general-select-each-input-choice(id='select-input-true')= __('No, this writing is hidden from users in turkish.') + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Writing Turkish Logo') + if writing.translations.tr.logo + label.general-image-input-wrapper(style='cursor: default') + .general-image-input-image(style=`background-image: url(${writing.translations.tr.logo}?${new Date().getTime()})`) + svg.general-image-input-delete-button(fill='var(--warning-color)' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 512') + path(d='M310.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L160 210.7 54.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L114.7 256 9.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 301.3 265.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L205.3 256 310.6 150.6z') + else + label.general-image-input-wrapper(style='cursor: pointer') + input.display-none#image(type='file') + span.general-image-input-placeholder= __('Upload from your device.') + each social in Object.keys(socialAccounts) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle #{__('Writing Turkish')} #{socialAccounts[social]} + input.general-input.turkish-social-account-input(type='text' id='turkish-' + social placeholder=__('URL address') value=writing.translations.tr.social_media_accounts[social]) + .general-create-button-wrapper + span.general-create-error#update-turkish-error + .general-create-button#update-turkish-button= __('Update Turkish') + span.general-create-title= __('Russian Translation') + .general-create-seperator + .general-create-input-grid-wrapper.russian-translation + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Writing Russian Title') + input.general-input#russian-title(type='text' placeholder=__('Enter the Russian translation of the writing title. Must be unique.') value=writing.translations.ru.title) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Writing Russian Subtitle') + input.general-input#russian-subtitle(type='text' placeholder=__('Enter the Russian translation of the writing subtitle.') value=writing.translations.ru.subtitle) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle= __('Russian Flag') + input.general-input#russian-flag(type='text' placeholder=__('Translate the custom flag to russian') value=writing.translations.ru.flag) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Is Russian Visible') + .general-select-input-wrapper + input.general-select-input-real-value#russian-is-hidden(value=JSON.stringify(writing.translations.ru.is_hidden)) + input.general-select-input-selected-value(type='text' autocomplete='off' name='new-password' placeholder=__('Type to choose a label') value=(writing.translations.ru.is_hidden ? __('No, this writing is hidden from users in russian.') : __('Yes, this writing is visible to users in russian.'))) + .general-select-input-choices-wrapper + .general-select-each-input-choice(id='select-input-false')= __('Yes, this writing is visible to users in russian.') + .general-select-each-input-choice(id='select-input-true')= __('No, this writing is hidden from users in russian.') + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle.general-create-required= __('Writing Russian Logo') + if writing.translations.ru.logo + label.general-image-input-wrapper(style='cursor: default') + .general-image-input-image(style=`background-image: url(${writing.translations.ru.logo}?${new Date().getTime()})`) + svg.general-image-input-delete-button(fill='var(--warning-color)' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 512') + path(d='M310.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L160 210.7 54.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L114.7 256 9.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 301.3 265.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L205.3 256 310.6 150.6z') + else + label.general-image-input-wrapper(style='cursor: pointer') + input.display-none.russian-logo#image(type='file') + span.general-image-input-placeholder= __('Upload from your device.') + each social in Object.keys(socialAccounts) + .general-create-input-grid-each-item-wrapper + span.general-create-subtitle #{__('Writing Russian')} #{socialAccounts[social]} + input.general-input.russian-social-account-input(type='text' id='russian-' + social placeholder=__('URL address') value=writing.translations.ru.social_media_accounts[social]) + .general-create-button-wrapper + span.general-create-error#update-russian-error + .general-create-button#update-russian-button= __('Update Russian') + \ No newline at end of file diff --git a/views/book/writing/index.pug b/views/book/writing/index.pug new file mode 100644 index 0000000..8562b15 --- /dev/null +++ b/views/book/writing/index.pug @@ -0,0 +1,43 @@ +extends ../../partials/navbar +block main + input.display-none#book-json(value=JSON.stringify(book)) + input.display-none#copy-element + .general-header-wrapper + .general-header-text-wrapper + .general-header-title #{__('Writings')} - #{book.title} + .general-header-subtitle= __('Add writings to this book.') + input.general-header-search-input#writing-search-input(type='text' placeholder='Search by title or subtitle' value=writings_search) + .general-header-create-button#create-writing-button= __('Add Writing') + .all-content-inner-wrapper + .general-page-wrapper + if writings_search + span.general-page-search-text #{__('Showing results of the search:')} "#{writings_search}" + .general-page-inner-wrapper + .general-page-buttons-wrapper + if writings_page > 0 + a.general-page-prev-button(href=`/book/writing?id=${book._id}&page=${writings_page-1}${writings_search ? '&search=' + writings_search : ''}`) < #{__('Previous')} + else + span.general-page-prev-button.general-page-prev-button-not-allowed < #{__('Previous')} + - for (let i = 0; i < parseInt(writings_count / writings_limit) + (writings_count % writings_limit ? 1 : 0); i += 1) + if i != writings_page + a.general-each-page-button(href=`/book/writing?id=${book._id}&page=${i}${writings_search ? '&search=' + writings_search : ''}`)= i+1 + else + span.general-each-page-button.general-each-page-button-selected= i+1 + if (writings_page + 1) * writings_limit < writings_count + a.general-page-next-button(href=`/book/writing?id=${book._id}&page=${writings_page+1}${writings_search ? '&search=' + writings_search : ''}`) #{__('Next')} > + else + span.general-page-next-button.general-page-next-button-not-allowed #{__('Next')} > + span.general-page-info #{__('Showing')} #{writings_limit} #{__('results per page.')} + a.deleted-writings-button(href='/book/writing/delete?id=' + book._id)= __('Deleted Writings') + .general-items-wrapper + each writing in writings + .general-each-item-wrapper(id=writing._id) + .general-each-item-title-wrappergi + span.general-each-item-title= writing.title + span.general-each-item-subtitle(style=(writing.is_completed ? '' : 'color: var(--warning-color)')) #{writing.is_completed ? '' : `(${__('not completed')})`} + .general-each-item-buttons-wrapper + .general-each-item-third-button.order-each-writing-button= __('Move Up') + .general-each-item-fifth-button.copy-static-link-each-writing-button= __('Copy Static Link') + .general-each-item-second-button.delete-each-writing-button= __('Delete') + a.general-each-item-fourth-button(href=`/book/writing/edit?id=${book._id}&writing_id=${writing._id}`)= __('Informations') + a.general-each-item-first-button(href=`/book/writing/content?id=${book._id}&writing_id=${writing._id}`)= __('Edit Content') \ No newline at end of file