1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-07-27 06:01:54 +03:00

Converted md settings to localstorage, added preview resize

This commit is contained in:
Dan Brown
2022-11-28 14:08:20 +00:00
parent 38db3a28ea
commit 31c28be57a
8 changed files with 102 additions and 102 deletions

View File

@ -14,7 +14,11 @@ export class MarkdownEditor extends Component {
this.display = this.$refs.display;
this.input = this.$refs.input;
this.settingContainer = this.$refs.settingContainer;
this.divider = this.$refs.divider;
this.displayWrap = this.$refs.displayWrap;
const settingContainer = this.$refs.settingContainer;
const settingInputs = settingContainer.querySelectorAll('input[type="checkbox"]');
this.editor = null;
initEditor({
@ -23,11 +27,11 @@ export class MarkdownEditor extends Component {
displayEl: this.display,
inputEl: this.input,
drawioUrl: this.getDrawioUrl(),
settingInputs: Array.from(settingInputs),
text: {
serverUploadLimit: this.serverUploadLimitText,
imageUploadError: this.imageUploadErrorText,
},
settings: this.loadSettings(),
}).then(editor => {
this.editor = editor;
this.setupListeners();
@ -76,30 +80,40 @@ export class MarkdownEditor extends Component {
toolbarLabel.closest('.markdown-editor-wrap').classList.add('active');
});
// Setting changes
this.settingContainer.addEventListener('change', e => {
const actualInput = e.target.parentNode.querySelector('input[type="hidden"]');
const name = actualInput.getAttribute('name');
const value = actualInput.getAttribute('value');
window.$http.patch('/preferences/update-boolean', {name, value});
this.editor.settings.set(name, value === 'true');
});
// Refresh CodeMirror on container resize
const resizeDebounced = debounce(() => this.editor.cm.refresh(), 100, false);
const observer = new ResizeObserver(resizeDebounced);
observer.observe(this.elem);
this.handleDividerDrag();
}
loadSettings() {
const settings = {};
const inputs = this.settingContainer.querySelectorAll('input[type="hidden"]');
handleDividerDrag() {
this.divider.addEventListener('pointerdown', event => {
const wrapRect = this.elem.getBoundingClientRect();
const moveListener = (event) => {
const xRel = event.pageX - wrapRect.left;
const xPct = Math.min(Math.max(20, Math.floor((xRel / wrapRect.width) * 100)), 80);
this.displayWrap.style.flexBasis = `${100-xPct}%`;
this.editor.settings.set('editorWidth', xPct);
};
const upListener = (event) => {
window.removeEventListener('pointermove', moveListener);
window.removeEventListener('pointerup', upListener);
this.display.style.pointerEvents = null;
document.body.style.userSelect = null;
this.editor.cm.refresh();
};
for (const input of inputs) {
settings[input.getAttribute('name')] = input.value === 'true';
this.display.style.pointerEvents = 'none';
document.body.style.userSelect = 'none';
window.addEventListener('pointermove', moveListener);
window.addEventListener('pointerup', upListener);
});
const widthSetting = this.editor.settings.get('editorWidth');
if (widthSetting) {
this.displayWrap.style.flexBasis = `${100-widthSetting}%`;
}
return settings;
}
scrollToTextIfNeeded() {

View File

@ -19,7 +19,7 @@ export async function init(config) {
const editor = {
config,
markdown: new Markdown(),
settings: new Settings(config.settings),
settings: new Settings(config.settingInputs),
};
editor.actions = new Actions(editor);
@ -39,8 +39,8 @@ export async function init(config) {
* @property {Element} displayEl
* @property {HTMLTextAreaElement} inputEl
* @property {String} drawioUrl
* @property {HTMLInputElement[]} settingInputs
* @property {Object<String, String>} text
* @property {Object<String, any>} settings
*/
/**

View File

@ -1,40 +1,62 @@
import {kebabToCamel} from "../services/text";
export class Settings {
constructor(initialSettings) {
this.settingMap = {};
constructor(settingInputs) {
this.settingMap = {
scrollSync: true,
showPreview: true,
editorWidth: 50,
};
this.changeListeners = {};
this.merge(initialSettings);
this.loadFromLocalStorage();
this.applyToInputs(settingInputs);
this.listenToInputChanges(settingInputs);
}
applyToInputs(inputs) {
for (const input of inputs) {
const name = input.getAttribute('name').replace('md-', '');
input.checked = this.settingMap[name];
}
}
listenToInputChanges(inputs) {
for (const input of inputs) {
input.addEventListener('change', event => {
const name = input.getAttribute('name').replace('md-', '');
this.set(name, input.checked);
});
}
}
loadFromLocalStorage() {
const lsValString = window.localStorage.getItem('md-editor-settings');
if (!lsValString) {
return;
}
const lsVals = JSON.parse(lsValString);
for (const [key, value] of Object.entries(lsVals)) {
if (value !== null && this.settingMap[key] !== undefined) {
this.settingMap[key] = value;
}
}
}
set(key, value) {
key = this.normaliseKey(key);
this.settingMap[key] = value;
window.localStorage.setItem('md-editor-settings', JSON.stringify(this.settingMap));
for (const listener of (this.changeListeners[key] || [])) {
listener(value);
}
}
get(key) {
return this.settingMap[this.normaliseKey(key)] || null;
}
merge(settings) {
for (const [key, value] of Object.entries(settings)) {
this.set(key, value);
}
return this.settingMap[key] || null;
}
onChange(key, callback) {
key = this.normaliseKey(key);
const listeners = this.changeListeners[this.normaliseKey(key)] || [];
const listeners = this.changeListeners[key] || [];
listeners.push(callback);
this.changeListeners[this.normaliseKey(key)] = listeners;
}
normaliseKey(key) {
return kebabToCamel(key.replace('md-', ''));
this.changeListeners[key] = listeners;
}
}