forked from FINAKON/HelpProject
1. Initial Commit - a boiler plate code and POC to realize the concept of context sensitive help 2. Frontend code written in ReactJS 3. Backend code written in Java, Spring Boot Framework 4. Frontend Start: pre-requisites : node, npm npm run dev ==> to start the frontend vite server 5. Backend Start: pre-requisites : java, mvn mvn spring-boot:run ==> to start the backend server 6. Visit http://localhost:5173/ for basic demo of help, press F1 in textboxes 7. Visit http://localhost:5173/editor and enter "admin123" to add/modify texts. Happy Coding !!! Thank you, Bhargava.
175 lines
4.4 KiB
JavaScript
175 lines
4.4 KiB
JavaScript
import extend from 'extend';
|
|
import Delta from 'quill-delta';
|
|
import Parchment from 'parchment';
|
|
import Break from './break';
|
|
import Inline from './inline';
|
|
import TextBlot from './text';
|
|
|
|
|
|
const NEWLINE_LENGTH = 1;
|
|
|
|
|
|
class BlockEmbed extends Parchment.Embed {
|
|
attach() {
|
|
super.attach();
|
|
this.attributes = new Parchment.Attributor.Store(this.domNode);
|
|
}
|
|
|
|
delta() {
|
|
return new Delta().insert(this.value(), extend(this.formats(), this.attributes.values()));
|
|
}
|
|
|
|
format(name, value) {
|
|
let attribute = Parchment.query(name, Parchment.Scope.BLOCK_ATTRIBUTE);
|
|
if (attribute != null) {
|
|
this.attributes.attribute(attribute, value);
|
|
}
|
|
}
|
|
|
|
formatAt(index, length, name, value) {
|
|
this.format(name, value);
|
|
}
|
|
|
|
insertAt(index, value, def) {
|
|
if (typeof value === 'string' && value.endsWith('\n')) {
|
|
let block = Parchment.create(Block.blotName);
|
|
this.parent.insertBefore(block, index === 0 ? this : this.next);
|
|
block.insertAt(0, value.slice(0, -1));
|
|
} else {
|
|
super.insertAt(index, value, def);
|
|
}
|
|
}
|
|
}
|
|
BlockEmbed.scope = Parchment.Scope.BLOCK_BLOT;
|
|
// It is important for cursor behavior BlockEmbeds use tags that are block level elements
|
|
|
|
|
|
class Block extends Parchment.Block {
|
|
constructor(domNode) {
|
|
super(domNode);
|
|
this.cache = {};
|
|
}
|
|
|
|
delta() {
|
|
if (this.cache.delta == null) {
|
|
this.cache.delta = this.descendants(Parchment.Leaf).reduce((delta, leaf) => {
|
|
if (leaf.length() === 0) {
|
|
return delta;
|
|
} else {
|
|
return delta.insert(leaf.value(), bubbleFormats(leaf));
|
|
}
|
|
}, new Delta()).insert('\n', bubbleFormats(this));
|
|
}
|
|
return this.cache.delta;
|
|
}
|
|
|
|
deleteAt(index, length) {
|
|
super.deleteAt(index, length);
|
|
this.cache = {};
|
|
}
|
|
|
|
formatAt(index, length, name, value) {
|
|
if (length <= 0) return;
|
|
if (Parchment.query(name, Parchment.Scope.BLOCK)) {
|
|
if (index + length === this.length()) {
|
|
this.format(name, value);
|
|
}
|
|
} else {
|
|
super.formatAt(index, Math.min(length, this.length() - index - 1), name, value);
|
|
}
|
|
this.cache = {};
|
|
}
|
|
|
|
insertAt(index, value, def) {
|
|
if (def != null) return super.insertAt(index, value, def);
|
|
if (value.length === 0) return;
|
|
let lines = value.split('\n');
|
|
let text = lines.shift();
|
|
if (text.length > 0) {
|
|
if (index < this.length() - 1 || this.children.tail == null) {
|
|
super.insertAt(Math.min(index, this.length() - 1), text);
|
|
} else {
|
|
this.children.tail.insertAt(this.children.tail.length(), text);
|
|
}
|
|
this.cache = {};
|
|
}
|
|
let block = this;
|
|
lines.reduce(function(index, line) {
|
|
block = block.split(index, true);
|
|
block.insertAt(0, line);
|
|
return line.length;
|
|
}, index + text.length);
|
|
}
|
|
|
|
insertBefore(blot, ref) {
|
|
let head = this.children.head;
|
|
super.insertBefore(blot, ref);
|
|
if (head instanceof Break) {
|
|
head.remove();
|
|
}
|
|
this.cache = {};
|
|
}
|
|
|
|
length() {
|
|
if (this.cache.length == null) {
|
|
this.cache.length = super.length() + NEWLINE_LENGTH;
|
|
}
|
|
return this.cache.length;
|
|
}
|
|
|
|
moveChildren(target, ref) {
|
|
super.moveChildren(target, ref);
|
|
this.cache = {};
|
|
}
|
|
|
|
optimize(context) {
|
|
super.optimize(context);
|
|
this.cache = {};
|
|
}
|
|
|
|
path(index) {
|
|
return super.path(index, true);
|
|
}
|
|
|
|
removeChild(child) {
|
|
super.removeChild(child);
|
|
this.cache = {};
|
|
}
|
|
|
|
split(index, force = false) {
|
|
if (force && (index === 0 || index >= this.length() - NEWLINE_LENGTH)) {
|
|
let clone = this.clone();
|
|
if (index === 0) {
|
|
this.parent.insertBefore(clone, this);
|
|
return this;
|
|
} else {
|
|
this.parent.insertBefore(clone, this.next);
|
|
return clone;
|
|
}
|
|
} else {
|
|
let next = super.split(index, force);
|
|
this.cache = {};
|
|
return next;
|
|
}
|
|
}
|
|
}
|
|
Block.blotName = 'block';
|
|
Block.tagName = 'P';
|
|
Block.defaultChild = 'break';
|
|
Block.allowedChildren = [Inline, Parchment.Embed, TextBlot];
|
|
|
|
|
|
function bubbleFormats(blot, formats = {}) {
|
|
if (blot == null) return formats;
|
|
if (typeof blot.formats === 'function') {
|
|
formats = extend(formats, blot.formats());
|
|
}
|
|
if (blot.parent == null || blot.parent.blotName == 'scroll' || blot.parent.statics.scope !== blot.statics.scope) {
|
|
return formats;
|
|
}
|
|
return bubbleFormats(blot.parent, formats);
|
|
}
|
|
|
|
|
|
export { bubbleFormats, BlockEmbed, Block as default };
|