fipamo/public/assets/scripts/dash/app/controllers/PageEditor.js
ro 981d182d1a
style, state and bounding tweaks for editor
new floating text formatter had some reveal state issues, some styling
wonkyness and didn't have any bounding rules, so all of that has been
addressed.

also removed css references to a component that has been removed.
2025-05-18 12:20:39 -06:00

330 lines
9.4 KiB
JavaScript

//TOOLS
import ContentRequest, {
TASK_PAGE_CREATE,
TASK_PAGE_EDIT,
TASK_PAGE_DELETE
} from '../../libraries/ContentRequest.js';
import Maintenance from '../../libraries/MaintenanceRequest.js';
import * as DataEvent from '../events/DataEvent.js';
import PageActions from '../actions/PageActions.js';
import * as EditorEvent from '../events/EditorEvent.js';
import TextEditor from '../ui/TextEditor.js';
import Notfications from '../ui/Notifications.js';
import FileManager from '../ui/FileManager.js';
const notify = new Notfications();
export default class PostEditor {
//--------------------------
// constructor
//--------------------------
constructor() {
this.processing = false;
this.textSelected = false;
this.activeSelect = false;
let self = this;
this.cr = new ContentRequest(null, document.getElementById('notify-progress'));
this.mr = new Maintenance(null, null);
this.urlPieces = document.URL.split('/');
this.post = [];
this.postID = null;
this.postUUID = null;
this.postLayout = null;
this.fm = null;
if (document.querySelector('.file-manager').getAttribute('data-index')) {
this.postID = document
.querySelector('.file-manager')
.getAttribute('data-index');
this.postUUID = document
.querySelector('.file-manager')
.getAttribute('data-uuid');
this.postLayout = document
.querySelector('.file-manager')
.getAttribute('data-layout');
}
let textEdit = document.getElementById('edit');
let control = document.querySelector('.text-editor-control');
textEdit.addEventListener('selectionchange', e => {
let start = e.target.selectionStart;
let end = e.target.selectionEnd;
if (start != end) {
this.activeSelect = true;
if (!self.textSelected) {
self.textSelected = true;
control.classList.remove('hide-el');
control.classList.add('show-grid');
}
}
});
textEdit.addEventListener('click', e => {
let start = e.target.selectionStart;
let end = e.target.selectionEnd;
if (start == end) {
if (self.textSelected) {
self.textSelected = false;
this.activeSelect = false;
control.classList.add('hide-el');
control.classList.remove('show-grid');
}
}
});
textEdit.addEventListener('blur', e => {
control.classList.add('hide-el');
control.classList.remove('show-grid');
});
textEdit.addEventListener('mouseup', e => {
if (window.getSelection().toString().length > 0) {
// Get selected text and encode it
const selection = encodeURIComponent(
window.getSelection().toString()
).replace(/[!'()*]/g, escape);
// Find out how much (if any) user has scrolled
var scrollTop =
window.pageYOffset !== undefined
? window.pageYOffset
: (
document.documentElement ||
document.body.parentNode ||
document.body
).scrollTop;
// Get cursor position
let posX = event.clientX - 110;
let posY = event.clientY + 20 + scrollTop;
let rect = document.querySelector('.text-editor').getBoundingClientRect();
let tangle = document
.querySelector('.text-editor-control')
.getBoundingClientRect();
//check for left side
if (posX < rect.left) {
posX = rect.left;
}
//check for right side
let editorWidth = rect.right - rect.left;
let controlWidth = tangle.right - tangle.left;
if (controlWidth + posX - rect.left > editorWidth) {
let adjust = controlWidth + posX - rect.left - editorWidth;
posX = posX - adjust;
}
document.querySelector('.text-editor-control').style.left = posX + 'px';
document.querySelector('.text-editor-control').style.top = posY + 'px';
}
});
if (document.getElementById('edit')) {
this.editor = new TextEditor(
document.getElementById('edit'),
document.querySelector('.page-meta').offsetHeight +
document.querySelector('.file-manager').offsetHeight +
document.querySelector('.text-editor').offsetHeight
);
this.editor.addListener(
EditorEvent.EDITOR_DELETE,
() => this.handleEditorOptions(EditorEvent.EDITOR_DELETE),
false
);
this.editor.addListener(
EditorEvent.EDITOR_UPLOAD_POST_IMAGE,
() => this.handleEditorOptions(EditorEvent.EDITOR_UPLOAD_POST_IMAGE),
false
);
this.editor.addListener(
EditorEvent.EDITOR_UPDATE,
() => this.handleEditorOptions(EditorEvent.EDITOR_UPDATE),
false
);
this.editor.addListener(
EditorEvent.EDITOR_SAVE,
() => this.handleEditorOptions(EditorEvent.EDITOR_SAVE),
false
);
document.getElementById('post-image-upload').addEventListener(
'change',
e => {
this.handleImageUpload(e.target.id, e.target.files);
},
false
);
/*
TinyDatePicker(document.getElementById('post-date'), {
mode: 'dp-below',
format() {
//return self.dateUtils.getDate('origin', date);
}
});
*/
this.start();
}
}
//--------------------------
// methods
//--------------------------
start() {
if (document.querySelector('.file-drop')) {
//insert fileManager here
this.fm = new FileManager(
document.querySelector('.file-drop'),
document.getElementById('page-files-upload'),
document.getElementById('page-images-list'),
document.querySelector('.page-files-list')
);
var optionButtons = document.querySelectorAll('.post-option-btn');
for (var i = 0, length = optionButtons.length; i < length; i++) {
optionButtons[i].addEventListener(
'click',
e => this.handlePostOptions(e),
false
);
}
}
let metabtn = document.getElementById('');
let metas = document.querySelectorAll('#meta-info-toggle');
let meta = document.querySelector('.meta');
for (var i = 0, length = metas.length; i < length; i++) {
metas[i].addEventListener('click', e => {
let metaO = window.getComputedStyle(meta).getPropertyValue('opacity');
if (metaO == 0) {
meta.classList.remove('hide-el');
meta.classList.add('show-grid');
} else {
meta.classList.add('hide-el');
meta.classList.remove('show-grid');
}
});
}
document.getElementById('files-upload').addEventListener('click', e => {
document.getElementById('page-files-upload').click();
});
}
//--------------------------
// event handlers
//--------------------------
handlePostOptions(e) {
let currentOption = null;
switch (e.target.id) {
case 'option-page-icon':
case 'option-menu-pin':
currentOption = document.getElementById('option-menu-pin');
break;
case 'option-feature-icon':
case 'option-feature':
currentOption = document.getElementById('option-feature');
break;
case 'option-published-icon':
case 'option-published':
currentOption = document.getElementById('option-published');
break;
}
if (currentOption != null) {
let active = currentOption.getAttribute('data-active');
if (active == 'false') {
currentOption.setAttribute('data-active', 'true');
currentOption.setAttribute('aria-pressed', 'true');
} else {
currentOption.setAttribute('data-active', 'false');
currentOption.setAttribute('aria-pressed', 'false');
}
}
}
handleEditorOptions(e) {
if (this.processing) return;
let self = this;
switch (e) {
case EditorEvent.EDITOR_SAVE:
case EditorEvent.EDITOR_UPDATE:
var task = '';
e === EditorEvent.EDITOR_SAVE
? (task = TASK_PAGE_CREATE)
: (task = TASK_PAGE_EDIT);
new PageActions().collectInfo(this.fm.getFileOrder()).then(page => {
self.processing = true;
notify.alert('Writing down changes', null);
self.cr
.pageActions(task, page)
.then(r => {
self.processing = false;
if (
r.type === DataEvent.PAGE_ERROR ||
r.type === DataEvent.API_REQUEST_LAME
) {
notify.alert(r.message, false);
} else {
if (r.type === DataEvent.PAGE_UPDATED) {
notify.alert(r.message, true);
} else {
notify.alert(r.message, true);
window.location = '/dashboard/pages/edit/' + r.id;
}
}
})
.catch(err => {
self.processing = false;
notify.alert(err, false);
});
});
break;
case EditorEvent.EDITOR_DELETE:
if (this.postLayout === 'index') {
notify.alert('Index cannot be deleted', false);
return;
}
if (confirm("AYE! You know you're deleting this post, right?")) {
new PageActions()
.collectInfo(this.fm.getFileOrder())
.then(page => {
self.processing = true;
this.cr
.pageActions(TASK_PAGE_DELETE, page)
.then(() => {
self.processing = false;
window.location = '/dashboard/pages';
})
.catch(err => {
self.processing = false;
notify.alert(err, false);
});
})
.catch(() => {});
} else {
// Do nothing!
}
break;
case EditorEvent.EDITOR_UPLOAD_POST_IMAGE:
document.getElementById('post-image-upload').click();
break;
}
}
handleImageUpload(type, files) {
let self = this;
notify.alert('Uploading Image', null);
let upload = new FormData();
upload.enctype = 'multipart/form-data';
upload.append('upload_files[]', files[0], files[0].name);
this.mr
.filesUpload(files[0].type, upload)
.then(result => {
if (result.message == 'File Uploaded. Great!') {
self.editor.notify(
EditorEvent.EDITOR_UPLOAD_POST_IMAGE,
result.filePath
);
notify.alert('Image Added to Entry', true);
} else {
notify.alert('Uh oh. Image not added', false);
}
})
.catch(() => {
notify.alert('Uh oh. Image not added', false);
});
}
}