feat(demo): add story 1 — Sorano: Rock and Time

This commit is contained in:
2026-06-20 21:19:57 +02:00
parent 42ed59a6b3
commit 8f87155c1d
5508 changed files with 1595740 additions and 124 deletions
@@ -0,0 +1,30 @@
export default function collapse(input) {
let output = input;
output = output.replace(/<figure class="image">((((?!(<\/figure>)).)|\n)*)<\/figure>/gm, '$1');
const domOutput = new DOMParser().parseFromString(output, 'text/html');
[...domOutput.querySelectorAll('shortcode-block, shortcode-inline')].forEach((domShortcode) => {
domShortcode.setAttribute('sc-rendered', false);
});
let domShortcode = domOutput.querySelector('shortcode-block[sc-rendered], shortcode-inline[sc-rendered]');
while (domShortcode) {
const name = domShortcode.getAttribute('name');
const shortcode = window.nextgenEditor.shortcodes[name];
domShortcode.removeAttribute('class');
domShortcode.removeAttribute('sc-rendered');
const domInnerContent = domShortcode.querySelector(`shortcode-${shortcode.type}-editable, shortcode-${shortcode.type}-readonly`);
domShortcode.innerHTML = (domInnerContent && domInnerContent.innerHTML) || '';
domShortcode = domOutput.querySelector('shortcode-block[sc-rendered], shortcode-inline[sc-rendered]');
}
output = domOutput.body.innerHTML;
return output;
}
@@ -0,0 +1,153 @@
import collapse from './collapse';
import uncollapse from './uncollapse';
const Command = window.nextgenEditor.classes.core.command.class;
window.nextgenEditor.addPlugin('GravShortcodeCoreCommand', {
init() {
Object.values(window.nextgenEditor.shortcodes).forEach((shortcode) => {
const commandName = `shortcode_${shortcode.name}`;
class GravShortcodeCoreCommand extends Command {
execute(args) {
this.editor.model.change((modelWriter) => {
let dataShortcode = '';
const argsForUncollapse = {};
const wrapOnInsert = !shortcode.child && !shortcode.parent
? shortcode.wrapOnInsert !== undefined
? shortcode.wrapOnInsert
: true
: false;
const selectedBlocks = [...this.editor.model.document.selection.getSelectedBlocks()];
const selectedItems = [...this.editor.model.document.selection.getFirstRange().getItems({ shallow: true })];
const firstSelectedBlock = selectedBlocks[0];
const firstBlockSelectedItems = selectedItems.filter((item) => item.parent === firstSelectedBlock);
const attributes = Object.keys(shortcode.attributes).reduce((acc, attrName) => {
acc[attrName] = shortcode.attributes[attrName].default.value;
return acc;
}, {});
dataShortcode += `<shortcode-${shortcode.type} name="${shortcode.name}" attributes="${encodeURIComponent(JSON.stringify(attributes))}">`;
if (wrapOnInsert) {
if (shortcode.type === 'block') {
const modelSelectedBlocks = modelWriter.createDocumentFragment();
selectedBlocks.forEach((block) => modelWriter.append(modelWriter.cloneElement(block), modelSelectedBlocks));
const viewSelectedBlocks = this.editor.data.toView(modelSelectedBlocks);
const dataSelectedBlocks = this.editor.data.processor.toData(viewSelectedBlocks);
dataShortcode += collapse(dataSelectedBlocks);
}
if (shortcode.type === 'inline') {
const modelSelectedBlocks = modelWriter.createDocumentFragment();
firstBlockSelectedItems.forEach((item) => {
const block = item.textNode
? modelWriter.createText(item.data)
: modelWriter.cloneElement(item);
modelWriter.append(block, modelSelectedBlocks);
});
const viewSelectedBlocks = this.editor.data.toView(modelSelectedBlocks);
const dataSelectedBlocks = this.editor.data.processor.toData(viewSelectedBlocks);
dataShortcode += collapse(dataSelectedBlocks);
}
}
if (shortcode.parent) {
dataShortcode += '<p>&nbsp;</p>';
}
dataShortcode += `</shortcode-${shortcode.type}>`;
if (shortcode.parent) {
if (args && args.modelParentShortcode) {
argsForUncollapse.parentAttributes = JSON.parse(decodeURIComponent(args.modelParentShortcode.getAttribute('attributes')));
}
}
dataShortcode = uncollapse(dataShortcode, argsForUncollapse);
const convertContext = shortcode.type === 'inline'
? '$block'
: '$root';
const viewShortcode = this.editor.data.processor.toView(dataShortcode).getChild(0);
const modelShortcode = this.editor.data.toModel(viewShortcode, convertContext).getChild(0);
let insertPosition = modelWriter.createPositionAt(this.editor.model.document.getRoot(), 0);
if (!args || !args.insertPosition) {
if (shortcode.type === 'block') {
const firstBlock = selectedBlocks[0];
const lastBlock = selectedBlocks[selectedBlocks.length - 1];
if (wrapOnInsert) {
insertPosition = modelWriter.createPositionBefore(firstBlock);
modelWriter.remove(
modelWriter.createRange(
modelWriter.createPositionBefore(firstBlock),
modelWriter.createPositionAfter(lastBlock),
),
);
} else {
insertPosition = modelWriter.createPositionAfter(lastBlock);
if (lastBlock && lastBlock.name === 'paragraph' && lastBlock.childCount === 0) {
insertPosition = modelWriter.createPositionBefore(lastBlock);
modelWriter.remove(lastBlock);
}
}
}
if (shortcode.type === 'inline') {
const firstItem = firstBlockSelectedItems.length
? firstBlockSelectedItems[0]
: null;
const lastItem = firstBlockSelectedItems.length
? firstBlockSelectedItems[firstBlockSelectedItems.length - 1]
: null;
if (wrapOnInsert) {
insertPosition = firstItem
? modelWriter.createPositionBefore(firstItem)
: this.editor.model.document.selection.getFirstPosition();
if (firstItem) {
modelWriter.remove(
modelWriter.createRange(
modelWriter.createPositionBefore(firstItem),
modelWriter.createPositionAfter(lastItem),
),
);
}
} else {
insertPosition = lastItem
? modelWriter.createPositionAfter(lastItem)
: this.editor.model.document.selection.getFirstPosition();
}
}
} else {
insertPosition = args.insertPosition;
}
modelWriter.insert(modelShortcode, insertPosition);
modelWriter.setSelection(modelShortcode, 'on');
});
}
}
this.editor.commands.add(commandName, new GravShortcodeCoreCommand(this.editor));
});
},
});
@@ -0,0 +1,150 @@
const Widget = window.nextgenEditor.classes.widget.class;
const { toWidget, toWidgetEditable } = window.nextgenEditor.classes.widget.utils;
window.nextgenEditor.addPlugin('GravShortcodeCoreConvertersBlock', {
requires: [Widget],
init() {
this.editor.model.schema.register('shortcode-block', {
isBlock: true,
isObject: true,
allowWhere: '$block',
allowContentOf: '$root',
allowAttributes: [
'name',
'attributes',
'class',
],
});
this.editor.conversion.for('upcast').elementToElement({
view: 'shortcode-block',
model(viewElement, { writer }) {
return writer.createElement('shortcode-block', viewElement.getAttributes());
},
});
this.editor.conversion.for('dataDowncast').elementToElement({
model: 'shortcode-block',
view(modelElement, { writer }) {
return writer.createContainerElement('shortcode-block', modelElement.getAttributes());
},
});
this.editor.conversion.for('editingDowncast').elementToElement({
model: 'shortcode-block',
view(modelElement, { writer }) {
const container = writer.createContainerElement('shortcode-block', modelElement.getAttributes());
return toWidget(container, writer);
},
});
this.editor.model.schema.register('shortcode-block-editable', {
isLimit: true,
allowWhere: '$block',
allowContentOf: '$root',
});
this.editor.conversion.for('upcast').elementToElement({
view: 'shortcode-block-editable',
model: 'shortcode-block-editable',
});
this.editor.conversion.for('dataDowncast').elementToElement({
model: 'shortcode-block-editable',
view: 'shortcode-block-editable',
});
this.editor.conversion.for('editingDowncast').elementToElement({
model: 'shortcode-block-editable',
view(modelElement, { writer }) {
const container = writer.createEditableElement('shortcode-block-editable', modelElement.getAttributes());
return toWidgetEditable(container, writer);
},
});
this.editor.model.schema.register('shortcode-block-readonly', {
isLimit: true,
allowWhere: '$block',
allowContentOf: '$root',
});
this.editor.conversion.elementToElement({
view: 'shortcode-block-readonly',
model: 'shortcode-block-readonly',
});
},
});
window.nextgenEditor.addPlugin('GravShortcodeCoreConvertersInline', {
requires: [Widget],
init() {
this.editor.model.schema.register('shortcode-inline', {
isObject: true,
isInline: true,
allowWhere: '$text',
allowContentOf: '$block',
allowAttributes: [
'name',
'attributes',
'class',
],
});
this.editor.conversion.for('upcast').elementToElement({
view: 'shortcode-inline',
model(viewElement, { writer }) {
return writer.createElement('shortcode-inline', viewElement.getAttributes());
},
});
this.editor.conversion.for('dataDowncast').elementToElement({
model: 'shortcode-inline',
view(modelElement, { writer }) {
return writer.createContainerElement('shortcode-inline', modelElement.getAttributes());
},
});
this.editor.conversion.for('editingDowncast').elementToElement({
model: 'shortcode-inline',
view(modelElement, { writer }) {
const container = writer.createContainerElement('shortcode-inline', modelElement.getAttributes());
return toWidget(container, writer);
},
});
this.editor.model.schema.register('shortcode-inline-editable', {
isLimit: true,
allowWhere: '$text',
allowContentOf: '$block',
});
this.editor.conversion.for('upcast').elementToElement({
view: 'shortcode-inline-editable',
model: 'shortcode-inline-editable',
});
this.editor.conversion.for('dataDowncast').elementToElement({
model: 'shortcode-inline-editable',
view: 'shortcode-inline-editable',
});
this.editor.conversion.for('editingDowncast').elementToElement({
model: 'shortcode-inline-editable',
view(modelElement, { writer }) {
const container = writer.createEditableElement('shortcode-inline-editable', modelElement.getAttributes());
return toWidgetEditable(container, writer);
},
});
this.editor.model.schema.register('shortcode-inline-readonly', {
isLimit: true,
allowWhere: '$text',
allowContentOf: '$block',
});
this.editor.conversion.elementToElement({
view: 'shortcode-inline-readonly',
model: 'shortcode-inline-readonly',
});
},
});
@@ -0,0 +1,86 @@
import displaySettings from './settings';
window.scDisplaySettings = function scDisplaySettings() {
const domShortcode = this.closest('shortcode-block, shortcode-inline');
if (domShortcode) {
displaySettings(domShortcode);
}
};
window.scBlockAddChildFromParent = function scBlockAddChildFromParent() {
const { editors } = window.nextgenEditor;
const domShortcode = this.parentNode;
const editor = (editors.filter((instance) => instance.ui.view.element.contains(domShortcode)) || []).shift();
const name = domShortcode.getAttribute('name');
const shortcode = window.nextgenEditor.shortcodes[name];
if (editor) {
const viewShortcode = editor.editing.view.domConverter.mapDomToView(domShortcode);
const modelShortcode = editor.editing.mapper.toModelElement(viewShortcode);
const domShortcodeBlockReadOnly = domShortcode.querySelector('shortcode-block-readonly');
const viewShortcodeBlockReadOnly = editor.editing.view.domConverter.mapDomToView(domShortcodeBlockReadOnly);
const modelShortcodeBlockReadOnly = editor.editing.mapper.toModelElement(viewShortcodeBlockReadOnly);
editor.model.change((modelWriter) => {
const insertPosition = modelWriter.createPositionAt(modelShortcodeBlockReadOnly, 0);
editor.execute(`shortcode_${shortcode.child.name}`, { insertPosition, modelParentShortcode: modelShortcode });
domShortcode.querySelector('.sc-add-child').classList.remove('sc-visible');
});
}
};
window.scBlockAddChild = function scBlockAddChild(event, where) {
const { editors } = window.nextgenEditor;
const domShortcode = this.parentNode;
const editor = (editors.filter((instance) => instance.ui.view.element.contains(domShortcode)) || []).shift();
const name = domShortcode.getAttribute('name');
const shortcode = window.nextgenEditor.shortcodes[name];
if (editor) {
const viewShortcode = editor.editing.view.domConverter.mapDomToView(domShortcode);
const modelShortcode = editor.editing.mapper.toModelElement(viewShortcode);
editor.model.change((modelWriter) => {
let modelParentShortcode = modelShortcode.parent;
const insertPosition = modelWriter.createPositionAt(modelShortcode, where);
while (modelParentShortcode && modelParentShortcode.name !== 'shortcode-block') {
modelParentShortcode = modelParentShortcode.parent;
}
if (modelParentShortcode) {
editor.execute(`shortcode_${shortcode.name}`, { insertPosition, modelParentShortcode });
}
});
}
};
window.scBlockMoveChild = function scBlockMove(event, where) {
const { editors } = window.nextgenEditor;
const domShortcode = this.parentNode;
const editor = (editors.filter((instance) => instance.ui.view.element.contains(domShortcode)) || []).shift();
if (editor) {
const viewShortcode = editor.editing.view.domConverter.mapDomToView(domShortcode);
const modelShortcode = editor.editing.mapper.toModelElement(viewShortcode);
const domSiblingShortcode = where === 'up'
? domShortcode.previousSibling
: domShortcode.nextSibling;
const viewSiblingShortcode = editor.editing.view.domConverter.mapDomToView(domSiblingShortcode);
const modelSiblingShortcode = editor.editing.mapper.toModelElement(viewSiblingShortcode);
editor.model.change((modelWriter) => {
modelWriter.move(modelWriter.createRangeOn(modelShortcode), modelSiblingShortcode, where === 'up' ? 'before' : 'after');
});
}
};
@@ -0,0 +1,45 @@
window.nextgenEditor.addHook('hookInit', () => {
Object.values(window.nextgenEditor.shortcodes).forEach((shortcode) => {
shortcode.attributes = shortcode.attributes || {};
if (!shortcode.button) {
shortcode.button = { label: shortcode.title };
}
Object.values(shortcode.attributes).forEach((attribute) => {
if (attribute.default === undefined) {
attribute.default = '';
}
if (typeof attribute.default !== 'object') {
attribute.default = { value: attribute.default };
}
if (attribute.shorthand === undefined) {
attribute.shorthand = true;
}
});
if (shortcode.type === 'block' && !shortcode.titlebar) {
shortcode.titlebar = () => '';
}
if (!shortcode.content) {
shortcode.content = () => '';
}
if (shortcode.preserve) {
if (shortcode.preserve.block) {
window.nextgenEditor.addVariable('preserveBlockTags', shortcode.preserve.block);
}
if (shortcode.preserve.inline) {
window.nextgenEditor.addVariable('preserveInlineTags', shortcode.preserve.inline);
}
}
if (!shortcode.parent) {
window.nextgenEditor.addButton(`shortcode_${shortcode.name}`, {
command: `shortcode_${shortcode.name}`,
...shortcode.button,
});
}
});
});
@@ -0,0 +1,278 @@
shortcode-block {
background: #fff;
border: 1px solid #ccc;
display: block;
margin: 16px 0;
}
#admin-main .ck.ck-editor__editable_inline > :first-child {
margin-top: 16px;
}
#admin-main .ck.ck-editor__editable_inline > :last-child {
margin-bottom: 16px;
}
#admin-main .ck-editor shortcode-block.ck-shortcode-child:hover {
outline-color: #1f89e5;
}
#admin-main .ck-editor shortcode-block > .sc-header > .sc-title > p,
#admin-main .ck-editor shortcode-block > .sc-header > .sc-titlebar > p,
#admin-main .ck-editor shortcode-block > .sc-header > .sc-settings > p,
#admin-main .ck-editor shortcode-block > .sc-add > p,
#admin-main .ck-editor shortcode-block > .sc-move > p {
margin: 0;
}
shortcode-block > .sc-header {
align-items: center;
border-bottom: 1px solid #ccc;
display: flex;
font-size: 14px;
line-height: 1.5;
padding: 8px 8px;
}
shortcode-block > .sc-header > .sc-title > p > .sc-value {
font-weight: 700;
}
shortcode-block > .sc-header > .sc-titlebar {
margin-left: 24px;
}
shortcode-block > .sc-header > .sc-settings {
color: #ffc83d;
cursor: pointer;
font-size: 0;
line-height: 0;
margin-left: auto;
opacity: 0;
transition: opacity .2s ease, color .2s ease;
}
shortcode-block > .sc-header > .sc-settings:hover,
shortcode-block.ck-shortcode-child > .sc-header > .sc-settings,
shortcode-block.ck-widget_selected > .sc-header > .sc-settings {
color: #1f89e5;
}
shortcode-block.ck-widget_selected > .sc-header > .sc-settings:hover,
shortcode-block.ck-shortcode-child > .sc-header > .sc-settings:hover {
opacity: .5
}
shortcode-block:hover > .sc-header > .sc-settings,
shortcode-block.ck-widget_selected > .sc-header > .sc-settings {
opacity: 1;
}
shortcode-block > .sc-header > .sc-settings > p > svg {
height: 24px;
width: 24px;
}
shortcode-block-editable,
shortcode-block-readonly {
display: block;
padding: 0 8px;
}
shortcode-block-readonly > [data-cke-filler] {
display: none;
}
#admin-main .ck-editor shortcode-block-editable > :first-child {
margin-top: 14px;
}
#admin-main .ck-editor shortcode-block.ck-shortcode-child .ck-widget__type-around__button_after,
#admin-main .ck-editor shortcode-block.ck-shortcode-child .ck-widget__type-around__button_before {
display: none;
}
shortcode-block > .sc-add-child {
align-items: center;
display: none;
justify-content: center;
margin: 16px 0;
opacity: 0;
transition: opacity .2s ease;
}
shortcode-block > .sc-add-child.sc-visible {
display: flex;
}
shortcode-block:hover > .sc-add-child,
shortcode-block.ck-widget_selected > .sc-add-child {
opacity: 1;
z-index: 1;
}
shortcode-block > .sc-add-child > p {
align-items: center;
background: #ffc83d;
border-radius: 50%;
cursor: pointer;
display: flex;
height: 24px;
justify-content: center;
margin: 0!important;
transition: opacity .2s ease, background .2s ease;
width: 24px;
}
shortcode-block > .sc-add-child > p:hover,
shortcode-block.ck-widget_selected > .sc-add-child > p {
background: #1f89e5;
}
shortcode-block.ck-widget_selected > .sc-add-child > p:hover {
opacity: .5;
}
shortcode-block > .sc-add-child > p > svg {
color: #fff;
height: 20px;
transition: opacity .2s ease;
width: 20px;
}
shortcode-block > .sc-add {
left: 30px;
opacity: 0;
position: absolute;
transition: opacity .2s ease;
top: -12px;
}
shortcode-block > .sc-add-after {
bottom: -11px;
left: auto;
right: 30px;
top: auto;
}
shortcode-block:hover > .sc-add {
opacity: 1;
z-index: 1;
}
shortcode-block > .sc-add > p {
align-items: center;
background: #1f89e5;
border-radius: 50%;
cursor: pointer;
display: flex;
height: 20px;
justify-content: center;
width: 20px;
}
shortcode-block > .sc-add > p > svg {
color: #fff;
height: 16px;
transition: opacity .2s ease;
width: 16px;
}
shortcode-block > .sc-add:hover > p > svg {
opacity: .5;
}
shortcode-block > .sc-move {
background: #1f89e5;
border-radius: 50%;
cursor: pointer;
height: 20px;
opacity: 0;
position: absolute;
right: -12px;
transition: opacity .2s ease;
width: 20px;
top: 46px;
}
shortcode-block > .sc-move-up {
transform: rotate(180deg);
}
shortcode-block:first-child > .sc-move-up,
shortcode-block:last-child > .sc-move-down {
display: none;
}
shortcode-block > .sc-move-down {
bottom: 4px;
left: auto;
top: auto;
}
shortcode-block:hover > .sc-move {
opacity: 1;
z-index: 1;
}
shortcode-block > .sc-move > p > svg {
color: #fff;
height: 20px;
left: 1.5px;
position: absolute;
top: 2px;
transition: opacity .2s ease;
width: 20px;
}
shortcode-block > .sc-move:hover > p > svg {
opacity: .5;
}
shortcode-inline {
background: #fff;
border: 1px solid #ccc;
display: inline-flex;
margin-left: 2px;
margin-right: 1px;
vertical-align: middle;
}
shortcode-inline-editable,
shortcode-inline-readonly {
display: inline;
padding: 1px 4px 2px;
}
shortcode-inline > .sc-content {
display: inline-flex;
align-items: center;
}
shortcode-inline > .sc-settings {
align-items: center;
border-left: 1px solid #ccc;
cursor: pointer;
display: inline-flex;
font-size: 0;
line-height: 0;
padding: 0 2px;
transition: opacity .2s ease, color .2s ease;
}
shortcode-inline:hover > .sc-settings {
color: #ffc83d;
}
shortcode-inline > .sc-settings:hover,
shortcode-inline.ck-widget_selected > .sc-settings {
color: #1f89e5;
}
shortcode-inline.ck-widget_selected > .sc-settings:hover {
opacity: .5;
}
shortcode-inline > .sc-settings > svg {
height: 16px;
width: 16px;
}
@@ -0,0 +1,10 @@
import './command';
import './converters';
import './events';
import './init';
import './prerender';
import './postsave';
import './remove';
import './render';
import './save';
import './main.css';
@@ -0,0 +1,95 @@
window.nextgenEditor.addHook('hookHTMLtoMarkdown', {
weight: 50,
handler(options, editor, input) {
let output = input;
const realNames = Object.values(window.nextgenEditor.shortcodes).map((shortcode) => shortcode.realName)
.filter((value, index, self) => self.indexOf(value) === index);
const openingRegexp = realNames
.map((name) => `(\\[${name}[^\\]]*\\])`).join('|');
const hashMap = {};
let shortcodeCounter = 1;
while (shortcodeCounter > 0) {
shortcodeCounter = 0;
// eslint-disable-next-line no-loop-func
Object.values(window.nextgenEditor.shortcodes).forEach((shortcode) => {
const regexp = `(?<opening>\\[${shortcode.realName}[^\\]]*\\])(?<content>(((?!(${openingRegexp}|(\\[\\/${shortcode.realName}\\]))).)|\\n)*)(?<closing>\\[\\/${shortcode.realName}\\])`;
output = output.replace(new RegExp(regexp, 'g'), (...matches) => {
shortcodeCounter += 1;
const hash = Math.random().toString(36).slice(2);
hashMap[hash] = { shortcode, matches };
if (shortcode.child) {
const childName = shortcode.child.realName;
Object.keys(hashMap).forEach((childHash) => {
const childShortcode = hashMap[childHash].shortcode;
if (childShortcode === shortcode.child && childShortcode.name !== `${shortcode.realName}_${childName}` && matches[0].includes(childHash)) {
hashMap[childHash].shortcode = window.nextgenEditor.shortcodes[`${shortcode.realName}_${childName}`];
}
});
}
return hash;
});
});
}
shortcodeCounter = 1;
while (shortcodeCounter > 0) {
shortcodeCounter = 0;
// eslint-disable-next-line no-loop-func
Object.keys(hashMap).forEach((hash) => {
if (!output.includes(hash)) {
return;
}
shortcodeCounter += 1;
const { shortcode, matches } = hashMap[hash];
const groups = matches.pop();
if (shortcode.type === 'block') {
let content = groups.content.replace(/^\n/, '').replace(/\n$/, '');
if (shortcode.child) {
content = content.trim().split('\n').filter((line) => !!line).join('\n');
content = `\n${content}\n`;
}
if (shortcode.parent) {
content = `\n${content}\n`;
}
output = output.replace(hash, `${groups.opening}${content}${groups.closing}`);
}
if (shortcode.type === 'inline') {
output = output.replace(hash, matches[0]);
}
});
}
/*
Object.values(window.nextgenEditor.shortcodes).forEach((shortcode) => {
const regexp = `(?<opening>\\[${shortcode.realName}[^\\]]*\\])\n(?<content>(((?!(${openingRegexp}|(\\[\\/${shortcode.realName}\\]))).))*)\n(?<closing>\\[\\/${shortcode.realName}\\])`;
output = output.replace(new RegExp(regexp, 'g'), (...matches) => {
const groups = matches.pop();
return `${groups.opening}${groups.content}${groups.closing}`;
});
});
*/
return output;
},
});
@@ -0,0 +1,100 @@
window.nextgenEditor.addHook('hookMarkdowntoHTML', {
weight: -50,
handler(options, input) {
let output = input;
const realNames = Object.values(window.nextgenEditor.shortcodes).map((shortcode) => shortcode.realName)
.filter((value, index, self) => self.indexOf(value) === index);
const openingRegexp = realNames
.map((name) => `(\\[${name}[^\\]]*\\])`).join('|');
realNames.forEach((name) => {
const regexp = `\\[${name}(?<attributes>(=| +).+?(?=/]))?\\/\\]`;
output = output.replace(new RegExp(regexp, 'g'), (...matches) => {
const groups = matches.pop();
const attributes = groups.attributes.trim()
? `${groups.attributes}`
: '';
return `[${name}${attributes}][/${name}]`;
});
});
const hashMap = {};
let shortcodeCounter = 1;
while (shortcodeCounter > 0) {
shortcodeCounter = 0;
// eslint-disable-next-line no-loop-func
Object.values(window.nextgenEditor.shortcodes).forEach((shortcode) => {
const regexp = `(?<spaces_before> *)\\[${shortcode.realName}(?<attributes>(=| +)[^\\]]*)?\\](?<content>(((?!(${openingRegexp}|(\\[\\/${shortcode.realName}\\]))).)|\\n)*)\\[\\/${shortcode.realName}\\](?<spaces_after> *)`;
output = output.replace(new RegExp(regexp, 'g'), (...matches) => {
shortcodeCounter += 1;
const hash = Math.random().toString(36).slice(2);
hashMap[hash] = { shortcode, matches };
if (shortcode.child) {
const childName = shortcode.child.realName;
Object.keys(hashMap).forEach((childHash) => {
const childShortcode = hashMap[childHash].shortcode;
if (childShortcode === shortcode.child && childShortcode.name !== `${shortcode.realName}_${childName}` && matches[0].includes(childHash)) {
hashMap[childHash].shortcode = window.nextgenEditor.shortcodes[`${shortcode.realName}_${childName}`];
}
});
}
return hash;
});
});
}
shortcodeCounter = 1;
while (shortcodeCounter > 0) {
shortcodeCounter = 0;
// eslint-disable-next-line no-loop-func
Object.keys(hashMap).forEach((hash) => {
if (!output.includes(hash)) {
return;
}
shortcodeCounter += 1;
const { shortcode, matches } = hashMap[hash];
const groups = matches.pop();
const spacesBefore = groups.spaces_before.replace(/ /g, '&nbsp;');
const spacesAfter = groups.spaces_after.replace(/ /g, '&nbsp;');
if (shortcode.type === 'block') {
let content = groups.content.trim();
if (groups.spaces_before.length) {
content = content.replace(new RegExp(`^( ){${groups.spaces_before.length}}`, 'gm'), '');
}
const replacement = `\n\n[${shortcode.name}${groups.attributes || ''}]\n\n${content}\n\n[/${shortcode.name}]\n\n`;
output = output.replace(new RegExp(`(\\n)?(\\n)?${hash}(\\n)?(\\n)?`), replacement);
}
if (shortcode.type === 'inline') {
output = output.replace(hash, `${spacesBefore}[${shortcode.name}${groups.attributes || ''}]${groups.content}[/${shortcode.name}]${spacesAfter}`);
}
});
}
output = output.replace(/^\n\n/, '').replace(/\n\n$/, '');
return output;
},
});
@@ -0,0 +1,55 @@
window.nextgenEditor.addPlugin('GravShortcodeCoreRemove', {
init() {
const deleteBackwardCommand = this.editor.commands.get('delete');
const deleteForwardCommand = this.editor.commands.get('forwardDelete');
const preDelete = (event) => {
const selectedElement = this.editor.model.document.selection.getSelectedElement();
if (selectedElement && selectedElement.name === 'shortcode-block') {
const name = selectedElement.getAttribute('name');
const shortcode = window.nextgenEditor.shortcodes[name];
if (shortcode.parent) {
const viewShortcode = this.editor.editing.mapper.toViewElement(selectedElement);
const domShortcode = this.editor.editing.view.domConverter.mapViewToDom(viewShortcode);
const domParentShortcode = domShortcode.closest(`shortcode-block[name="${shortcode.parent.name}"]`);
event.childShortcodeDeleted = true;
event.modelShortcodeBlockReadOnly = selectedElement.parent;
event.domParentShortcode = domParentShortcode;
}
}
};
const postDelete = (event) => {
if (event.childShortcodeDeleted) {
const { domParentShortcode, modelShortcodeBlockReadOnly } = event;
const children = [...modelShortcodeBlockReadOnly.getChildren()];
const scChildren = children.filter((child) => child.name === 'shortcode-block');
const otherChildren = children.filter((child) => child.name !== 'shortcode-block');
setTimeout(() => {
this.editor.model.change((modelWriter) => {
otherChildren.forEach((modelChild) => {
if (modelChild.name === 'paragraph' && modelChild.childCount === 0) {
modelWriter.remove(modelChild);
}
});
});
});
if (!scChildren.length) {
domParentShortcode.querySelector('shortcode-block > .sc-add-child').classList.add('sc-visible');
}
}
};
deleteBackwardCommand.on('execute', preDelete, { priority: 'highest' });
deleteForwardCommand.on('execute', preDelete, { priority: 'highest' });
deleteBackwardCommand.on('execute', postDelete, { priority: 'lowest' });
deleteForwardCommand.on('execute', postDelete, { priority: 'lowest' });
},
});
@@ -0,0 +1,95 @@
import uncollapse from './uncollapse';
window.nextgenEditor.addHook('hookMarkdowntoHTML', {
weight: 50,
handler(options, input) {
let output = input;
let shortcodeCounter = 1;
const openingRegexp = Object.keys(window.nextgenEditor.shortcodes).map((name) => `(\\[${name}[^\\]]*\\])`).join('|');
while (shortcodeCounter > 0) {
shortcodeCounter = 0;
// eslint-disable-next-line no-loop-func
Object.values(window.nextgenEditor.shortcodes).forEach((shortcode) => {
const regexp = `(?<p1><p>)?\\[${shortcode.name}(?<attributes>(=| +)[^\\]]*)?\\](<\\/p>)?(?<content>(((?!(${openingRegexp}|(\\[\\/${shortcode.name}\\]))).)|\\n)*)\\[\\/${shortcode.name}\\](?<p2><\\/p>)?`;
output = output.replace(new RegExp(regexp, 'g'), (...matches) => {
shortcodeCounter += 1;
const groups = matches.pop();
let content = shortcode.type === 'block'
? groups.content.replace(/<p>$/, '')
: groups.content;
const bbcode = Object.keys(shortcode.attributes).reduce((acc, attrName) => acc || (shortcode.attributes[attrName].bbcode && shortcode.attributes[attrName].shorthand && attrName), '');
const innerHTMLAttribute = Object.keys(shortcode.attributes).reduce((acc, attrName) => acc || (shortcode.attributes[attrName].innerHTML && attrName), '');
let attrGroup = bbcode && groups.attributes && groups.attributes.startsWith('=')
? `${bbcode}${groups.attributes}`
: groups.attributes || '';
if (innerHTMLAttribute) {
const innerHTML = shortcode.type === 'block'
? content.replace(/^<p>/, '').replace(/<\/p>$/, '').replace(/^&nbsp;$/, '')
: content.replace(/^&nbsp;$/, '');
attrGroup = attrGroup
? `${attrGroup} ${innerHTMLAttribute}="${innerHTML}"`
: `${innerHTMLAttribute}="${innerHTML}"`;
content = '';
}
const domAttributes = new DOMParser().parseFromString(`<div ${attrGroup}></div>`, 'text/html').body.firstChild.attributes;
const attributes = Object.keys(shortcode.attributes).reduce((acc, attrName) => {
const attribute = shortcode.attributes[attrName];
let attrValue = domAttributes.getNamedItem(attrName)
? domAttributes.getNamedItem(attrName).value
: attribute.default.value;
if (attribute.type === Boolean && domAttributes.getNamedItem(attrName)) {
attrValue = domAttributes.getNamedItem(attrName) !== 'false';
}
if (attribute.type === Number) {
attrValue = +attrValue;
}
acc[attrName] = attrValue;
return acc;
}, {});
let replacement = '';
const attributesEncoded = encodeURIComponent(JSON.stringify(attributes));
if (shortcode.type === 'block') {
replacement += `<shortcode-block name="${shortcode.name}" attributes="${attributesEncoded}">`;
replacement += content;
replacement += '</shortcode-block>';
}
if (shortcode.type === 'inline') {
replacement += groups.p1 || '';
replacement += `<shortcode-inline name="${shortcode.name}" attributes="${attributesEncoded}">`;
replacement += content;
replacement += '</shortcode-inline>';
replacement += groups.p2 || '';
}
return replacement;
});
});
}
output = uncollapse(output);
return output;
},
});
@@ -0,0 +1,80 @@
import collapse from './collapse';
window.nextgenEditor.addHook('hookHTMLtoMarkdown', {
weight: -50,
handler(options, editor, input) {
let output = input;
output = collapse(output);
const domOutput = new DOMParser().parseFromString(output, 'text/html');
let domShortcode = domOutput.querySelector('shortcode-block, shortcode-inline');
while (domShortcode) {
const name = domShortcode.getAttribute('name');
const shortcode = window.nextgenEditor.shortcodes[name];
const attributes = JSON.parse(decodeURIComponent(domShortcode.getAttribute('attributes')));
const innerHTMLAttribute = Object.keys(shortcode.attributes).reduce((acc, attrName) => acc || (shortcode.attributes[attrName].innerHTML && attrName), '');
const attrLine = Object.keys(shortcode.attributes).reduce((acc, attrName) => {
const attribute = shortcode.attributes[attrName];
if (attribute.type === Boolean) {
return attributes[attrName]
? `${acc} ${attrName}`
: acc;
}
if (attributes[attrName] === attribute.default.value && !attribute.default.preserve) {
return acc;
}
if (attribute.bbcode && attribute.shorthand) {
return `="${attributes[attrName]}"${acc}`;
}
if (attribute.innerHTML) {
return acc;
}
return `${acc} ${attrName}="${attributes[attrName]}"`;
}, '');
if (shortcode.type === 'block') {
if (domShortcode.innerHTML === '<p>&nbsp;</p>') {
domShortcode.innerHTML = '';
}
if (innerHTMLAttribute) {
domShortcode.outerHTML = `<p>[${shortcode.realName}${attrLine}]${attributes[innerHTMLAttribute]}[/${shortcode.realName}]</p>`;
} else if (domShortcode.innerHTML) {
domShortcode.outerHTML = `<p>[${shortcode.realName}${attrLine}]</p>${domShortcode.innerHTML}<p>[/${shortcode.realName}]</p>`;
} else {
domShortcode.outerHTML = `<p>[${shortcode.realName}${attrLine} /]</p>`;
}
}
if (shortcode.type === 'inline') {
if (domShortcode.innerHTML === '&nbsp;') {
domShortcode.innerHTML = '';
}
if (innerHTMLAttribute) {
domShortcode.outerHTML = `[${shortcode.realName}${attrLine}]${attributes[innerHTMLAttribute]}[/${shortcode.realName}]`;
} else if (domShortcode.innerHTML) {
domShortcode.outerHTML = `[${shortcode.realName}${attrLine}]${domShortcode.innerHTML}[/${shortcode.realName}]`;
} else {
domShortcode.outerHTML = `[${shortcode.realName}${attrLine} /]`;
}
}
domShortcode = domOutput.querySelector('shortcode-block, shortcode-inline');
}
output = domOutput.body.innerHTML;
return output;
},
});
@@ -0,0 +1,153 @@
import collapse from './collapse';
import uncollapse from './uncollapse';
const { showSettingsPopup } = window.nextgenEditor.exports;
export default function displaySettings(domShortcode) {
const { editors } = window.nextgenEditor;
const editor = (editors.filter((instance) => instance.ui.view.element.contains(domShortcode)) || []).shift();
const name = domShortcode.getAttribute('name');
const shortcode = window.nextgenEditor.shortcodes[name];
const plugin = window.nextgenEditor.shortcodePlugins[shortcode.plugin];
if (editor) {
const viewShortcode = editor.editing.view.domConverter.mapDomToView(domShortcode);
let modelShortcode = editor.editing.mapper.toModelElement(viewShortcode);
const currentAttributes = JSON.parse(decodeURIComponent(domShortcode.getAttribute('attributes')));
const domDisplayPoint = shortcode.type === 'block'
? domShortcode.querySelector('.sc-header > .sc-settings')
: domShortcode;
const title = []
.concat([
(plugin && plugin.title) || '',
(shortcode.parent && shortcode.parent.title) || '',
shortcode.title || '',
])
.filter((item) => !!item)
.join(' / ');
const argsForPopup = {
title,
domDisplayPoint,
debounceDelay: 1000,
attributes: shortcode.attributes,
currentAttributes,
parentAttributes: null,
childAttributes: null,
};
if (shortcode.parent) {
const domParentShortcode = domShortcode.closest(`shortcode-block[name="${shortcode.parent.name}"]`);
argsForPopup.parentAttributes = domParentShortcode
? JSON.parse(decodeURIComponent(domParentShortcode.getAttribute('attributes')))
: {};
}
if (shortcode.child) {
argsForPopup.childAttributes = [];
const childNodes = [...domShortcode.querySelectorAll(`shortcode-block shortcode-block[name="${shortcode.child.name}"]`)];
const deepChildNodes = [...domShortcode.querySelectorAll(`shortcode-block shortcode-block shortcode-block[name="${shortcode.child.name}"]`)];
childNodes
.filter((domChildShortcode) => !deepChildNodes.includes(domChildShortcode))
.forEach((domChildShortcode) => {
const childAttributes = JSON.parse(decodeURIComponent(domChildShortcode.getAttribute('attributes')));
argsForPopup.childAttributes.push(childAttributes);
});
}
argsForPopup.deleteItem = () => editor.execute('delete');
argsForPopup.changeAttributes = () => {
editor.model.change((modelWriter) => {
modelWriter.setAttribute('attributes', encodeURIComponent(JSON.stringify(currentAttributes)), modelShortcode);
const convertContext = shortcode.type === 'inline'
? '$block'
: '$root';
if (shortcode.parent) {
const viewOldShortcode = editor.editing.mapper.toViewElement(modelShortcode);
const domOldShortcode = editor.editing.view.domConverter.mapViewToDom(viewOldShortcode);
if (!domOldShortcode) {
return;
}
const domOldParentShortcode = domOldShortcode.parentNode.closest('shortcode-block');
const viewOldParentShortcode = editor.editing.view.domConverter.mapDomToView(domOldParentShortcode);
const modelOldParentShortcode = editor.editing.mapper.toModelElement(viewOldParentShortcode);
const childNodes = [...domOldParentShortcode.querySelectorAll('shortcode-block shortcode-block')];
const deepChildNodes = [...domOldParentShortcode.querySelectorAll('shortcode-block shortcode-block shortcode-block')];
const childIndex = childNodes
.filter((domChildShortcode) => !deepChildNodes.includes(domChildShortcode))
.indexOf(domOldShortcode);
const insertPosition = modelWriter.createPositionBefore(modelOldParentShortcode);
const modelOldParentClonedShortcode = modelWriter.cloneElement(modelOldParentShortcode);
const modelOldParentFragment = modelWriter.createDocumentFragment();
modelWriter.append(modelOldParentClonedShortcode, modelOldParentFragment);
const viewOldParentClonedShortcode = editor.data.toView(modelOldParentFragment).getChild(0);
const dataOldParentClonedShortcode = editor.data.processor.toData(viewOldParentClonedShortcode);
const dataNewParentShortcode = uncollapse(collapse(dataOldParentClonedShortcode));
const viewNewParentShortcode = editor.data.processor.toView(dataNewParentShortcode).getChild(0);
const modelNewParentShortcode = editor.data.toModel(viewNewParentShortcode, convertContext).getChild(0);
modelWriter.remove(modelOldParentShortcode);
modelWriter.insert(modelNewParentShortcode, insertPosition);
setTimeout(() => {
const viewParentShortcode = editor.editing.mapper.toViewElement(modelNewParentShortcode);
const domParentShortcode = editor.editing.view.domConverter.mapViewToDom(viewParentShortcode);
const childNewNodes = [...domParentShortcode.querySelectorAll('shortcode-block shortcode-block')];
const deepNewChildNodes = [...domParentShortcode.querySelectorAll('shortcode-block shortcode-block shortcode-block')];
const domNewShortcode = childNewNodes.filter((domChildShortcode) => !deepNewChildNodes.includes(domChildShortcode))[childIndex];
const viewNewShortcode = editor.editing.view.domConverter.mapDomToView(domNewShortcode);
const modelNewShortcode = editor.editing.mapper.toModelElement(viewNewShortcode);
editor.model.change((modelWriter2) => {
modelWriter2.setSelection(modelNewShortcode, 'on');
modelShortcode = modelNewShortcode;
});
});
return;
}
const insertPosition = modelWriter.createPositionBefore(modelShortcode);
const modelOldShortcode = modelWriter.cloneElement(modelShortcode);
const modelOldFragment = modelWriter.createDocumentFragment();
modelWriter.append(modelOldShortcode, modelOldFragment);
const viewOldShortcode = editor.data.toView(modelOldFragment).getChild(0);
const dataOldShortcode = editor.data.processor.toData(viewOldShortcode);
const dataNewShortcode = uncollapse(collapse(dataOldShortcode));
const viewNewShortcode = editor.data.processor.toView(dataNewShortcode).getChild(0);
const modelNewShortcode = editor.data.toModel(viewNewShortcode, convertContext).getChild(0);
modelWriter.remove(modelShortcode);
modelWriter.insert(modelNewShortcode, insertPosition);
modelWriter.setSelection(modelNewShortcode, 'on');
modelShortcode = modelNewShortcode;
});
};
showSettingsPopup(argsForPopup);
}
}
@@ -0,0 +1,164 @@
export default function uncollapse(input, args) {
const domOutput = new DOMParser().parseFromString(input, 'text/html');
[...domOutput.querySelectorAll('shortcode-block, shortcode-inline')].forEach((domShortcode) => {
domShortcode.setAttribute('sc-rendered', false);
});
let domShortcode = domOutput.querySelector('shortcode-block[sc-rendered], shortcode-inline[sc-rendered]');
while (domShortcode) {
const name = domShortcode.getAttribute('name');
const shortcode = window.nextgenEditor.shortcodes[name];
const attributes = JSON.parse(decodeURIComponent(domShortcode.getAttribute('attributes')));
domShortcode.classList.add('ck-shortcode');
domShortcode.classList.add(`ck-shortcode-${shortcode.type}`);
domShortcode.removeAttribute('sc-rendered');
const argsForRender = {
shortcode,
attributes,
innerHTML: domShortcode.innerHTML,
parentAttributes: null,
childAttributes: null,
};
let innerHTML = '';
if (shortcode.type === 'block') {
if (shortcode.parent) {
domShortcode.classList.add('ck-shortcode-child');
const domParentShortcode = domShortcode.closest(`shortcode-block[name="${shortcode.parent.name}"]`);
argsForRender.parentAttributes = !args || !args.parentAttributes
? domParentShortcode
? JSON.parse(decodeURIComponent(domParentShortcode.getAttribute('attributes')))
: {}
: args.parentAttributes;
}
if (shortcode.child) {
argsForRender.childAttributes = [];
domShortcode.classList.add('ck-shortcode-parent');
const childNodes = [...domShortcode.querySelectorAll(`shortcode-block shortcode-block[name="${shortcode.child.name}"]`)];
const deepChildNodes = [...domShortcode.querySelectorAll(`shortcode-block shortcode-block shortcode-block[name="${shortcode.child.name}"]`)];
childNodes
.filter((domChildShortcode) => !deepChildNodes.includes(domChildShortcode))
.forEach((domChildShortcode) => {
const childAttributes = JSON.parse(decodeURIComponent(domChildShortcode.getAttribute('attributes')));
argsForRender.childAttributes.push(childAttributes);
});
}
/* eslint-disable indent, no-multi-spaces */
innerHTML += '<div class="sc-header">';
innerHTML += `<div class="sc-title">Shortcode - <span class="sc-value">${shortcode.title}</span></div>`;
innerHTML += `<div class="sc-titlebar">${shortcode.titlebar(argsForRender)}</div>`;
innerHTML += '<div class="sc-settings">';
innerHTML += '<svg viewBox="0 0 24 24" fill="currentColor" stroke="none">';
innerHTML += '<path d="M9 4.58V4c0-1.1.9-2 2-2h2a2 2 0 0 1 2 2v.58a8 8 0 0 1 1.92 1.11l.5-.29a2 2 0 0 1 2.74.73l1 1.74a2 2 0 0 1-.73 2.73l-.5.29a8.06 8.06 0 0 1 0 2.22l.5.3a2 2 0 0 1 .73 2.72l-1 1.74a2 2 0 0 1-2.73.73l-.5-.3A8 8 0 0 1 15 19.43V20a2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2v-.58a8 8 0 0 1-1.92-1.11l-.5.29a2 2 0 0 1-2.74-.73l-1-1.74a2 2 0 0 1 .73-2.73l.5-.29a8.06 8.06 0 0 1 0-2.22l-.5-.3a2 2 0 0 1-.73-2.72l1-1.74a2 2 0 0 1 2.73-.73l.5.3A8 8 0 0 1 9 4.57zM7.88 7.64l-.54.51-1.77-1.02-1 1.74 1.76 1.01-.17.73a6.02 6.02 0 0 0 0 2.78l.17.73-1.76 1.01 1 1.74 1.77-1.02.54.51a6 6 0 0 0 2.4 1.4l.72.2V20h2v-2.04l.71-.2a6 6 0 0 0 2.41-1.4l.54-.51 1.77 1.02 1-1.74-1.76-1.01.17-.73a6.02 6.02 0 0 0 0-2.78l-.17-.73 1.76-1.01-1-1.74-1.77 1.02-.54-.51a6 6 0 0 0-2.4-1.4l-.72-.2V4h-2v2.04l-.71.2a6 6 0 0 0-2.41 1.4zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"></path>';
innerHTML += '</svg>';
innerHTML += '</div>';
innerHTML += '</div>';
innerHTML += '<div class="sc-content">';
innerHTML += shortcode.content(argsForRender)
.replace('{{content_editable}}', `<shortcode-block-editable>${domShortcode.innerHTML}</shortcode-block-editable>`)
.replace('{{content_readonly}}', `<shortcode-block-readonly>${domShortcode.innerHTML}</shortcode-block-readonly>`);
innerHTML += '</div>';
if (shortcode.child) {
const visible = !domShortcode.innerHTML ? ' sc-visible' : '';
innerHTML += `<div class="sc-add-child${visible}" title="Insert new ${shortcode.child.title}">`;
innerHTML += '<svg viewBox="0 0 24 24" fill="currentColor" stroke="none">';
innerHTML += '<path d="M17 11a1 1 0 0 1 0 2h-4v4a1 1 0 0 1-2 0v-4H7a1 1 0 0 1 0-2h4V7a1 1 0 0 1 2 0v4h4z"></path>';
innerHTML += '</svg>';
innerHTML += '</div>';
}
if (shortcode.parent) {
['before', 'after'].forEach((where) => {
innerHTML += `<div class="sc-add sc-add-${where}" title="Insert new ${shortcode.title} ${where}">`;
innerHTML += '<svg viewBox="0 0 24 24" fill="currentColor" stroke="none">';
innerHTML += '<path d="M17 11a1 1 0 0 1 0 2h-4v4a1 1 0 0 1-2 0v-4H7a1 1 0 0 1 0-2h4V7a1 1 0 0 1 2 0v4h4z"></path>';
innerHTML += '</svg>';
innerHTML += '</div>';
});
['up', 'down'].forEach((where) => {
innerHTML += `<div class="sc-move sc-move-${where}" title="Move ${shortcode.title} ${where}">`;
innerHTML += '<svg viewBox="0 0 24 24" fill="currentColor" stroke="none">';
innerHTML += '<path fill-rule="evenodd" clip-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"></path>';
innerHTML += '</svg>';
innerHTML += '</div>';
});
}
/* eslint-enable indent, no-multi-spaces */
}
if (shortcode.type === 'inline') {
/* eslint-disable indent, no-multi-spaces */
innerHTML += '<span class="sc-content">';
innerHTML += shortcode.content(argsForRender)
.replace('{{content_editable}}', `<shortcode-inline-editable>${domShortcode.innerHTML}</shortcode-inline-editable>`)
.replace('{{content_readonly}}', `<shortcode-inline-readonly>${domShortcode.innerHTML}</shortcode-inline-readonly>`);
innerHTML += '</span>';
innerHTML += '<span class="sc-settings">';
innerHTML += '<svg viewBox="0 0 24 24" fill="currentColor" stroke="none">';
innerHTML += '<path d="M9 4.58V4c0-1.1.9-2 2-2h2a2 2 0 0 1 2 2v.58a8 8 0 0 1 1.92 1.11l.5-.29a2 2 0 0 1 2.74.73l1 1.74a2 2 0 0 1-.73 2.73l-.5.29a8.06 8.06 0 0 1 0 2.22l.5.3a2 2 0 0 1 .73 2.72l-1 1.74a2 2 0 0 1-2.73.73l-.5-.3A8 8 0 0 1 15 19.43V20a2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2v-.58a8 8 0 0 1-1.92-1.11l-.5.29a2 2 0 0 1-2.74-.73l-1-1.74a2 2 0 0 1 .73-2.73l.5-.29a8.06 8.06 0 0 1 0-2.22l-.5-.3a2 2 0 0 1-.73-2.72l1-1.74a2 2 0 0 1 2.73-.73l.5.3A8 8 0 0 1 9 4.57zM7.88 7.64l-.54.51-1.77-1.02-1 1.74 1.76 1.01-.17.73a6.02 6.02 0 0 0 0 2.78l.17.73-1.76 1.01 1 1.74 1.77-1.02.54.51a6 6 0 0 0 2.4 1.4l.72.2V20h2v-2.04l.71-.2a6 6 0 0 0 2.41-1.4l.54-.51 1.77 1.02 1-1.74-1.76-1.01.17-.73a6.02 6.02 0 0 0 0-2.78l-.17-.73 1.76-1.01-1-1.74-1.77 1.02-.54-.51a6 6 0 0 0-2.4-1.4l-.72-.2V4h-2v2.04l-.71.2a6 6 0 0 0-2.41 1.4zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"></path>';
innerHTML += '</svg>';
innerHTML += '</span>';
/* eslint-enable indent, no-multi-spaces */
}
domShortcode.innerHTML = innerHTML;
domShortcode = domOutput.querySelector('shortcode-block[sc-rendered], shortcode-inline[sc-rendered]');
}
return domOutput.body.innerHTML;
}
document.addEventListener('click', (event) => {
const { target } = event;
const list = ['sc-settings', 'sc-move', 'sc-add', 'sc-add-child'];
const action = { element: null, className: null };
const isAction = list.some((item) => {
let match = target.classList.contains(item);
if (match) {
action.element = target;
action.className = item;
return true;
}
match = target.closest(`.${item}`);
if (match) {
action.element = match;
action.className = item;
return true;
}
return false;
});
if (isAction) {
switch (action.className) {
case 'sc-move':
window.scBlockMoveChild.call(action.element, event, action.element.classList.contains('sc-move-up') ? 'up' : 'down');
break;
case 'sc-add':
window.scBlockAddChild.call(action.element, event, action.element.classList.contains('sc-add-before') ? 'before' : 'after');
break;
case 'sc-add-child':
window.scBlockAddChildFromParent.call(action.element, event);
break;
case 'sc-settings':
default:
window.scDisplaySettings.call(action.element, event);
}
}
});