From 25b6dcf28b01c635b0149aa36993ed2e7e233374 Mon Sep 17 00:00:00 2001 From: Joshua Nicholson <94021017+jnicholCU@users.noreply.github.com> Date: Wed, 9 Apr 2025 18:00:41 -0600 Subject: [PATCH] Add bootstrap accordion plugin and update other plugins A full integration of the bootstrap accordion plugin Updates to other plugin's builds. --- .../bootstrapAccordion/README.md | 62 +++ .../bootstrapAccordion/src/augmentation.ts | 31 ++ .../src/bootstrapaccordion.ts | 32 ++ .../src/bootstrapaccordionconfig.ts | 134 +++++ .../src/bootstrapaccordionediting.ts | 457 ++++++++++++++++++ .../src/bootstrapaccordionevents.ts | 64 +++ .../src/bootstrapaccordionkeyboard.ts | 153 ++++++ .../src/bootstrapaccordionshims.ts | 44 ++ .../src/bootstrapaccordiontypes.ts | 50 ++ .../src/bootstrapaccordionui.ts | 268 ++++++++++ .../src/bootstrapaccordionutils.ts | 144 ++++++ .../bootstrapaccordioncollapseallcommand.ts | 39 ++ .../bootstrapaccordionfirstitemopencommand.ts | 41 ++ .../bootstrapaccordionopenallcommand.ts | 35 ++ .../insertbootstrapaccordioncommand.ts | 69 +++ .../insertbootstrapaccordionitemcommand.ts | 53 ++ .../modifybootstrapaccordioncommand.ts | 80 +++ .../removebootstrapaccordionitemcommand.ts | 47 ++ .../bootstrapAccordion/src/index.ts | 19 + .../bootstrapaccordionclipboardpipeline.ts | 42 ++ .../bootstrapaccordiongeneralhtmlsupport.ts | 75 +++ css/bootstrap-accordion.admin.css | 3 + css/bootstrap-accordion.css | 137 ++++++ css/bootstrap-accordion.editor.css | 62 +++ icons/bootstrap-accordion-item.svg | 1 + icons/bootstrap-accordion-open-collapse.svg | 1 + icons/bootstrap-accordion.svg | 1 + js/build/bootstrapAccordion.js | 1 + js/build/box.js | 2 +- js/build/button.js | 2 +- js/build/buttongroup.js | 2 +- js/build/calendar.js | 2 +- js/build/callout.js | 2 +- js/build/column.js | 2 +- js/build/countdown.js | 2 +- js/build/cuiconextras.js | 2 +- js/build/invisible.js | 2 +- js/build/jumpmenu.js | 2 +- js/build/map.js | 2 +- js/build/tooltip.js | 2 +- package.json | 2 + src/Plugin/Filter/BootstrapAccordion.php | 135 ++++++ ucb_ckeditor_plugins.ckeditor5.yml | 28 ++ ucb_ckeditor_plugins.libraries.yml | 16 + ucb_ckeditor_plugins.module | 7 + 45 files changed, 2345 insertions(+), 12 deletions(-) create mode 100644 ckeditor5_plugins/bootstrapAccordion/README.md create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/augmentation.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordion.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionconfig.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionediting.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionevents.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionkeyboard.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionshims.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordiontypes.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionui.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionutils.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/commands/bootstrapaccordioncollapseallcommand.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/commands/bootstrapaccordionfirstitemopencommand.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/commands/bootstrapaccordionopenallcommand.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/commands/insertbootstrapaccordioncommand.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/commands/insertbootstrapaccordionitemcommand.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/commands/modifybootstrapaccordioncommand.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/commands/removebootstrapaccordionitemcommand.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/index.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/integration/bootstrapaccordionclipboardpipeline.ts create mode 100644 ckeditor5_plugins/bootstrapAccordion/src/integration/bootstrapaccordiongeneralhtmlsupport.ts create mode 100644 css/bootstrap-accordion.admin.css create mode 100644 css/bootstrap-accordion.css create mode 100644 css/bootstrap-accordion.editor.css create mode 100644 icons/bootstrap-accordion-item.svg create mode 100644 icons/bootstrap-accordion-open-collapse.svg create mode 100644 icons/bootstrap-accordion.svg create mode 100644 js/build/bootstrapAccordion.js create mode 100644 src/Plugin/Filter/BootstrapAccordion.php diff --git a/ckeditor5_plugins/bootstrapAccordion/README.md b/ckeditor5_plugins/bootstrapAccordion/README.md new file mode 100644 index 0000000..2ebb5a5 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/README.md @@ -0,0 +1,62 @@ +# CKEditor 5 Plugin: Bootstrap Accordion + +## Model +```xml + + + + ... + + + + ... + + + + + + ... + + + + ... + + + + ... + +``` + +## HTML +```html +
+
+
+ ... +
+
+
+ ... +
+
+
+
+
+ ... +
+
+
+ ... +
+
+
+ ... +
+``` diff --git a/ckeditor5_plugins/bootstrapAccordion/src/augmentation.ts b/ckeditor5_plugins/bootstrapAccordion/src/augmentation.ts new file mode 100644 index 0000000..1709a63 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/augmentation.ts @@ -0,0 +1,31 @@ +import type { ClipboardPipeline } from '@ckeditor/ckeditor5-clipboard'; +import type { DataFilter } from '@ckeditor/ckeditor5-html-support'; +import type { BootstrapAccordionConfig, ItemsStayOpen, ItemsStayOpenAttributeDefinition } from './bootstrapaccordionconfig'; +import type BootstrapAccordionCollapseAllCommand from './commands/bootstrapaccordioncollapseallcommand'; +import type BootstrapAccordionEvents from './bootstrapaccordionevents'; +import type BootstrapAccordionFirstItemOpenCommand from './commands/bootstrapaccordionfirstitemopencommand'; +import type BootstrapAccordionOpenAllCommand from './commands/bootstrapaccordionopenallcommand'; +import type InsertBootstrapAccordionCommand from './commands/insertbootstrapaccordioncommand'; +import type InsertBootstrapAccordionItemCommand from './commands/insertbootstrapaccordionitemcommand'; +import type ModifyBootstrapAccordionCommand from './commands/modifybootstrapaccordioncommand'; +import type RemoveBootstrapAccordionItemCommand from './commands/removebootstrapaccordionitemcommand'; + +declare module '@ckeditor/ckeditor5-core' { + interface EditorConfig { + bootstrapAccordion: BootstrapAccordionConfig; + } + interface CommandsMap { + bootstrapAccordionCollapseAll: BootstrapAccordionCollapseAllCommand; + bootstrapAccordionFirstItemOpen: BootstrapAccordionFirstItemOpenCommand; + bootstrapAccordionItemsStayOpen: ModifyBootstrapAccordionCommand; + bootstrapAccordionOpenAll: BootstrapAccordionOpenAllCommand; + insertBootstrapAccordion: InsertBootstrapAccordionCommand; + insertBootstrapAccordionItem: InsertBootstrapAccordionItemCommand; + removeBootstrapAccordionItem: RemoveBootstrapAccordionItemCommand; + } + interface PluginsMap { + [BootstrapAccordionEvents.pluginName]: BootstrapAccordionEvents; + [ClipboardPipeline.pluginName]: ClipboardPipeline; + [DataFilter.pluginName]: DataFilter; + } +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordion.ts b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordion.ts new file mode 100644 index 0000000..c045aef --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordion.ts @@ -0,0 +1,32 @@ +import type { PluginInterface } from '@ckeditor/ckeditor5-core/src/plugin'; +import { Plugin } from 'ckeditor5/src/core'; +import BootstrapAccordionEditing from './bootstrapaccordionediting'; +import BootstrapAccordionEvents from './bootstrapaccordionevents'; +import BootstrapAccordionKeyboard from './bootstrapaccordionkeyboard'; +import BootstrapAccordionUI from './bootstrapaccordionui'; + +/** + * Defines the base Bootstrap Accordion plugin. + */ +export default class BootstrapAccordion extends Plugin implements PluginInterface { + + /** + * The plugin's name in the PluginCollection. + */ + static get pluginName(): 'BootstrapAccordion' { + return 'BootstrapAccordion' as const; + } + + /** + * The plugin's dependencies. + */ + static get requires() { + return [ + BootstrapAccordionEditing, + BootstrapAccordionEvents, + BootstrapAccordionKeyboard, + BootstrapAccordionUI + ] as const; + } + +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionconfig.ts b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionconfig.ts new file mode 100644 index 0000000..df00109 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionconfig.ts @@ -0,0 +1,134 @@ +/** + * @file Contains configuration for Bootstrap Accordion. + */ + +import type { ToolbarConfigItem } from '@ckeditor/ckeditor5-core'; +import type { ModelAttributeDefinition, SelectableOption } from './bootstrapaccordiontypes'; + +/** + * The options available in `editor.config.get('bootstrapAccordion')`. + */ +export interface BootstrapAccordionConfig { + toolbarItems: ToolbarConfigItem[]; +}; + +/** + * The allowed model attributes for an accordion. + */ +export type AccordionModelAttribute = 'bootstrapAccordionId' | 'bootstrapAccordionStyle' | 'bootstrapAccordionItemsStayOpen'; + +/** + * The allowed model attributes for an accordion header. + */ +export type AccordionButtonModelAttribute = 'bootstrapAccordionButtonCollapsed'; + +/** + * The allowed model attributes for an accordion collapse. + */ +export type AccordionCollapseModelAttribute = 'bootstrapAccordionCollapseShow'; + +/** + * Defines the allowed values for the `bootstrapAccordionStyle` attribute. + */ +export type Style = 'regular' | 'flush'; + +/** + * Defines the attribute definition for the `bootstrapAccordionStyle` + * attribute. + */ +export type StyleAttributeDefinition = ModelAttributeDefinition; + +/** + * Defines the attribute value to class name conversion for the + * `bootstrapAccordionStyle` attribute. + */ +export const styleOptions: { [key in Style]: SelectableOption; } = { + regular: { + label: 'Regular' + }, + flush: { + label: 'Flush', + className: 'accordion-flush' + } +}; + +/** + * Defines the default value for the `bootstrapAccordionStyle` attribute. + */ +export const styleDefault: Style = 'regular'; + +/** + * Defines the allowed values for the `bootstrapAccordionItemsStayOpen` + * attribute. + */ +export type ItemsStayOpen = 'true' | 'false'; + +/** + * Defines the attribute definition for the `bootstrapAccordionItemsStayOpen` + * attribute. + */ +export type ItemsStayOpenAttributeDefinition = ModelAttributeDefinition; + +/** + * Defines the attribute value to class name conversion for the + * `bootstrapAccordionItemsStayOpen` attribute. + */ +export const itemsStayOpenOptions: { [key in ItemsStayOpen]: SelectableOption; } = { + true: { + className: 'accordion-items-stay-open' + }, + false: {} +}; + +/** + * Defines the default value for the `bootstrapAccordionItemsStayOpen` + * attribute. + */ +export const itemsStayOpenDefault: ItemsStayOpen = 'false'; + +/** + * Defines the allowed values for the `bootstrapAccordionButtonCollapsed` + * attribute. + */ +export type ButtonCollapsed = 'true' | 'false'; + +/** + * Defines the attribute definition for the `bootstrapAccordionButtonCollapsed` + * attribute. + */ +export type ButtonCollapsedAttributeDefinition = ModelAttributeDefinition; + +/** + * Defines the attribute value to class name conversion for the + * `bootstrapAccordionButtonCollapsed` attribute. + */ +export const buttonCollapsedOptions: { [key in ItemsStayOpen]: SelectableOption; } = { + true: { + className: 'collapsed' + }, + false: {} +}; + +/** + * Defines the allowed values for the `bootstrapAccordionCollapseShow` + * attribute. + */ +export type CollapseShow = 'true' | 'false'; + +/** + * Defines the attribute definition for the `bootstrapAccordionCollapseShow` + * attribute. + */ +export type CollapseShowAttributeDefinition = ModelAttributeDefinition; + +/** + * Defines the attribute value to class name conversion for the + * `bootstrapAccordionCollapseShow` attribute. + */ +export const collapseShowOptions: { [key in ItemsStayOpen]: SelectableOption; } = { + true: { + className: 'show' + }, + false: {} +}; + diff --git a/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionediting.ts b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionediting.ts new file mode 100644 index 0000000..c9e69c8 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionediting.ts @@ -0,0 +1,457 @@ +import type { PluginInterface } from '@ckeditor/ckeditor5-core/src/plugin'; +import type { UpcastElementEvent } from '@ckeditor/ckeditor5-engine'; +import type { + AccordionCollapseModelAttribute, + AccordionButtonModelAttribute, + AccordionModelAttribute, + CollapseShow, + CollapseShowAttributeDefinition, + ButtonCollapsed, + ButtonCollapsedAttributeDefinition, + ItemsStayOpen, + ItemsStayOpenAttributeDefinition, + Style, + StyleAttributeDefinition +} from './bootstrapaccordionconfig'; +import type { ModelAttributeDefinition, SelectableOption } from './bootstrapaccordiontypes'; +import { Plugin } from 'ckeditor5/src/core'; +import { uid } from 'ckeditor5/src/utils'; +import { Widget, toWidget, toWidgetEditable } from 'ckeditor5/src/widget'; +import { + buttonCollapsedOptions, + collapseShowOptions, + itemsStayOpenDefault, + itemsStayOpenOptions, + styleOptions +} from './bootstrapaccordionconfig'; +import { engineEnablePlaceholder as shimmedEnablePlaceholder } from './bootstrapaccordionshims'; +import BootstrapAccordionCollapseAllCommand from './commands/bootstrapaccordioncollapseallcommand'; +import BootstrapAccordionFirstItemOpenCommand from './commands/bootstrapaccordionfirstitemopencommand'; +import BootstrapAccordionOpenAllCommand from './commands/bootstrapaccordionopenallcommand'; +import InsertBootstrapAccordionCommand from './commands/insertbootstrapaccordioncommand'; +import InsertBootstrapAccordionItemCommand from './commands/insertbootstrapaccordionitemcommand'; +import RemoveBootstrapAccordionItemCommand from './commands/removebootstrapaccordionitemcommand'; +import ModifyBootstrapAccordionCommand from './commands/modifybootstrapaccordioncommand'; + +/** + * Defines the Bootstrap Accordion schema, conversion, and commands. + * + * CKEditor 5 plugins do not work directly with the DOM. They are defined as + * plugin-specific data models that are then converted to markup that is + * inserted in the DOM. + * + * CKEditor 5 internally interacts with box as this model: + * + * ```xml + * + * + * + * ... + * + * + * + * ... + * + * + * + * + * + * ... + * + * + * + * ... + * + * + * + * ... + * + * ``` + * + * Which is converted for the browser/user as this markup: + * + * ```html + *
+ *
+ *
+ * ... + *
+ *
+ *
+ * ... + *
+ *
+ *
+ *
+ *
+ * ... + *
+ *
+ *
+ * ... + *
+ *
+ *
+ * ... + *
+ * ``` + * + * This file has the logic for defining the accordion model, and for how it is + * converted to standard DOM markup. + */ +export default class BootstrapAccordionEditing extends Plugin implements PluginInterface { + + /** + * The plugin's name in the PluginCollection. + */ + static get pluginName(): 'BootstrapAccordionEditing' { + return 'BootstrapAccordionEditing' as const; + } + + /** + * The plugin's dependencies. + */ + static get requires() { + return [Widget] as const; + } + + /** + * @inheritdoc + */ + init() { + this._defineSchema(); + this._defineConverters(); + this._defineCommands(); + } + + /** + * Defines the accordion's model schema. + */ + private _defineSchema() { + const schema = this.editor.model.schema; + + schema.register('bootstrapAccordion', { + isObject: true, + allowWhere: '$block', + allowAttributes: + [ + 'bootstrapAccordionId', + 'bootstrapAccordionStyle', + 'bootstrapAccordionItemsStayOpen' + ] as AccordionModelAttribute[], + allowChildren: ['bootstrapAccordionItem'] + }); + + schema.register('bootstrapAccordionItem', { + allowIn: 'bootstrapAccordion', + allowChildren: ['bootstrapAccordionHeader', 'bootstrapAccordionBody'] + }); + + schema.register('bootstrapAccordionHeader', { + allowIn: 'bootstrapAccordionItem', + allowChildren: ['bootstrapAccordionButton'] + }); + + schema.register('bootstrapAccordionButton', { + // Limits commands like "select all" to its contents when the cursor is + // inside. + isLimit: true, + // Allows only text and text-like elements (like icons) inside. + allowContentOf: '$block', + allowAttributes: + [ + 'bootstrapAccordionButtonCollapsed' + ] as AccordionButtonModelAttribute[], + allowIn: 'bootstrapAccordionHeader' + }); + + schema.register('bootstrapAccordionCollapse', { + allowIn: 'bootstrapAccordionItem', + allowAttributes: + [ + 'bootstrapAccordionCollapseShow' + ] as AccordionCollapseModelAttribute[], + }); + + schema.register('bootstrapAccordionBody', { + // Limits commands like "select all" to its contents when the cursor is + // inside. + isLimit: true, + // Allows almost everything inside, same as if at the root of the editor. + allowContentOf: '$root', + allowIn: 'bootstrapAccordionCollapse' + }); + + schema.addAttributeCheck((context, attributeName) => { + if (['linkHref', 'anchorId'].includes(attributeName) && [...context.getNames()].includes('bootstrapAccordionButton')) { + // Disallows links and anchors inside accordion buttons. + return false; + } + return; + }); + } + + /** + * Defines the accordion's model converters. + * + * Converters determine how CKEditor 5 models are converted into markup and + * vice-versa. + */ + private _defineConverters() { + const { conversion, editing, t } = this.editor; + + conversion.attributeToAttribute({ + model: 'bootstrapAccordionId', + view: 'data-accordion-id' + }); + + conversion.attributeToAttribute(buildAttributeToAttributeClassNameDefinition('bootstrapAccordionStyle', styleOptions)); + conversion.attributeToAttribute(buildAttributeToAttributeClassNameDefinition('bootstrapAccordionItemsStayOpen', itemsStayOpenOptions)); + conversion.attributeToAttribute(buildAttributeToAttributeClassNameDefinition('bootstrapAccordionButtonCollapsed', buttonCollapsedOptions)); + conversion.attributeToAttribute(buildAttributeToAttributeClassNameDefinition('bootstrapAccordionCollapseShow', collapseShowOptions)); + + // Defines conversion for bootstrapAccordion. + conversion.for('upcast').add(dispatcher => { + dispatcher.on('element:div', (_evt, data, conversionApi) => { + const viewItem = data.viewItem; + if (conversionApi.consumable.consume(viewItem, { name: true, classes: 'accordion' })) { + const modelElement = conversionApi.writer.createElement('bootstrapAccordion', { + // Enforces a default for accordion id. + bootstrapAccordionId: viewItem.getAttribute('data-accordion-id') || viewItem.getAttribute('id') || uid() + } as { [key in AccordionModelAttribute]: string; }); + // Forces insertion and conversion of a clean `bootstrapAccordion` + // model element. + if (conversionApi.safeInsert(modelElement, data.modelCursor)) { + conversionApi.convertChildren(viewItem, modelElement); + conversionApi.updateConversionResult(modelElement, data); + } + } + }); + }); + conversion.for('editingDowncast').elementToElement({ + model: 'bootstrapAccordion', + view: (_modelElement, { writer }) => toWidget( + writer.createContainerElement('div', { class: 'ckeditor5-bootstrap-accordion__widget' }), + writer, { label: t('Accordion widget'), hasSelectionHandle: true } + ) + }); + conversion.for('dataDowncast').elementToElement({ + model: 'bootstrapAccordion', + view: { + name: 'div', + classes: 'accordion' + } + }); + + // Defines conversion for bootstrapAccordionItem. + conversion.for('upcast').elementToElement({ + model: 'bootstrapAccordionItem', + view: { + name: 'div', + classes: 'accordion-item' + } + }); + conversion.for('editingDowncast').elementToElement({ + model: 'bootstrapAccordionItem', + view: { + name: 'div', + classes: 'ckeditor5-bootstrap-accordion-item' + } + }); + conversion.for('dataDowncast').elementToElement({ + model: 'bootstrapAccordionItem', + view: { + name: 'div', + classes: 'accordion-item' + } + }); + + // Defines conversion for bootstrapAccordionHeader. + conversion.for('upcast').add(dispatcher => { + dispatcher.on('element', (_evt, data, conversionApi) => { + if (conversionApi.consumable.consume(data.viewItem, { name: true, classes: 'accordion-header' })) { + const modelElement = conversionApi.writer.createElement('bootstrapAccordionHeader'); + // Forces insertion and conversion of a clean + // `bootstrapAccordionHeader` model element. + if (conversionApi.safeInsert(modelElement, data.modelCursor)) { + conversionApi.convertChildren(data.viewItem, modelElement); + conversionApi.updateConversionResult(modelElement, data); + } + } + }); + }); + conversion.for('editingDowncast').elementToElement({ + model: 'bootstrapAccordionHeader', + view: { + name: 'div', + classes: 'ckeditor5-bootstrap-accordion-header' + } + }); + conversion.for('dataDowncast').elementToElement({ + model: 'bootstrapAccordionHeader', + view: { + name: 'div', + classes: 'accordion-header' + } + }); + + // Defines conversion for bootstrapAccordionButton. + conversion.for('upcast').add(dispatcher => { + dispatcher.on('element:a', (_evt, data, conversionApi) => { + if (conversionApi.consumable.consume(data.viewItem, { name: true, classes: 'accordion-button', attributes: ['href'] }) || conversionApi.consumable.consume(data.viewItem, { name: true, classes: 'accordion-button' })) { + const modelElement = conversionApi.writer.createElement('bootstrapAccordionButton'); + // Forces insertion and conversion of a clean + // `bootstrapAccordionButton` model element. + if (conversionApi.safeInsert(modelElement, data.modelCursor)) { + conversionApi.convertChildren(data.viewItem, modelElement); + conversionApi.updateConversionResult(modelElement, data); + } + } + }); + dispatcher.on('element:button', (_evt, data, conversionApi) => { + if (conversionApi.consumable.consume(data.viewItem, { name: true, classes: 'accordion-button' })) { + const modelElement = conversionApi.writer.createElement('bootstrapAccordionButton'); + // Forces insertion and conversion of a clean + // `bootstrapAccordionButton` model element. + if (!conversionApi.safeInsert(modelElement, data.modelCursor)) { + conversionApi.convertChildren(data.viewItem, modelElement); + conversionApi.updateConversionResult(modelElement, data); + } + } + }); + }); + conversion.for('editingDowncast').elementToElement({ + model: 'bootstrapAccordionButton', + view: (_modelElement, { writer }) => { + const element = writer.createEditableElement('a', { + class: 'ckeditor5-bootstrap-accordion-button', + href: '#' + }); + element.placeholder = t('Accordion item'); + shimmedEnablePlaceholder({ + view: editing.view, + element, + keepOnFocus: true + }); + const widget = toWidgetEditable(element, writer, { label: t('Accordion item header') }); + return widget; + } + }); + conversion.for('dataDowncast').elementToElement({ + model: 'bootstrapAccordionButton', + view: { + name: 'a', + classes: 'accordion-button', + attributes: { + href: '#' + } + } + }); + + // Defines conversion for bootstrapAccordionCollapse. + conversion.for('upcast').elementToElement({ + model: 'bootstrapAccordionCollapse', + view: { + name: 'div', + classes: 'accordion-collapse' + } + }); + conversion.for('editingDowncast').elementToElement({ + model: 'bootstrapAccordionCollapse', + view: { + name: 'div', + classes: 'ckeditor5-bootstrap-accordion-collapse' + } + }); + conversion.for('dataDowncast').elementToElement({ + model: 'bootstrapAccordionCollapse', + view: { + name: 'div', + classes: ['accordion-collapse', 'collapse'] + } + }); + + // Defines conversion for bootstrapAccordionBody. + conversion.for('upcast').elementToElement({ + model: 'bootstrapAccordionBody', + view: { + name: 'div', + classes: 'accordion-body' + } + }); + conversion.for('editingDowncast').elementToElement({ + model: 'bootstrapAccordionBody', + view: (_modelElement, { writer }) => { + const element = writer.createEditableElement('div', { + class: 'ckeditor5-bootstrap-accordion-body' + }); + element.placeholder = t('Accordion item body'); + shimmedEnablePlaceholder({ + view: editing.view, + element, + isDirectHost: false, + keepOnFocus: true + }); + return toWidgetEditable(element, writer, { label: t('Accordion item body') }); + } + }); + conversion.for('dataDowncast').elementToElement({ + model: 'bootstrapAccordionBody', + view: { + name: 'div', + classes: 'accordion-body' + } + }); + } + + /** + * Defines the commands for inserting or modifying the accordion. + */ + private _defineCommands() { + const editor = this.editor; + const commands = editor.commands; + commands.add('insertBootstrapAccordion', new InsertBootstrapAccordionCommand(editor)); + commands.add('insertBootstrapAccordionItem', new InsertBootstrapAccordionItemCommand(editor)); + commands.add('removeBootstrapAccordionItem', new RemoveBootstrapAccordionItemCommand(editor)); + commands.add('bootstrapAccordionFirstItemOpen', new BootstrapAccordionFirstItemOpenCommand(editor)); + commands.add('bootstrapAccordionItemsStayOpen', new ModifyBootstrapAccordionCommand(editor, 'bootstrapAccordionItemsStayOpen', itemsStayOpenDefault)); + commands.add('bootstrapAccordionOpenAll', new BootstrapAccordionOpenAllCommand(editor)); + commands.add('bootstrapAccordionCollapseAll', new BootstrapAccordionCollapseAllCommand(editor)); + } + +} + +/** + * Builds an attribute to attribute definition which converts between a CSS + * class and a model attribute. + * + * @param attributeName + * The attribute name. + * @param attributeOptions + * The options available for the attribute. + * @returns + * The attribute to attribute definition of the specified attribute. + */ +function buildAttributeToAttributeClassNameDefinition>(attributeName: D[1], attributeOptions: Record) { + const view: { [key: string]: { key: 'class', value: string } } = {}; + const values: string[] = []; + for (const [value, option] of Object.entries(attributeOptions)) { + if (!option.className) continue; + values.push(value); + view[value] = { key: 'class', value: option.className }; + } + return { + model: { + key: attributeName, + values + }, + view + }; +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionevents.ts b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionevents.ts new file mode 100644 index 0000000..e50821c --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionevents.ts @@ -0,0 +1,64 @@ +import type { PluginInterface } from '@ckeditor/ckeditor5-core/src/plugin'; +import type { AccordionEvent, AccordionItemEvent } from './bootstrapaccordiontypes'; +import { Plugin } from 'ckeditor5/src/core'; +import BootstrapAccordionEditing from './bootstrapaccordionediting'; + +/** + * Listens for events that affect a selected Bootstrap Accordion widget. + */ +export default class BootstrapAccordionEvents extends Plugin implements PluginInterface { + + /** + * The plugin's name in the PluginCollection. + */ + static get pluginName(): 'BootstrapAccordionEvents' { + return 'BootstrapAccordionEvents' as const; + } + + /** + * The plugin's dependencies. + */ + static get requires() { + return [BootstrapAccordionEditing] as const; + } + + /** + * @inheritdoc + */ + init() { + const commands = this.editor.commands; + const bootstrapAccordionFirstItemOpen = commands.get('bootstrapAccordionFirstItemOpen')!; + const bootstrapAccordionItemsStayOpen = commands.get('bootstrapAccordionItemsStayOpen')!; + const bootstrapAccordionOpenAll = commands.get('bootstrapAccordionOpenAll')!; + const bootstrapAccordionCollapseAll = commands.get('bootstrapAccordionCollapseAll')!; + const insertBootstrapAccordionItem = commands.get('insertBootstrapAccordionItem')!; + const removeBootstrapAccordionItem = commands.get('removeBootstrapAccordionItem')!; + + this.on('accordion', (_eventInfo, type) => { + if (type === 'toggleFirstItemOpen') { + bootstrapAccordionFirstItemOpen.execute({ value: !bootstrapAccordionFirstItemOpen.value }); + } else if (type === 'toggleItemsStayOpen') { + const oldValue = bootstrapAccordionItemsStayOpen.value; + bootstrapAccordionItemsStayOpen.execute({ value: oldValue === 'false' ? 'true' : 'false' }); + if (oldValue === 'true') { + bootstrapAccordionCollapseAll.execute({ omitFirst: true }); + } + } else if (type === 'openAll') { + bootstrapAccordionOpenAll.execute(); + } else if (type === 'collapseAll') { + bootstrapAccordionCollapseAll.execute(); + } + }); + + this.on('accordionItem', (_eventInfo, type) => { + if (type === 'insertAbove') { + insertBootstrapAccordionItem.execute({ value: 'before' }); + } else if (type === 'insertBelow') { + insertBootstrapAccordionItem.execute({ value: 'after' }); + } else if (type === 'remove') { + removeBootstrapAccordionItem.execute(); + } + }); + } + +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionkeyboard.ts b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionkeyboard.ts new file mode 100644 index 0000000..7733ca0 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionkeyboard.ts @@ -0,0 +1,153 @@ +import type { PluginInterface } from '@ckeditor/ckeditor5-core/src/plugin'; +import type { + BubblingEventInfo, + DocumentSelection, + DomEventData, + Element, + ViewDocumentTabEvent +} from 'ckeditor5/src/engine'; +import type { KeystrokeInfo } from 'ckeditor5/src/utils'; +import { Plugin } from 'ckeditor5/src/core'; +import { getSelectedAccordionItemModelElement } from './bootstrapaccordionutils'; + +/** + * Enables navigating through Bootstrap Accordion widgets using the tab keys. + */ +export default class BootstrapAccordionKeyboard extends Plugin implements PluginInterface { + + /** + * The plugin's name in the PluginCollection. + */ + static get pluginName(): 'BootstrapAccordionKeyboard' { + return 'BootstrapAccordionKeyboard' as const; + } + + /** + * @inheritdoc + */ + init() { + const viewDocument = this.editor.editing.view.document; + + this.listenTo( + viewDocument, + 'tab', + (bubblingEventInfo: BubblingEventInfo, domEventData: DomEventData & KeystrokeInfo) => + this._handleNavigation(bubblingEventInfo, domEventData, !domEventData.shiftKey), + { context: node => node.is('element') && (node.hasClass('ckeditor5-bootstrap-accordion-button') || node.hasClass('ckeditor5-bootstrap-accordion-body')) } + ); + } + + /** + * Handles navigation keystroke events. + * + * @param bubblingEventInfo + * The event object passed to bubbling event callbacks. + * @param domEventData + * The DOM event data. + * @param forward + * Whether to more forward or backward through the accordion. + */ + private _handleNavigation(bubblingEventInfo: BubblingEventInfo, domEventData: DomEventData, forward: boolean) { + const model = this.editor.model; + const selection = model.document.selection; + const selectedElement = selection.getFirstPosition()?.findAncestor('bootstrapAccordionButton') || selection.getFirstPosition()?.findAncestor('bootstrapAccordionBody'); + + if (!selectedElement) { + return; + } + + const navigateToElement = navigate(selectedElement, selection, forward); + + if (!navigateToElement) { + return; + } + + domEventData.preventDefault(); + domEventData.stopPropagation(); + bubblingEventInfo.stop(); + + model.change(writer => { + writer.setSelection(writer.createRangeIn(navigateToElement)); + }); + } + +} + +/** + * Navigates within an accordion widget. + * + * @param selectedElement + * The selected accordion button or body. + * @param selection + * The model document selection. + * @param forward + * Whether to more forward or backward through the accordion. + * @returns + * The element to navigate to, or null if there isn't one (as in the case of + * the first or last accordion item being selected). + */ +function navigate(selectedElement: Element, selection: DocumentSelection, forward: boolean): Element | null { + const accordionItem = getSelectedAccordionItemModelElement(selection); + if (!accordionItem) { + return null; + } + const accordion = accordionItem.parent as Element; + return forward ? getNext(accordion, accordionItem, selectedElement) : getPrevious(accordion, accordionItem, selectedElement); +} + +/** + * Moves to the previous available element in the accordion. + * + * @param accordion + * The selected accordion. + * @param accordionItem + * The accordion item. If this parameter is `null` then the function simply + * returns `null`. + * @param selectedElement + * The selected accordion button or body. + * @returns + * The previous available element, or null if there isn't one. + */ +function getPrevious(accordion: Element, accordionItem: Element | null, selectedElement: Element | null): Element | null { + if (!accordionItem) { + // Selection was at the start of the accordion, there isn't a previous + // item. + return null; + } + const itemChildren = [...accordionItem.getChildren()]; + const childIndex = selectedElement ? itemChildren.indexOf(selectedElement.parent as Element) - 1 : itemChildren.length - 1; + if (childIndex > -1) { + return (itemChildren[childIndex] as Element).getChild(0) as Element | null; + } else { + // No more elements in this accordion item, move to the previous one. + return getPrevious(accordion, accordion.getChild(accordion.getChildIndex(accordionItem)! - 1) as Element | null, null); + } +} + +/** + * Moves to the next available element in the accordion. + * + * @param accordion + * The selected accordion. + * @param accordionItem + * The accordion item. If this parameter is `null` then the function simply + * returns `null`. + * @param selectedElement + * The selected accordion button or body. + * @returns + * The next available element, or null if there isn't one. + */ +function getNext(accordion: Element, accordionItem: Element | null, selectedElement: Element | null): Element | null { + if (!accordionItem) { + // Selection was at the end of the accordion, there isn't a next item. + return null; + } + const itemChildren = [...accordionItem.getChildren()]; + const childIndex = selectedElement ? itemChildren.indexOf(selectedElement.parent as Element) + 1 : 0; + if (childIndex < itemChildren.length) { + return (itemChildren[childIndex] as Element).getChild(0) as Element | null; + } else { + // No more elements in this accordion item, move to the next one. + return getNext(accordion, accordion.getChild(accordion.getChildIndex(accordionItem)! + 1) as Element | null, null); + } +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionshims.ts b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionshims.ts new file mode 100644 index 0000000..3817b85 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionshims.ts @@ -0,0 +1,44 @@ +/** + * @file Contains shims to avoid breaking older versions of CKEditor 5. + */ + +import type EditableElement from '@ckeditor/ckeditor5-engine/src/view/editableelement'; +import type View from '@ckeditor/ckeditor5-engine/src/view/view'; +import { enablePlaceholder } from 'ckeditor5/src/engine'; +import { ViewModel } from 'ckeditor5/src/ui'; +import { ckMajorVersion } from './bootstrapaccordionutils'; + +// cSpell:ignore editableelement + +/** + * Older versions of CKEditor 5 expect the export to be named `Model` rather + * than `ViewModel`. See https://github.com/ckeditor/ckeditor5/issues/15661 + * + * This shim allows CKEditor 5 Bootstrap Accordion to retain compatibility with + * Drupal 10.2 and earlier. + */ +export const UiViewModel = ViewModel; + +/** + * Older versions of CKEditor 5 handled placeholders differently. + * + * This shim allows CKEditor 5 Bootstrap Accordion to support placeholders in + * Drupal 10.1 and earlier. + * + * @param placeholderOptions + * The placeholder options to be passed through to the `enablePlaceholder` + * library call. + */ +export function engineEnablePlaceholder(placeholderOptions: { + view: View; + element: EditableElement; + isDirectHost?: boolean; + keepOnFocus?: boolean; + text?: string; +}) { + if (ckMajorVersion < 39) { + // Uses legacy `text` option in older versions of CKEditor 5. + placeholderOptions.text = placeholderOptions.element.placeholder; + } + enablePlaceholder(placeholderOptions); +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordiontypes.ts b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordiontypes.ts new file mode 100644 index 0000000..94528d5 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordiontypes.ts @@ -0,0 +1,50 @@ +/** + * @file Contains TypeScript type definitions for Bootstrap Accordion. + */ + +/** + * The types of operations that can be done to an accordion. + */ +export type AccordionOperation = 'toggleFirstItemOpen' | 'toggleItemsStayOpen' | 'openAll' | 'collapseAll'; + +/** + * The types of operations that can be done to an accordion item. + */ +export type AccordionItemOperation = 'insertAbove' | 'insertBelow' | 'remove'; + +/** + * The event fired when a command is chosen with an accordion is selected. + */ +export type AccordionEvent = { + name: 'accordion'; + args: [type: AccordionOperation]; +}; + +/** + * The event fired when a command is chosen with an accordion item selected. + */ +export type AccordionItemEvent = { + name: 'accordionItem'; + args: [type: AccordionItemOperation]; +}; + +/** + * An allowed attribute for a model. + */ +export type ModelAttribute = string; + +/** + * A compound type for linking together an attribute and its options as a + * single attribute definition. + */ +export type ModelAttributeDefinition = [T, A]; + +/** + * An option in the accordion toolbar which changes a class name on a selected + * element. + */ +export type SelectableOption = { + label?: string; + icon?: string; + className?: string; +}; diff --git a/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionui.ts b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionui.ts new file mode 100644 index 0000000..c7ad96c --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionui.ts @@ -0,0 +1,268 @@ +import type { PluginInterface } from '@ckeditor/ckeditor5-core/src/plugin'; +import type { DropdownViewEvent } from '@ckeditor/ckeditor5-ui/src/dropdown/dropdownview'; +import type { Command } from 'ckeditor5/src/core'; +import type { ButtonExecuteEvent, DropdownView, ViewModel } from 'ckeditor5/src/ui'; +import type { Locale } from 'ckeditor5/src/utils'; +import type { AccordionEvent, AccordionItemEvent, AccordionItemOperation, AccordionOperation } from './bootstrapaccordiontypes'; +import { Plugin } from 'ckeditor5/src/core'; +import { ButtonView, ListDropdownItemDefinition, addListToDropdown, createDropdown } from 'ckeditor5/src/ui'; +import { Collection } from 'ckeditor5/src/utils'; +import { WidgetToolbarRepository } from 'ckeditor5/src/widget'; +import BootstrapAccordionEvents from './bootstrapaccordionevents'; +import { UiViewModel as ShimmedViewModel } from './bootstrapaccordionshims'; +import { getSelectedAccordionWidget } from './bootstrapaccordionutils'; +import icon from '../../../icons/bootstrap-accordion.svg'; +import iconItem from '../../../icons/bootstrap-accordion-item.svg'; +import iconOpenCollapse from '../../../icons/bootstrap-accordion-open-collapse.svg'; + +// cSpell:ignore dropdownview switchbutton + +/** + * Defines the user interface for editing Bootstrap Accordion widgets. + */ +export default class BootstrapAccordionUI extends Plugin implements PluginInterface { + + /** + * The plugin's name in the PluginCollection. + */ + static get pluginName(): 'BootstrapAccordionUI' { + return 'BootstrapAccordionUI' as const; + } + + /** + * The plugin's dependencies. + */ + static get requires() { + return [BootstrapAccordionEvents, WidgetToolbarRepository] as const; + } + + /** + * @inheritdoc + */ + init() { + const { commands, plugins, ui } = this.editor; + const componentFactory = ui.componentFactory; + const events = plugins.get('BootstrapAccordionEvents')!; + + componentFactory.add('bootstrapAccordion', locale => + createToolbarButton(locale, locale.t('Insert accordion'), icon, commands.get('insertBootstrapAccordion')!)); + componentFactory.add('bootstrapAccordionItem', locale => + this._buildAccordionItemToolbarDropdown(locale, events)); + componentFactory.add('bootstrapAccordionOpenCollapse', locale => + this._buildAccordionOpenCollapseToolbarDropdown(locale, events)); + } + + /** + * @inheritdoc + */ + afterInit() { + const { config, plugins } = this.editor; + const widgetToolbarRepository = plugins.get(WidgetToolbarRepository); + + widgetToolbarRepository.register('bootstrapAccordion', { + items: config.get('bootstrapAccordion.toolbarItems')!, + getRelatedElement: getSelectedAccordionWidget + }); + } + + /** + * Builds the dropdown with options for the selected accordion item. + * + * @param locale + * The locale. + * @param events + * An instance of the BootstrapAccordionEvents plugin. + * @returns + * The dropdown view. + */ + private _buildAccordionItemToolbarDropdown(locale: Locale, events: BootstrapAccordionEvents): DropdownView { + const commands = this.editor.commands; + const insertBootstrapAccordionItem = commands.get('insertBootstrapAccordionItem')!; + const removeBootstrapAccordionItem = commands.get('removeBootstrapAccordionItem')!; + + const dropdownView = createDropdown(locale); + const buttonView = dropdownView.buttonView; + const list = new Collection(); + const t = locale.t; + + list.add({ + type: 'button', model: + createViewModel(insertBootstrapAccordionItem, null, 'insertAbove', t('Insert item above')) + }); + list.add({ + type: 'button', model: + createViewModel(insertBootstrapAccordionItem, null, 'insertBelow', t('Insert item below')) + }); + list.add({ + type: 'button', model: + createViewModel(removeBootstrapAccordionItem, null, 'remove', t('Delete item')) + }); + + addListToDropdown(dropdownView, list); + + dropdownView.on('execute', eventInfo => + events.fire('accordionItem', (eventInfo.source as typeof ViewModel).name as AccordionItemOperation)); + + buttonView.set({ + label: t('Accordion item'), + icon: iconItem, + tooltip: t('Accordion item'), + class: 'ck-dropdown__button_label-width_auto', + withText: false + }); + + return dropdownView; + } + + /** + * Builds the dropdown with open/collapse options for the selected accordion. + * + * @param locale + * The locale. + * @param events + * An instance of the BootstrapAccordionEvents plugin. + * @returns + * The dropdown view. + */ + private _buildAccordionOpenCollapseToolbarDropdown(locale: Locale, events: BootstrapAccordionEvents): DropdownView { + const commands = this.editor.commands; + + const dropdownView = createDropdown(locale); + const buttonView = dropdownView.buttonView; + const list = new Collection(); + const t = locale.t; + + list.add({ + type: 'switchbutton', model: + createViewModel(commands.get('bootstrapAccordionFirstItemOpen')!, true, 'toggleFirstItemOpen', t('Open first item')) + }); + list.add({ + type: 'switchbutton', model: + createViewModel(commands.get('bootstrapAccordionItemsStayOpen')!, 'true', 'toggleItemsStayOpen', t('Allow opening multiple items')) + }); + list.add({ type: 'separator' }); + list.add({ + type: 'button', model: + createViewModel(commands.get('bootstrapAccordionOpenAll')!, 'true', 'openAll', t('Open all items')) + }); + list.add({ + type: 'button', model: + createViewModel(commands.get('bootstrapAccordionCollapseAll')!, 'true', 'collapseAll', t('Collapse all items')) + }); + + addListToDropdown(dropdownView, list); + + dropdownView.on('execute', eventInfo => + events.fire('accordion', (eventInfo.source as typeof ViewModel).name as AccordionOperation)); + + buttonView.set({ + label: t('Accordion open / collapse'), + icon: iconOpenCollapse, + tooltip: t('Accordion open / collapse'), + class: 'ck-dropdown__button_label-width_auto', + withText: false + }); + + return dropdownView; + } + + +} + +/** + * Creates a toolbar button to execute a command. + * + * @param locale + * The locale. + * @param label + * The button's label. + * @param icon + * The button's icon (can be `null` for none). + * @param command + * The command to execute when pressing the button. + * @param value + * The value to pass to the command (optional). + * @returns + * A button with the specified parameters. + */ +function createToolbarButton(locale: Locale, label: string, icon: string | null | undefined, command: Command, value?: T): ButtonView { + const editor = command.editor; + const buttonView = createButton(locale, label, icon); + // Displays the tooltip on hover if there is no icon. + buttonView.tooltip = !!icon; + // Disables the button if the command is disabled. + buttonView.bind('isEnabled').to(command); + // Executes the command with the button's value on click. + buttonView.on('execute', () => { + command.execute({ value }); + editor.editing.view.focus(); + }); + return buttonView; +} + +/** + * Creates a button. + * + * @param locale + * The locale. + * @param label + * The button's label. + * @param icon + * The button's icon (optional). + * @param className + * The button's class (optional). + * @param withText + * Set to force text display even if the button has an icon. + * @returns + * A button with the specified parameters. + */ +function createButton(locale: Locale, label: string, icon?: string | null, className?: string | null, withText?: boolean | string | null): ButtonView { + const button = new ButtonView(locale); + button.set({ + label: typeof withText === 'string' ? withText : label, + icon, + tooltip: icon ? label : false, + withText: withText || !icon, + class: className + }); + return button; +} + +/** + * Creates a view model. + * + * @param command + * The command this view model affects. + * @param value + * The value of the command which makes this view model `on`. Can be `null`, + * in which case it will never have the `on` state. + * @param name + * The view model's name. + * @param label + * The view model's label. + * @param icon + * The view model's icon (optional). + * @param className + * The view model's class (optional). + * @param withText + * Set to force text display even if the button has an icon. + * @returns + * A view model with the specified parameters. + */ +function createViewModel(command: Command, value: unknown, name: T, label: string, icon?: string | null, className?: string | null, withText?: boolean | string | null): ViewModel { + const viewModel = new ShimmedViewModel({ + name, + label: typeof withText === 'string' ? withText : label, + icon, + tooltip: icon ? label : false, + withText: withText || !icon, + class: className + }); + + viewModel.bind('isEnabled').to(command); + if (value !== null) { + viewModel.bind('isOn').to(command, 'value', commandValue => commandValue === value); + } + + return viewModel; +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionutils.ts b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionutils.ts new file mode 100644 index 0000000..227dae8 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/bootstrapaccordionutils.ts @@ -0,0 +1,144 @@ +/** + * @file Contains helper functions for Bootstrap Accordion. + */ + +import type { + DocumentSelection, + Element, + ViewDocumentSelection, + ViewElement, + Writer +} from 'ckeditor5/src/engine'; +import type { AccordionCollapseModelAttribute, AccordionButtonModelAttribute } from './bootstrapaccordionconfig' +import { version } from 'ckeditor5/src/utils'; + +/** + * The CKEditor 5 major version number + */ +export const ckMajorVersion = parseInt(version.split('.')[0]!); + +/** + * Checks if a provided element is an accordion widget. + * + * @param element + * The element to check. + * @returns + * Whether the element is an accordion widget. + */ +export function isAccordionWidget(element: ViewElement): boolean { + return element.hasClass('ckeditor5-bootstrap-accordion__widget'); +} + +/** + * Gets the selected accordion widget. + * + * @param selection + * The view document selection. + * @returns + * The selected accordion widget, or null if there is none. + */ +export function getSelectedAccordionWidget(selection: ViewDocumentSelection): ViewElement | null { + const accordion = selection.focus?.getAncestors().reverse() + .find(node => node.is('element') && isAccordionWidget(node)); + return accordion?.is('element') ? accordion : null; +} + +/** + * Gets the selected accordion item model element. + * + * @param selection + * The model document selection. + * @returns + * The selected accordion item element, or null if there is none. + */ +export function getSelectedAccordionItemModelElement(selection: DocumentSelection): Element | null | undefined { + return selection.getFirstPosition()?.findAncestor('bootstrapAccordionItem'); +} + +/** + * Gets the selected accordion model element. + * + * @param selection + * The model document selection. + * @returns + * The selected accordion element, or null if there is none. + */ +export function getSelectedAccordionModelElement(selection: DocumentSelection): Element | null | undefined { + return selection.getFirstPosition()?.findAncestor('bootstrapAccordion'); +} + +/** + * Creates a `` model element with the necessary child elements. + * + * @param writer + * The model writer. + * @returns + * The accordion item model element. + */ +export function createAccordionItem(writer: Writer, isOpen: boolean = false) { + const accordionItem = writer.createElement('bootstrapAccordionItem'); + const accordionHeader = writer.createElement('bootstrapAccordionHeader'); + const accordionButton = writer.createElement('bootstrapAccordionButton', { + bootstrapAccordionButtonCollapsed: isOpen ? 'false' : 'true', + } as { [key in AccordionButtonModelAttribute]: string; }); + const accordionCollapse = writer.createElement('bootstrapAccordionCollapse', { + bootstrapAccordionCollapseShow: isOpen ? 'true' : 'false', + } as { [key in AccordionCollapseModelAttribute]: string; }); + const accordionBody = writer.createElement('bootstrapAccordionBody'); + + writer.append(accordionHeader, accordionItem); + writer.append(accordionButton, accordionHeader); + writer.append(accordionCollapse, accordionItem); + writer.append(accordionBody, accordionCollapse); + + // The accordionBody text content will automatically be wrapped in a + // `

`. + writer.appendElement('paragraph', accordionBody); + + return { accordionItem, accordionHeader, accordionButton, accordionCollapse, accordionBody }; +} + +/** + * Gets whether an accordion item is open. + * + * @param accordionItem + * The accordion item check if open. + * @returns + * Whether or not the accordion item is open. + */ +export function isAccordionItemOpen(accordionItem: Element) { + let isOpen = false; + [...accordionItem.getChildren()].forEach(node => { + if (node.is('element', 'bootstrapAccordionCollapse')) { + // If the second item is open, assume someone ran the "open all" + // command earlier, and make sure any new accordion items are + // open as well. + isOpen = node.getAttribute('bootstrapAccordionCollapseShow') === 'true'; + } + }); + return isOpen; +} + +/** + * Opens or collapses an accordion item. + * + * @param accordionItem + * The accordion item to open or collapse. + * @param writer + * The model writer. + * @param isOpen + * Whether to open or collapse the accordion item. + */ +export function setAccordionItemIsOpen(accordionItem: Element, writer: Writer, isOpen: boolean) { + [...accordionItem.getChildren()].forEach(node => { + if (node.is('element', 'bootstrapAccordionHeader')) { + [...node.getChildren()].forEach(node => { + if (node.is('element', 'bootstrapAccordionButton')) { + writer.setAttribute('bootstrapAccordionButtonCollapsed', isOpen ? 'false' : 'true', node); + } + }); + } else if (node.is('element', 'bootstrapAccordionCollapse')) { + writer.setAttribute('bootstrapAccordionCollapseShow', isOpen ? 'true' : 'false', node); + } + }); +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/commands/bootstrapaccordioncollapseallcommand.ts b/ckeditor5_plugins/bootstrapAccordion/src/commands/bootstrapaccordioncollapseallcommand.ts new file mode 100644 index 0000000..b37b8b0 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/commands/bootstrapaccordioncollapseallcommand.ts @@ -0,0 +1,39 @@ +import { Command } from 'ckeditor5/src/core'; +import { getSelectedAccordionModelElement, setAccordionItemIsOpen } from '../bootstrapaccordionutils'; +import type { Element } from 'ckeditor5/src/engine'; + +/** + * Represents a command which is executed to collapse all items in an + * accordion. + */ +export default class BootstrapAccordionCollapseAllCommand extends Command { + + /** + * The selected accordion widget. + */ + public accordionWidget?: Element | null; + + /** + * @inheritdoc + */ + public override refresh() { + this.accordionWidget = getSelectedAccordionModelElement(this.editor.model.document.selection); + // Disables any BootstrapAccordionOpenAllCommand if there is no selected + // accordion or only one item can be open at once. + this.isEnabled = !!this.accordionWidget; + } + + /** + * @inheritdoc + */ + public override execute(options: { omitFirst: boolean } = { omitFirst: false }) { + const accordionItemIterator = this.accordionWidget!.getChildren(); + if (options.omitFirst) { + accordionItemIterator.next(); + } + this.editor.model.change(writer => + [...accordionItemIterator].forEach(accordionItem => + setAccordionItemIsOpen(accordionItem as Element, writer, false))); + } + +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/commands/bootstrapaccordionfirstitemopencommand.ts b/ckeditor5_plugins/bootstrapAccordion/src/commands/bootstrapaccordionfirstitemopencommand.ts new file mode 100644 index 0000000..9daf386 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/commands/bootstrapaccordionfirstitemopencommand.ts @@ -0,0 +1,41 @@ +import { Command } from 'ckeditor5/src/core'; +import { getSelectedAccordionModelElement, isAccordionItemOpen, setAccordionItemIsOpen } from '../bootstrapaccordionutils'; +import type { Element } from 'ckeditor5/src/engine'; + +/** + * Represents a command which is executed to modify attributes of the accordion + * from the widget toolbar. + */ +export default class BootstrapAccordionFirstItemOpenCommand extends Command { + + /** + * The selected accordion widget. + */ + public accordionWidget?: Element | null; + + /** + * The value of this command. + */ + public override value: boolean; + + /** + * @inheritdoc + */ + public override refresh() { + const model = this.editor.model; + this.accordionWidget = getSelectedAccordionModelElement(model.document.selection); + // Disables any BootstrapAccordionFirstItemOpenCommand if there is no + // selected accordion. + this.isEnabled = !!this.accordionWidget; + this.value = this.isEnabled && isAccordionItemOpen(this.accordionWidget!.getChild(0) as Element); + } + + /** + * @inheritdoc + */ + public override execute(options: { value: boolean } = { value: false }) { + this.editor.model.change(writer => + setAccordionItemIsOpen(this.accordionWidget!.getChild(0) as Element, writer, options.value)); + } + +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/commands/bootstrapaccordionopenallcommand.ts b/ckeditor5_plugins/bootstrapAccordion/src/commands/bootstrapaccordionopenallcommand.ts new file mode 100644 index 0000000..223f719 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/commands/bootstrapaccordionopenallcommand.ts @@ -0,0 +1,35 @@ +import { Command } from 'ckeditor5/src/core'; +import { getSelectedAccordionModelElement, setAccordionItemIsOpen } from '../bootstrapaccordionutils'; +import type { Element } from 'ckeditor5/src/engine'; + +/** + * Represents a command which is executed to open all items in an accordion. + */ +export default class BootstrapAccordionOpenAllCommand extends Command { + + /** + * The selected accordion widget. + */ + public accordionWidget?: Element | null; + + /** + * @inheritdoc + */ + public override refresh() { + const model = this.editor.model; + this.accordionWidget = getSelectedAccordionModelElement(model.document.selection); + // Disables any BootstrapAccordionOpenAllCommand if there is no selected + // accordion or only one item can be open at once. + this.isEnabled = !!this.accordionWidget && this.accordionWidget.getAttribute('bootstrapAccordionItemsStayOpen') === 'true'; + } + + /** + * @inheritdoc + */ + public override execute() { + this.editor.model.change(writer => + [...this.accordionWidget!.getChildren()].forEach(accordionItem => + setAccordionItemIsOpen(accordionItem as Element, writer, true))); + } + +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/commands/insertbootstrapaccordioncommand.ts b/ckeditor5_plugins/bootstrapAccordion/src/commands/insertbootstrapaccordioncommand.ts new file mode 100644 index 0000000..d5452e5 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/commands/insertbootstrapaccordioncommand.ts @@ -0,0 +1,69 @@ +import type { DocumentSelection, Element, Model } from 'ckeditor5/src/engine'; +import type { AccordionModelAttribute } from '../bootstrapaccordionconfig'; +import { Command } from 'ckeditor5/src/core'; +import { uid } from 'ckeditor5/src/utils'; +import { findOptimalInsertionRange } from 'ckeditor5/src/widget'; +import { itemsStayOpenDefault, styleDefault } from '../bootstrapaccordionconfig'; +import { createAccordionItem } from '../bootstrapaccordionutils'; + +/** + * Represents a command which is executed when the accordion toolbar button is + * pressed to insert an accordion. + */ +export default class InsertBootstrapAccordionCommand extends Command { + + /** + * @inheritdoc + */ + public override refresh() { + const model = this.editor.model; + const { document, schema } = model; + + // Determine if the cursor (selection) is in a position where adding an + // accordion is permitted. This is based on the schema of the model(s) + // currently containing the cursor. + this.isEnabled = schema.checkChild(getParentElement(document.selection, model), 'bootstrapAccordion'); + } + + /** + * @inheritdoc + */ + public override execute() { + const { editing, model } = this.editor; + + model.change(writer => { + // Insert at the current + // selection position in a way that will result in creating a valid model + // structure. + const accordion = writer.createElement('bootstrapAccordion', { + bootstrapAccordionId: uid(), + bootstrapAccordionStyle: styleDefault, + bootstrapAccordionItemsStayOpen: itemsStayOpenDefault + } as { [key in AccordionModelAttribute]: string; }); + const { accordionItem } = createAccordionItem(writer); + writer.append(accordionItem, accordion); + model.insertContent(accordion); + editing.view.focus(); + writer.setSelection(accordion, 'on'); + }); + } + +} + +/** + * Gets the parent element of the document selection. + * + * @param selection + * The document selection. + * @param model + * The data model. + * @returns + * The parent element to evaluate whether an accordion can be inserted as a + * child. + */ +function getParentElement(selection: DocumentSelection, model: Model): Element { + const parent = findOptimalInsertionRange(selection, model).start.parent; + if (parent.isEmpty && !parent.is('element', '$root')) + return parent.parent as Element; + return parent as Element; +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/commands/insertbootstrapaccordionitemcommand.ts b/ckeditor5_plugins/bootstrapAccordion/src/commands/insertbootstrapaccordionitemcommand.ts new file mode 100644 index 0000000..25ac86b --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/commands/insertbootstrapaccordionitemcommand.ts @@ -0,0 +1,53 @@ +import type { Element, PositionOffset } from 'ckeditor5/src/engine'; +import { Command } from 'ckeditor5/src/core'; +import { createAccordionItem, getSelectedAccordionItemModelElement, isAccordionItemOpen, setAccordionItemIsOpen } from '../bootstrapaccordionutils'; + +/** + * Represents a command which is executed when the insert item above or insert + * item below button is pressed with an accordion item selected. + */ +export default class InsertBootstrapAccordionItemCommand extends Command { + + /** + * The currently-selected accordion item. + */ + protected accordionItem?: Element | null; + + /** + * @inheritdoc + */ + public override refresh() { + const selection = this.editor.model.document.selection; + this.accordionItem = getSelectedAccordionItemModelElement(selection); + this.isEnabled = !!this.accordionItem; + } + + /** + * @inheritdoc + */ + public override execute(options: { value: PositionOffset }) { + const { commands, model } = this.editor + const accordionItem = this.accordionItem!; + const value = options.value; + model.change(writer => { + let isOpen = commands.get('bootstrapAccordionItemsStayOpen')?.value === 'true' && isAccordionItemOpen(accordionItem); + const accordion = accordionItem.parent as Element; + if (accordion.getChildIndex(accordionItem) === 0) { + const secondAccordionItem = accordion.getChild(1); + const secondAccordionItemIsOpen = secondAccordionItem ? isAccordionItemOpen(secondAccordionItem as Element) : false; + if (value === 'before') { + // An accordion item is being inserted above the first item, and the + // "open first item" setting is on. Closes the item as it will no + // longer be the first. + isOpen = !!commands.get('bootstrapAccordionFirstItemOpen')?.value; + setAccordionItemIsOpen(accordionItem, writer, secondAccordionItemIsOpen); + } else { + isOpen = secondAccordionItemIsOpen; + } + } + const newAccordionItem = createAccordionItem(writer, isOpen).accordionItem; + writer.insert(newAccordionItem, accordionItem, value); + }); + } + +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/commands/modifybootstrapaccordioncommand.ts b/ckeditor5_plugins/bootstrapAccordion/src/commands/modifybootstrapaccordioncommand.ts new file mode 100644 index 0000000..5a88fd4 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/commands/modifybootstrapaccordioncommand.ts @@ -0,0 +1,80 @@ +import { Command } from 'ckeditor5/src/core'; +import { getSelectedAccordionModelElement } from '../bootstrapaccordionutils'; +import type { Editor } from 'ckeditor5/src/core'; +import type { ModelAttributeDefinition } from '../bootstrapaccordiontypes'; +import type { Element } from 'ckeditor5/src/engine'; + +/** + * Represents a command which is executed to modify attributes of the accordion + * from the widget toolbar. + */ +export default class ModifyBootstrapAccordionCommand = ModelAttributeDefinition> extends Command { + + /** + * The name of the attribute this command modifies. + */ + protected readonly attributeName: D[1]; + + /** + * The default value to set if there isn't one specified. + */ + protected readonly defaultValue: T; + + /** + * The value of this command. + */ + public override value: T; + + /** + * The selected accordion widget. + */ + public accordionWidget?: Element | null; + + /** + * Constructs a new ModifyBootstrapAccordionCommand. + * + * @param editor + * The editor. + * @param attributeName + * The name of the attribute this command modifies. + * @param defaultValue + * The default value to set if there isn't one specified. + */ + public constructor(editor: Editor, attributeName: D[1], defaultValue: T) { + super(editor); + this.attributeName = attributeName; + this.defaultValue = defaultValue; + this.value = defaultValue; + } + + /** + * @inheritdoc + */ + public override refresh() { + const model = this.editor.model; + const attributeName = this.attributeName + const defaultValue = this.defaultValue; + this.accordionWidget = getSelectedAccordionModelElement(model.document.selection); + // Disables any ModifyBootstrapAccordionCommand if there is no selected + // accordion. + this.isEnabled = !!this.accordionWidget; + this.value = defaultValue; + if (this.isEnabled && this.accordionWidget!.hasAttribute(attributeName)) { + // Sets the `value` of this ModifyBootstrapAccordionCommand to the + // attribute of the selected accordion. + this.value = this.accordionWidget!.getAttribute(attributeName) as T; + } + } + + /** + * @inheritdoc + */ + public override execute(options: { value: T } = { value: this.defaultValue }) { + const model = this.editor.model; + const accordionWidget = this.accordionWidget; + // Sets the attribute of the selected accordion to a new value upon + // execution of this command. + model.change(writer => writer.setAttribute(this.attributeName, options.value, accordionWidget!)); + } + +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/commands/removebootstrapaccordionitemcommand.ts b/ckeditor5_plugins/bootstrapAccordion/src/commands/removebootstrapaccordionitemcommand.ts new file mode 100644 index 0000000..73fdf34 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/commands/removebootstrapaccordionitemcommand.ts @@ -0,0 +1,47 @@ +import type { Element } from 'ckeditor5/src/engine'; +import { Command } from 'ckeditor5/src/core'; +import { getSelectedAccordionItemModelElement, setAccordionItemIsOpen } from '../bootstrapaccordionutils'; + +/** + * Represents a command which is executed when the delete item button is + * pressed with an accordion item selected. + */ +export default class RemoveBootstrapAccordionItemCommand extends Command { + + /** + * The currently-selected accordion item. + */ + protected accordionItem?: Element | null; + + /** + * @inheritdoc + */ + public override refresh() { + const selection = this.editor.model.document.selection; + this.accordionItem = getSelectedAccordionItemModelElement(selection); + // Disables the remove command if the accordion has only one item. + this.isEnabled = this.accordionItem ? 1 < Array.from(this.accordionItem!.parent!.getChildren()).length : false; + } + + /** + * @inheritdoc + */ + public override execute() { + const editor = this.editor; + const { commands, model } = editor + const accordionItem = this.accordionItem!; + model.change(writer => { + if (commands.get('bootstrapAccordionFirstItemOpen')?.value) { + const accordion = accordionItem.parent as Element; + // The accordion item being removed is the first item, and the "open + // first item" setting is on. Opens the item below it as it will now be + // the first item. + if (accordion.getChildIndex(accordionItem) === 0) { + setAccordionItemIsOpen(accordion.getChild(1) as Element, writer, true); + } + } + writer.remove(accordionItem); + }); + } + +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/index.ts b/ckeditor5_plugins/bootstrapAccordion/src/index.ts new file mode 100644 index 0000000..9b3ba83 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/index.ts @@ -0,0 +1,19 @@ +/** + * @file The build process always expects an index.js file. Anything exported + * here will be recognized by CKEditor 5 as an available plugin. Multiple + * plugins can be exported in this one file. + * + * I.e. this file's purpose is to make plugin(s) discoverable. + */ + +import BootstrapAccordion from './bootstrapaccordion'; +import BootstrapAccordionClipboardPipeline from './integration/bootstrapaccordionclipboardpipeline'; +import BootstrapAccordionGeneralHtmlSupport from './integration/bootstrapaccordiongeneralhtmlsupport'; + +// Only these plugins will be built when running `b bootstrapAccordion` or +// `w bootstrapAccordion`. +export default { + BootstrapAccordion, + BootstrapAccordionClipboardPipeline, + BootstrapAccordionGeneralHtmlSupport +}; diff --git a/ckeditor5_plugins/bootstrapAccordion/src/integration/bootstrapaccordionclipboardpipeline.ts b/ckeditor5_plugins/bootstrapAccordion/src/integration/bootstrapaccordionclipboardpipeline.ts new file mode 100644 index 0000000..0c82541 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/integration/bootstrapaccordionclipboardpipeline.ts @@ -0,0 +1,42 @@ +import type { ClipboardInputTransformationEvent } from '@ckeditor/ckeditor5-clipboard'; +import type { PluginInterface } from '@ckeditor/ckeditor5-core/src/plugin'; +import { Plugin } from 'ckeditor5/src/core'; + +/** + * Integration with the external `ClipboardPipeline` plugin. Drops + * the `data-accordion-id` attribute in pasted accordions to prevent two + * accordions in the same document from having the same id. + */ +export default class BootstrapAccordionClipboardPipeline extends Plugin implements PluginInterface { + + /** + * The plugin's name in the PluginCollection. + */ + static get pluginName(): 'BootstrapAccordionClipboardPipeline' { + return 'BootstrapAccordionClipboardPipeline' as const; + } + + /** + * @inheritdoc + */ + init() { + const editor = this.editor; + const plugins = editor.plugins; + + if (!plugins.has('ClipboardPipeline')) { + // Nothing to integrate with. + return; + } + + plugins.get('ClipboardPipeline').on('inputTransformation', (_eventInfo, data) => { + let html = editor.data.htmlProcessor.toData(data.content); + if (!html.includes('data-accordion-id')) { + return; + } + // Strips the `data-accordion-id` attribute. + html = html.replace(/(<[^>]*)(data-accordion-id="[^"]*")/gimu, '$1'); + data.content = editor.data.htmlProcessor.toView(html); + }); + } + +} diff --git a/ckeditor5_plugins/bootstrapAccordion/src/integration/bootstrapaccordiongeneralhtmlsupport.ts b/ckeditor5_plugins/bootstrapAccordion/src/integration/bootstrapaccordiongeneralhtmlsupport.ts new file mode 100644 index 0000000..830b123 --- /dev/null +++ b/ckeditor5_plugins/bootstrapAccordion/src/integration/bootstrapaccordiongeneralhtmlsupport.ts @@ -0,0 +1,75 @@ +import { Plugin } from 'ckeditor5/src/core'; +import { setViewAttributes } from '@ckeditor/ckeditor5-html-support/src/utils'; +import type { PluginInterface } from '@ckeditor/ckeditor5-core/src/plugin'; +import type { DowncastAttributeEvent, Element as ModelElement, ViewElement, UpcastElementEvent } from 'ckeditor5/src/engine'; + +/** + * Integration with the external `GeneralHtmlSupport` plugin. Preserves allowed + * HTML attributes on the accordion. + */ +export default class BootstrapAccordionGeneralHtmlSupport extends Plugin implements PluginInterface { + + /** + * The plugin's name in the PluginCollection. + */ + static get pluginName(): 'BootstrapAccordionGeneralHtmlSupport' { + return 'BootstrapAccordionGeneralHtmlSupport' as const; + } + + /** + * @inheritdoc + */ + init() { + const editor = this.editor; + const plugins = editor.plugins; + + if (!plugins.has('GeneralHtmlSupport') || !plugins.has('DataFilter')) { + // Nothing to integrate with. + return; + } + + const { model, conversion } = editor; + const schema = model.schema; + const dataFilter = plugins.get('DataFilter'); + + schema.extend('bootstrapAccordion', { + allowAttributes: ['htmlAttributes'] + }); + + conversion.for('upcast').add(dispatcher => { + dispatcher.on('element:div', + (_evt, data, conversionApi) => { + const viewElement = data.viewItem; + if (!viewElement.hasClass('accordion')) { + return; + } + const preserveElementAttributes = (viewElement: ViewElement, attributeName: string) => { + const viewAttributes = dataFilter.processViewAttributes(viewElement, conversionApi); + if (viewAttributes) { + conversionApi.writer.setAttribute(attributeName, viewAttributes, data.modelRange!); + } + }; + preserveElementAttributes(viewElement, 'htmlAttributes'); + }, + { priority: 'low' } + ); + }); + + conversion.for('downcast').add(dispatcher => { + dispatcher.on>('attribute:htmlAttributes:bootstrapAccordion', + (evt, data, conversionApi) => { + if (!conversionApi.consumable.consume(data.item, evt.name)) { + return; + } + const modelElement = data.item; + const viewElement = conversionApi.mapper.toViewElement(modelElement); + if (viewElement?.is('element', 'div')) { + setViewAttributes(conversionApi.writer, data.attributeNewValue!, viewElement); + } + }, + { priority: 'low' } + ); + }); + } + +} diff --git a/css/bootstrap-accordion.admin.css b/css/bootstrap-accordion.admin.css new file mode 100644 index 0000000..2acd46d --- /dev/null +++ b/css/bootstrap-accordion.admin.css @@ -0,0 +1,3 @@ +.ckeditor5-toolbar-button-bootstrapAccordion { + background-image: url(../icons/bootstrap-accordion.svg); +} diff --git a/css/bootstrap-accordion.css b/css/bootstrap-accordion.css new file mode 100644 index 0000000..581a39f --- /dev/null +++ b/css/bootstrap-accordion.css @@ -0,0 +1,137 @@ +/* Bootstrap Accordion Styles */ +.accordion { + --bs-accordion-color: var(--bs-body-color); + --bs-accordion-bg: var(--bs-body-bg); + --bs-accordion-transition: color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease; + --bs-accordion-border-color: var(--bs-border-color); + --bs-accordion-border-width: 1px; + --bs-accordion-border-radius: 0.375rem; + --bs-accordion-inner-border-radius: calc(0.375rem - 1px); + --bs-accordion-btn-padding-x: 1.25rem; + --bs-accordion-btn-padding-y: 1rem; + --bs-accordion-btn-color: var(--bs-body-color); + --bs-accordion-btn-bg: var(--bs-accordion-bg); + --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + --bs-accordion-btn-icon-width: 1.25rem; + --bs-accordion-btn-icon-transform: rotate(-180deg); + --bs-accordion-btn-icon-transition: transform 0.2s ease-in-out; + --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23052c65'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + --bs-accordion-btn-focus-border-color: #86b7fe; + --bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); + --bs-accordion-body-padding-x: 1.25rem; + --bs-accordion-body-padding-y: 1rem; + --bs-accordion-active-color: var(--bs-primary-text-emphasis); + --bs-accordion-active-bg: var(--bs-primary-bg-subtle); +} + +.accordion-button { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x); + font-size: 1rem; + color: var(--bs-accordion-btn-color); + text-align: left; + background-color: var(--bs-accordion-btn-bg); + border: 0; + border-radius: 0; + overflow-anchor: none; + transition: var(--bs-accordion-transition); +} + +.accordion-button:not(.collapsed) { + color: var(--bs-accordion-active-color); + background-color: var(--bs-accordion-active-bg); + box-shadow: inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color); +} + +.accordion-button::after { + flex-shrink: 0; + width: var(--bs-accordion-btn-icon-width); + height: var(--bs-accordion-btn-icon-width); + margin-left: auto; + content: ""; + background-image: var(--bs-accordion-btn-icon); + background-repeat: no-repeat; + background-size: var(--bs-accordion-btn-icon-width); + transition: var(--bs-accordion-btn-icon-transition); +} + +.accordion-button:not(.collapsed)::after { + background-image: var(--bs-accordion-btn-active-icon); + transform: var(--bs-accordion-btn-icon-transform); +} + +.accordion-item { + color: var(--bs-accordion-color); + background-color: var(--bs-accordion-bg); + border: var(--bs-accordion-border-width) solid var(--bs-accordion-border-color); +} + +.accordion-item:first-of-type { + border-top-left-radius: var(--bs-accordion-border-radius); + border-top-right-radius: var(--bs-accordion-border-radius); +} + +.accordion-item:first-of-type .accordion-button { + border-top-left-radius: var(--bs-accordion-inner-border-radius); + border-top-right-radius: var(--bs-accordion-inner-border-radius); +} + +.accordion-item:last-of-type { + border-bottom-right-radius: var(--bs-accordion-border-radius); + border-bottom-left-radius: var(--bs-accordion-border-radius); +} + +.accordion-item:last-of-type .accordion-button.collapsed { + border-bottom-right-radius: var(--bs-accordion-inner-border-radius); + border-bottom-left-radius: var(--bs-accordion-inner-border-radius); +} + +.accordion-item:last-of-type .accordion-collapse { + border-bottom-right-radius: var(--bs-accordion-border-radius); + border-bottom-left-radius: var(--bs-accordion-border-radius); +} + +.accordion-body { + padding: var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x); +} + +.accordion-flush .accordion-collapse { + border-width: 0; +} + +.accordion-flush .accordion-item { + border-right: 0; + border-left: 0; + border-radius: 0; +} + +.accordion-flush .accordion-item:first-child { + border-top: 0; +} + +.accordion-flush .accordion-item:last-child { + border-bottom: 0; +} + +.accordion-flush .accordion-item .accordion-button { + border-radius: 0; +} + +.collapse:not(.show) { + display: none; +} + +.collapsing { + height: 0; + overflow: hidden; + transition: height 0.35s ease; +} + +@media (prefers-reduced-motion: reduce) { + .collapsing { + transition: none; + } +} \ No newline at end of file diff --git a/css/bootstrap-accordion.editor.css b/css/bootstrap-accordion.editor.css new file mode 100644 index 0000000..3de12de --- /dev/null +++ b/css/bootstrap-accordion.editor.css @@ -0,0 +1,62 @@ +.ck .ckeditor5-bootstrap-accordion__widget { + --ckeditor5-bootstrap-accordion-collapsed-icon: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAgMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTS45NDEgNC41MjNhLjc1Ljc1IDAgMSAxIDEuMDYtMS4wNmwzLjAwNiAzLjAwNSAzLjAwNS0zLjAwNWEuNzUuNzUgMCAxIDEgMS4wNiAxLjA2bC0zLjU0OSAzLjU1YS43NS43NSAwIDAgMS0xLjE2OC0uMTM2TC45NDEgNC41MjN6Ij48L3BhdGg+PC9zdmc+"); + + border: 1px solid #b3b3b3; +} + +.ck .ckeditor5-bootstrap-accordion-header { + padding: 0.5em; +} + +.ck .ckeditor5-bootstrap-accordion-button { + display: block; + padding: 0; + font-weight: bold; +} + +.ck .ckeditor5-bootstrap-accordion-button:not(.ck-placeholder)::before { + display: inline-block; + width: 0.8em; + height: 0.8em; + margin-right: 0.3em; + content: ""; + transition: rotate 0.5s; + background-color: currentColor; + -webkit-mask-image: var(--ckeditor5-bootstrap-accordion-collapsed-icon); + -moz-mask-image: var(--ckeditor5-bootstrap-accordion-collapsed-icon); + mask-image: var(--ckeditor5-bootstrap-accordion-collapsed-icon); +} + +.ck + .ckeditor5-bootstrap-accordion-button:not( + .ck-placeholder, + .collapsed + )::before { + rotate: 180deg; +} + +.ck .ckeditor5-bootstrap-accordion-body { + overflow: auto; + padding: 0.5em; +} + +.ck .ck-editor__nested-editable.ckeditor5-bootstrap-accordion-button:focus, +.ck + .ck-editor__nested-editable.ckeditor5-bootstrap-accordion-button.ck-editor__nested-editable_focused, +.ck .ck-editor__nested-editable.ckeditor5-bootstrap-accordion-body:focus, +.ck + .ck-editor__nested-editable.ckeditor5-bootstrap-accordion-body.ck-editor__nested-editable_focused { + background-color: transparent; +} + +.ck .ckeditor5-bootstrap-accordion-item:not(:first-child) { + border-top: 1px solid #b3b3b3; +} + +.ck .ckeditor5-bootstrap-accordion-item:hover { + background-color: rgb(108, 181, 249, 0.1); +} + +.ck .ckeditor5-bootstrap-accordion-item:focus-within { + background-color: rgb(13, 101, 255, 0.1); +} diff --git a/icons/bootstrap-accordion-item.svg b/icons/bootstrap-accordion-item.svg new file mode 100644 index 0000000..6fba65d --- /dev/null +++ b/icons/bootstrap-accordion-item.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/icons/bootstrap-accordion-open-collapse.svg b/icons/bootstrap-accordion-open-collapse.svg new file mode 100644 index 0000000..1e1bb9a --- /dev/null +++ b/icons/bootstrap-accordion-open-collapse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/icons/bootstrap-accordion.svg b/icons/bootstrap-accordion.svg new file mode 100644 index 0000000..1e87435 --- /dev/null +++ b/icons/bootstrap-accordion.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/build/bootstrapAccordion.js b/js/build/bootstrapAccordion.js new file mode 100644 index 0000000..08d452e --- /dev/null +++ b/js/build/bootstrapAccordion.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.CKEditor5=e():(t.CKEditor5=t.CKEditor5||{},t.CKEditor5.bootstrapAccordion=e())}(self,(()=>(()=>{var t=[(t,e,o)=>{t.exports=o(2)("./src/core.js")},(t,e,o)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.ckMajorVersion=void 0,e.isAccordionWidget=r,e.getSelectedAccordionWidget=function(t){var e;const o=null===(e=t.focus)||void 0===e?void 0:e.getAncestors().reverse().find((t=>t.is("element")&&r(t)));return(null==o?void 0:o.is("element"))?o:null},e.getSelectedAccordionItemModelElement=function(t){var e;return null===(e=t.getFirstPosition())||void 0===e?void 0:e.findAncestor("bootstrapAccordionItem")},e.getSelectedAccordionModelElement=function(t){var e;return null===(e=t.getFirstPosition())||void 0===e?void 0:e.findAncestor("bootstrapAccordion")},e.createAccordionItem=function(t,e=!1){const o=t.createElement("bootstrapAccordionItem"),n=t.createElement("bootstrapAccordionHeader"),r=t.createElement("bootstrapAccordionButton",{bootstrapAccordionButtonCollapsed:e?"false":"true"}),c=t.createElement("bootstrapAccordionCollapse",{bootstrapAccordionCollapseShow:e?"true":"false"}),i=t.createElement("bootstrapAccordionBody");return t.append(n,o),t.append(r,n),t.append(c,o),t.append(i,c),t.appendElement("paragraph",i),{accordionItem:o,accordionHeader:n,accordionButton:r,accordionCollapse:c,accordionBody:i}},e.isAccordionItemOpen=function(t){let e=!1;return[...t.getChildren()].forEach((t=>{t.is("element","bootstrapAccordionCollapse")&&(e="true"===t.getAttribute("bootstrapAccordionCollapseShow"))})),e},e.setAccordionItemIsOpen=function(t,e,o){[...t.getChildren()].forEach((t=>{t.is("element","bootstrapAccordionHeader")?[...t.getChildren()].forEach((t=>{t.is("element","bootstrapAccordionButton")&&e.setAttribute("bootstrapAccordionButtonCollapsed",o?"false":"true",t)})):t.is("element","bootstrapAccordionCollapse")&&e.setAttribute("bootstrapAccordionCollapseShow",o?"true":"false",t)}))};const n=o(3);function r(t){return t.hasClass("ckeditor5-bootstrap-accordion__widget")}e.ckMajorVersion=parseInt(n.version.split(".")[0])},t=>{"use strict";t.exports=CKEditor5.dll},(t,e,o)=>{t.exports=o(2)("./src/utils.js")},function(t,e,o){"use strict";var n=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});const r=o(0),c=o(3),i=o(6),s=o(10),a=o(11),l=n(o(14)),u=n(o(15)),d=n(o(16)),p=n(o(17)),f=n(o(18)),b=n(o(19)),m=n(o(20));class h extends r.Plugin{static get pluginName(){return"BootstrapAccordionEditing"}static get requires(){return[i.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){const t=this.editor.model.schema;t.register("bootstrapAccordion",{isObject:!0,allowWhere:"$block",allowAttributes:["bootstrapAccordionId","bootstrapAccordionStyle","bootstrapAccordionItemsStayOpen"],allowChildren:["bootstrapAccordionItem"]}),t.register("bootstrapAccordionItem",{allowIn:"bootstrapAccordion",allowChildren:["bootstrapAccordionHeader","bootstrapAccordionBody"]}),t.register("bootstrapAccordionHeader",{allowIn:"bootstrapAccordionItem",allowChildren:["bootstrapAccordionButton"]}),t.register("bootstrapAccordionButton",{isLimit:!0,allowContentOf:"$block",allowAttributes:["bootstrapAccordionButtonCollapsed"],allowIn:"bootstrapAccordionHeader"}),t.register("bootstrapAccordionCollapse",{allowIn:"bootstrapAccordionItem",allowAttributes:["bootstrapAccordionCollapseShow"]}),t.register("bootstrapAccordionBody",{isLimit:!0,allowContentOf:"$root",allowIn:"bootstrapAccordionCollapse"}),t.addAttributeCheck(((t,e)=>{if(["linkHref","anchorId"].includes(e)&&[...t.getNames()].includes("bootstrapAccordionButton"))return!1}))}_defineConverters(){const{conversion:t,editing:e,t:o}=this.editor;t.attributeToAttribute({model:"bootstrapAccordionId",view:"data-accordion-id"}),t.attributeToAttribute(v("bootstrapAccordionStyle",s.styleOptions)),t.attributeToAttribute(v("bootstrapAccordionItemsStayOpen",s.itemsStayOpenOptions)),t.attributeToAttribute(v("bootstrapAccordionButtonCollapsed",s.buttonCollapsedOptions)),t.attributeToAttribute(v("bootstrapAccordionCollapseShow",s.collapseShowOptions)),t.for("upcast").add((t=>{t.on("element:div",((t,e,o)=>{const n=e.viewItem;if(o.consumable.consume(n,{name:!0,classes:"accordion"})){const t=o.writer.createElement("bootstrapAccordion",{bootstrapAccordionId:n.getAttribute("data-accordion-id")||n.getAttribute("id")||(0,c.uid)()});o.safeInsert(t,e.modelCursor)&&(o.convertChildren(n,t),o.updateConversionResult(t,e))}}))})),t.for("editingDowncast").elementToElement({model:"bootstrapAccordion",view:(t,{writer:e})=>(0,i.toWidget)(e.createContainerElement("div",{class:"ckeditor5-bootstrap-accordion__widget"}),e,{label:o("Accordion widget"),hasSelectionHandle:!0})}),t.for("dataDowncast").elementToElement({model:"bootstrapAccordion",view:{name:"div",classes:"accordion"}}),t.for("upcast").elementToElement({model:"bootstrapAccordionItem",view:{name:"div",classes:"accordion-item"}}),t.for("editingDowncast").elementToElement({model:"bootstrapAccordionItem",view:{name:"div",classes:"ckeditor5-bootstrap-accordion-item"}}),t.for("dataDowncast").elementToElement({model:"bootstrapAccordionItem",view:{name:"div",classes:"accordion-item"}}),t.for("upcast").add((t=>{t.on("element",((t,e,o)=>{if(o.consumable.consume(e.viewItem,{name:!0,classes:"accordion-header"})){const t=o.writer.createElement("bootstrapAccordionHeader");o.safeInsert(t,e.modelCursor)&&(o.convertChildren(e.viewItem,t),o.updateConversionResult(t,e))}}))})),t.for("editingDowncast").elementToElement({model:"bootstrapAccordionHeader",view:{name:"div",classes:"ckeditor5-bootstrap-accordion-header"}}),t.for("dataDowncast").elementToElement({model:"bootstrapAccordionHeader",view:{name:"div",classes:"accordion-header"}}),t.for("upcast").add((t=>{t.on("element:a",((t,e,o)=>{if(o.consumable.consume(e.viewItem,{name:!0,classes:"accordion-button",attributes:["href"]})||o.consumable.consume(e.viewItem,{name:!0,classes:"accordion-button"})){const t=o.writer.createElement("bootstrapAccordionButton");o.safeInsert(t,e.modelCursor)&&(o.convertChildren(e.viewItem,t),o.updateConversionResult(t,e))}})),t.on("element:button",((t,e,o)=>{if(o.consumable.consume(e.viewItem,{name:!0,classes:"accordion-button"})){const t=o.writer.createElement("bootstrapAccordionButton");o.safeInsert(t,e.modelCursor)||(o.convertChildren(e.viewItem,t),o.updateConversionResult(t,e))}}))})),t.for("editingDowncast").elementToElement({model:"bootstrapAccordionButton",view:(t,{writer:n})=>{const r=n.createEditableElement("a",{class:"ckeditor5-bootstrap-accordion-button",href:"#"});r.placeholder=o("Accordion item"),(0,a.engineEnablePlaceholder)({view:e.view,element:r,keepOnFocus:!0});return(0,i.toWidgetEditable)(r,n,{label:o("Accordion item header")})}}),t.for("dataDowncast").elementToElement({model:"bootstrapAccordionButton",view:{name:"a",classes:"accordion-button",attributes:{href:"#"}}}),t.for("upcast").elementToElement({model:"bootstrapAccordionCollapse",view:{name:"div",classes:"accordion-collapse"}}),t.for("editingDowncast").elementToElement({model:"bootstrapAccordionCollapse",view:{name:"div",classes:"ckeditor5-bootstrap-accordion-collapse"}}),t.for("dataDowncast").elementToElement({model:"bootstrapAccordionCollapse",view:{name:"div",classes:["accordion-collapse","collapse"]}}),t.for("upcast").elementToElement({model:"bootstrapAccordionBody",view:{name:"div",classes:"accordion-body"}}),t.for("editingDowncast").elementToElement({model:"bootstrapAccordionBody",view:(t,{writer:n})=>{const r=n.createEditableElement("div",{class:"ckeditor5-bootstrap-accordion-body"});return r.placeholder=o("Accordion item body"),(0,a.engineEnablePlaceholder)({view:e.view,element:r,isDirectHost:!1,keepOnFocus:!0}),(0,i.toWidgetEditable)(r,n,{label:o("Accordion item body")})}}),t.for("dataDowncast").elementToElement({model:"bootstrapAccordionBody",view:{name:"div",classes:"accordion-body"}})}_defineCommands(){const t=this.editor,e=t.commands;e.add("insertBootstrapAccordion",new p.default(t)),e.add("insertBootstrapAccordionItem",new f.default(t)),e.add("removeBootstrapAccordionItem",new b.default(t)),e.add("bootstrapAccordionFirstItemOpen",new u.default(t)),e.add("bootstrapAccordionItemsStayOpen",new m.default(t,"bootstrapAccordionItemsStayOpen",s.itemsStayOpenDefault)),e.add("bootstrapAccordionOpenAll",new d.default(t)),e.add("bootstrapAccordionCollapseAll",new l.default(t))}}function v(t,e){const o={},n=[];for(const[t,r]of Object.entries(e))r.className&&(n.push(t),o[t]={key:"class",value:r.className});return{model:{key:t,values:n},view:o}}e.default=h},function(t,e,o){"use strict";var n=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});const r=o(0),c=n(o(4));class i extends r.Plugin{static get pluginName(){return"BootstrapAccordionEvents"}static get requires(){return[c.default]}init(){const t=this.editor.commands,e=t.get("bootstrapAccordionFirstItemOpen"),o=t.get("bootstrapAccordionItemsStayOpen"),n=t.get("bootstrapAccordionOpenAll"),r=t.get("bootstrapAccordionCollapseAll"),c=t.get("insertBootstrapAccordionItem"),i=t.get("removeBootstrapAccordionItem");this.on("accordion",((t,c)=>{if("toggleFirstItemOpen"===c)e.execute({value:!e.value});else if("toggleItemsStayOpen"===c){const t=o.value;o.execute({value:"false"===t?"true":"false"}),"true"===t&&r.execute({omitFirst:!0})}else"openAll"===c?n.execute():"collapseAll"===c&&r.execute()})),this.on("accordionItem",((t,e)=>{"insertAbove"===e?c.execute({value:"before"}):"insertBelow"===e?c.execute({value:"after"}):"remove"===e&&i.execute()}))}}e.default=i},(t,e,o)=>{t.exports=o(2)("./src/widget.js")},function(t,e,o){"use strict";var n=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});const r=n(o(8)),c=n(o(25)),i=n(o(26));e.default={BootstrapAccordion:r.default,BootstrapAccordionClipboardPipeline:c.default,BootstrapAccordionGeneralHtmlSupport:i.default}},function(t,e,o){"use strict";var n=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});const r=o(0),c=n(o(4)),i=n(o(5)),s=n(o(21)),a=n(o(9));class l extends r.Plugin{static get pluginName(){return"BootstrapAccordion"}static get requires(){return[c.default,i.default,s.default,a.default]}}e.default=l},function(t,e,o){"use strict";var n=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});const r=o(0),c=o(12),i=o(3),s=o(6),a=n(o(5)),l=o(11),u=o(1),d=n(o(22)),p=n(o(23)),f=n(o(24));class b extends r.Plugin{static get pluginName(){return"BootstrapAccordionUI"}static get requires(){return[a.default,s.WidgetToolbarRepository]}init(){const{commands:t,plugins:e,ui:o}=this.editor,n=o.componentFactory,r=e.get("BootstrapAccordionEvents");n.add("bootstrapAccordion",(e=>function(t,e,o,n,r){const i=n.editor,s=function(t,e,o,n,r){const i=new c.ButtonView(t);return i.set({label:"string"==typeof r?r:e,icon:o,tooltip:!!o&&e,withText:r||!o,class:n}),i}(t,e,o);return s.tooltip=!!o,s.bind("isEnabled").to(n),s.on("execute",(()=>{n.execute({value:r}),i.editing.view.focus()})),s}(e,e.t("Insert accordion"),d.default,t.get("insertBootstrapAccordion")))),n.add("bootstrapAccordionItem",(t=>this._buildAccordionItemToolbarDropdown(t,r))),n.add("bootstrapAccordionOpenCollapse",(t=>this._buildAccordionOpenCollapseToolbarDropdown(t,r)))}afterInit(){const{config:t,plugins:e}=this.editor;e.get(s.WidgetToolbarRepository).register("bootstrapAccordion",{items:t.get("bootstrapAccordion.toolbarItems"),getRelatedElement:u.getSelectedAccordionWidget})}_buildAccordionItemToolbarDropdown(t,e){const o=this.editor.commands,n=o.get("insertBootstrapAccordionItem"),r=o.get("removeBootstrapAccordionItem"),s=(0,c.createDropdown)(t),a=s.buttonView,l=new i.Collection,u=t.t;return l.add({type:"button",model:m(n,null,"insertAbove",u("Insert item above"))}),l.add({type:"button",model:m(n,null,"insertBelow",u("Insert item below"))}),l.add({type:"button",model:m(r,null,"remove",u("Delete item"))}),(0,c.addListToDropdown)(s,l),s.on("execute",(t=>e.fire("accordionItem",t.source.name))),a.set({label:u("Accordion item"),icon:p.default,tooltip:u("Accordion item"),class:"ck-dropdown__button_label-width_auto",withText:!1}),s}_buildAccordionOpenCollapseToolbarDropdown(t,e){const o=this.editor.commands,n=(0,c.createDropdown)(t),r=n.buttonView,s=new i.Collection,a=t.t;return s.add({type:"switchbutton",model:m(o.get("bootstrapAccordionFirstItemOpen"),!0,"toggleFirstItemOpen",a("Open first item"))}),s.add({type:"switchbutton",model:m(o.get("bootstrapAccordionItemsStayOpen"),"true","toggleItemsStayOpen",a("Allow opening multiple items"))}),s.add({type:"separator"}),s.add({type:"button",model:m(o.get("bootstrapAccordionOpenAll"),"true","openAll",a("Open all items"))}),s.add({type:"button",model:m(o.get("bootstrapAccordionCollapseAll"),"true","collapseAll",a("Collapse all items"))}),(0,c.addListToDropdown)(n,s),n.on("execute",(t=>e.fire("accordion",t.source.name))),r.set({label:a("Accordion open / collapse"),icon:f.default,tooltip:a("Accordion open / collapse"),class:"ck-dropdown__button_label-width_auto",withText:!1}),n}}function m(t,e,o,n,r,c,i){const s=new l.UiViewModel({name:o,label:"string"==typeof i?i:n,icon:r,tooltip:!!r&&n,withText:i||!r,class:c});return s.bind("isEnabled").to(t),null!==e&&s.bind("isOn").to(t,"value",(t=>t===e)),s}e.default=b},(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.collapseShowOptions=e.buttonCollapsedOptions=e.itemsStayOpenDefault=e.itemsStayOpenOptions=e.styleDefault=e.styleOptions=void 0,e.styleOptions={regular:{label:"Regular"},flush:{label:"Flush",className:"accordion-flush"}},e.styleDefault="regular",e.itemsStayOpenOptions={true:{className:"accordion-items-stay-open"},false:{}},e.itemsStayOpenDefault="false",e.buttonCollapsedOptions={true:{className:"collapsed"},false:{}},e.collapseShowOptions={true:{className:"show"},false:{}}},(t,e,o)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.UiViewModel=void 0,e.engineEnablePlaceholder=function(t){c.ckMajorVersion<39&&(t.text=t.element.placeholder);(0,n.enablePlaceholder)(t)};const n=o(13),r=o(12),c=o(1);e.UiViewModel=r.ViewModel},(t,e,o)=>{t.exports=o(2)("./src/ui.js")},(t,e,o)=>{t.exports=o(2)("./src/engine.js")},(t,e,o)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=o(0),r=o(1);class c extends n.Command{refresh(){this.accordionWidget=(0,r.getSelectedAccordionModelElement)(this.editor.model.document.selection),this.isEnabled=!!this.accordionWidget}execute(t={omitFirst:!1}){const e=this.accordionWidget.getChildren();t.omitFirst&&e.next(),this.editor.model.change((t=>[...e].forEach((e=>(0,r.setAccordionItemIsOpen)(e,t,!1)))))}}e.default=c},(t,e,o)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=o(0),r=o(1);class c extends n.Command{refresh(){const t=this.editor.model;this.accordionWidget=(0,r.getSelectedAccordionModelElement)(t.document.selection),this.isEnabled=!!this.accordionWidget,this.value=this.isEnabled&&(0,r.isAccordionItemOpen)(this.accordionWidget.getChild(0))}execute(t={value:!1}){this.editor.model.change((e=>(0,r.setAccordionItemIsOpen)(this.accordionWidget.getChild(0),e,t.value)))}}e.default=c},(t,e,o)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=o(0),r=o(1);class c extends n.Command{refresh(){const t=this.editor.model;this.accordionWidget=(0,r.getSelectedAccordionModelElement)(t.document.selection),this.isEnabled=!!this.accordionWidget&&"true"===this.accordionWidget.getAttribute("bootstrapAccordionItemsStayOpen")}execute(){this.editor.model.change((t=>[...this.accordionWidget.getChildren()].forEach((e=>(0,r.setAccordionItemIsOpen)(e,t,!0)))))}}e.default=c},(t,e,o)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=o(0),r=o(3),c=o(6),i=o(10),s=o(1);class a extends n.Command{refresh(){const t=this.editor.model,{document:e,schema:o}=t;this.isEnabled=o.checkChild(function(t,e){const o=(0,c.findOptimalInsertionRange)(t,e).start.parent;return o.isEmpty&&!o.is("element","$root")?o.parent:o}(e.selection,t),"bootstrapAccordion")}execute(){const{editing:t,model:e}=this.editor;e.change((o=>{const n=o.createElement("bootstrapAccordion",{bootstrapAccordionId:(0,r.uid)(),bootstrapAccordionStyle:i.styleDefault,bootstrapAccordionItemsStayOpen:i.itemsStayOpenDefault}),{accordionItem:c}=(0,s.createAccordionItem)(o);o.append(c,n),e.insertContent(n),t.view.focus(),o.setSelection(n,"on")}))}}e.default=a},(t,e,o)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=o(0),r=o(1);class c extends n.Command{refresh(){const t=this.editor.model.document.selection;this.accordionItem=(0,r.getSelectedAccordionItemModelElement)(t),this.isEnabled=!!this.accordionItem}execute(t){const{commands:e,model:o}=this.editor,n=this.accordionItem,c=t.value;o.change((t=>{var o,i;let s="true"===(null===(o=e.get("bootstrapAccordionItemsStayOpen"))||void 0===o?void 0:o.value)&&(0,r.isAccordionItemOpen)(n);const a=n.parent;if(0===a.getChildIndex(n)){const o=a.getChild(1),l=!!o&&(0,r.isAccordionItemOpen)(o);"before"===c?(s=!!(null===(i=e.get("bootstrapAccordionFirstItemOpen"))||void 0===i?void 0:i.value),(0,r.setAccordionItemIsOpen)(n,t,l)):s=l}const l=(0,r.createAccordionItem)(t,s).accordionItem;t.insert(l,n,c)}))}}e.default=c},(t,e,o)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=o(0),r=o(1);class c extends n.Command{refresh(){const t=this.editor.model.document.selection;this.accordionItem=(0,r.getSelectedAccordionItemModelElement)(t),this.isEnabled=!!this.accordionItem&&1{var o;if(null===(o=e.get("bootstrapAccordionFirstItemOpen"))||void 0===o?void 0:o.value){const e=n.parent;0===e.getChildIndex(n)&&(0,r.setAccordionItemIsOpen)(e.getChild(1),t,!0)}t.remove(n)}))}}e.default=c},(t,e,o)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=o(0),r=o(1);class c extends n.Command{constructor(t,e,o){super(t),this.attributeName=e,this.defaultValue=o,this.value=o}refresh(){const t=this.editor.model,e=this.attributeName,o=this.defaultValue;this.accordionWidget=(0,r.getSelectedAccordionModelElement)(t.document.selection),this.isEnabled=!!this.accordionWidget,this.value=o,this.isEnabled&&this.accordionWidget.hasAttribute(e)&&(this.value=this.accordionWidget.getAttribute(e))}execute(t={value:this.defaultValue}){const e=this.editor.model,o=this.accordionWidget;e.change((e=>e.setAttribute(this.attributeName,t.value,o)))}}e.default=c},(t,e,o)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=o(0),r=o(1);class c extends n.Plugin{static get pluginName(){return"BootstrapAccordionKeyboard"}init(){const t=this.editor.editing.view.document;this.listenTo(t,"tab",((t,e)=>this._handleNavigation(t,e,!e.shiftKey)),{context:t=>t.is("element")&&(t.hasClass("ckeditor5-bootstrap-accordion-button")||t.hasClass("ckeditor5-bootstrap-accordion-body"))})}_handleNavigation(t,e,o){var n,c;const a=this.editor.model,l=a.document.selection,u=(null===(n=l.getFirstPosition())||void 0===n?void 0:n.findAncestor("bootstrapAccordionButton"))||(null===(c=l.getFirstPosition())||void 0===c?void 0:c.findAncestor("bootstrapAccordionBody"));if(!u)return;const d=function(t,e,o){const n=(0,r.getSelectedAccordionItemModelElement)(e);if(!n)return null;const c=n.parent;return o?s(c,n,t):i(c,n,t)}(u,l,o);d&&(e.preventDefault(),e.stopPropagation(),t.stop(),a.change((t=>{t.setSelection(t.createRangeIn(d))})))}}function i(t,e,o){if(!e)return null;const n=[...e.getChildren()],r=o?n.indexOf(o.parent)-1:n.length-1;return r>-1?n[r].getChild(0):i(t,t.getChild(t.getChildIndex(e)-1),null)}function s(t,e,o){if(!e)return null;const n=[...e.getChildren()],r=o?n.indexOf(o.parent)+1:0;return r{"use strict";o.r(e),o.d(e,{default:()=>n});const n=''},(t,e,o)=>{"use strict";o.r(e),o.d(e,{default:()=>n});const n=''},(t,e,o)=>{"use strict";o.r(e),o.d(e,{default:()=>n});const n=''},(t,e,o)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=o(0);class r extends n.Plugin{static get pluginName(){return"BootstrapAccordionClipboardPipeline"}init(){const t=this.editor,e=t.plugins;e.has("ClipboardPipeline")&&e.get("ClipboardPipeline").on("inputTransformation",((e,o)=>{let n=t.data.htmlProcessor.toData(o.content);n.includes("data-accordion-id")&&(n=n.replace(/(<[^>]*)(data-accordion-id="[^"]*")/gimu,"$1"),o.content=t.data.htmlProcessor.toView(n))}))}}e.default=r},(t,e,o)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=o(0),r=o(27);class c extends n.Plugin{static get pluginName(){return"BootstrapAccordionGeneralHtmlSupport"}init(){const t=this.editor,e=t.plugins;if(!e.has("GeneralHtmlSupport")||!e.has("DataFilter"))return;const{model:o,conversion:n}=t,c=o.schema,i=e.get("DataFilter");c.extend("bootstrapAccordion",{allowAttributes:["htmlAttributes"]}),n.for("upcast").add((t=>{t.on("element:div",((t,e,o)=>{const n=e.viewItem;if(!n.hasClass("accordion"))return;((t,n)=>{const r=i.processViewAttributes(t,o);r&&o.writer.setAttribute(n,r,e.modelRange)})(n,"htmlAttributes")}),{priority:"low"})})),n.for("downcast").add((t=>{t.on("attribute:htmlAttributes:bootstrapAccordion",((t,e,o)=>{if(!o.consumable.consume(e.item,t.name))return;const n=e.item,c=o.mapper.toViewElement(n);(null==c?void 0:c.is("element","div"))&&(0,r.setViewAttributes)(o.writer,e.attributeNewValue,c)}),{priority:"low"})}))}}e.default=c},(t,e,o)=>{"use strict";o.r(e),o.d(e,{getHtmlAttributeName:()=>Tn,mergeViewElementAttributes:()=>Pn,modifyGhsAttribute:()=>Bn,removeViewAttributes:()=>Sn,setViewAttributes:()=>En,toPascalCase:()=>Mn,updateViewAttributes:()=>Cn});const n=function(){this.__data__=[],this.size=0};const r=function(t,e){return t===e||t!=t&&e!=e};const c=function(t,e){for(var o=t.length;o--;)if(r(t[o][0],e))return o;return-1};var i=Array.prototype.splice;const s=function(t){var e=this.__data__,o=c(e,t);return!(o<0)&&(o==e.length-1?e.pop():i.call(e,o,1),--this.size,!0)};const a=function(t){var e=this.__data__,o=c(e,t);return o<0?void 0:e[o][1]};const l=function(t){return c(this.__data__,t)>-1};const u=function(t,e){var o=this.__data__,n=c(o,t);return n<0?(++this.size,o.push([t,e])):o[n][1]=e,this};function d(t){var e=-1,o=null==t?0:t.length;for(this.clear();++e-1&&t%1==0&&t-1&&t%1==0&&t<=9007199254740991};var Nt={};Nt["[object Float32Array]"]=Nt["[object Float64Array]"]=Nt["[object Int8Array]"]=Nt["[object Int16Array]"]=Nt["[object Int32Array]"]=Nt["[object Uint8Array]"]=Nt["[object Uint8ClampedArray]"]=Nt["[object Uint16Array]"]=Nt["[object Uint32Array]"]=!0,Nt["[object Arguments]"]=Nt["[object Array]"]=Nt["[object ArrayBuffer]"]=Nt["[object Boolean]"]=Nt["[object DataView]"]=Nt["[object Date]"]=Nt["[object Error]"]=Nt["[object Function]"]=Nt["[object Map]"]=Nt["[object Number]"]=Nt["[object Object]"]=Nt["[object RegExp]"]=Nt["[object Set]"]=Nt["[object String]"]=Nt["[object WeakMap]"]=!1;const Wt=function(t){return jt(t)&&kt(t.length)&&!!Nt[S(t)]};const Ut=function(t){return function(e){return t(e)}};var Vt="object"==typeof exports&&exports&&!exports.nodeType&&exports,Rt=Vt&&"object"==typeof module&&module&&!module.nodeType&&module,Ht=Rt&&Rt.exports===Vt&&v.process;const $t=function(){try{var t=Rt&&Rt.require&&Rt.require("util").types;return t||Ht&&Ht.binding&&Ht.binding("util")}catch(t){}}();var Lt=$t&&$t.isTypedArray;const Gt=Lt?Ut(Lt):Wt;var Zt=Object.prototype.hasOwnProperty;const Kt=function(t,e){var o=St(t),n=!o&&Et(t),r=!o&&!n&&Dt(t),c=!o&&!n&&!r&&Gt(t),i=o||n||r||c,s=i?_t(t.length,String):[],a=s.length;for(var l in t)!e&&!Zt.call(t,l)||i&&("length"==l||r&&("offset"==l||"parent"==l)||c&&("buffer"==l||"byteLength"==l||"byteOffset"==l)||Ft(l,a))||s.push(l);return s};var qt=Object.prototype;const Yt=function(t){var e=t&&t.constructor;return t===("function"==typeof e&&e.prototype||qt)};const Jt=function(t,e){return function(o){return t(e(o))}};const Qt=Jt(Object.keys,Object);var Xt=Object.prototype.hasOwnProperty;const te=function(t){if(!Yt(t))return Qt(t);var e=[];for(var o in Object(t))Xt.call(t,o)&&"constructor"!=o&&e.push(o);return e};const ee=function(t){return null!=t&&kt(t.length)&&!B(t)};const oe=function(t){return ee(t)?Kt(t):te(t)};const ne=function(t,e){return t&&wt(e,oe(e),t)};const re=function(t){var e=[];if(null!=t)for(var o in Object(t))e.push(o);return e};var ce=Object.prototype.hasOwnProperty;const ie=function(t){if(!P(t))return re(t);var e=Yt(t),o=[];for(var n in t)("constructor"!=n||!e&&ce.call(t,n))&&o.push(n);return o};const se=function(t){return ee(t)?Kt(t,!0):ie(t)};const ae=function(t,e){return t&&wt(e,se(e),t)};var le="object"==typeof exports&&exports&&!exports.nodeType&&exports,ue=le&&"object"==typeof module&&module&&!module.nodeType&&module,de=ue&&ue.exports===le?A.Buffer:void 0,pe=de?de.allocUnsafe:void 0;const fe=function(t,e){if(e)return t.slice();var o=t.length,n=pe?pe(o):new t.constructor(o);return t.copy(n),n};const be=function(t,e){var o=-1,n=t.length;for(e||(e=Array(n));++or?0:r+e),(o=o>r?r:o)<0&&(o+=r),r=e>o?0:o-e>>>0,e>>>=0;for(var c=Array(r);++n=n?t:cn(t,e,o)};var an=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]");const ln=function(t){return an.test(t)};const un=function(t){return t.split("")};var dn="\\ud800-\\udfff",pn="["+dn+"]",fn="[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]",bn="\\ud83c[\\udffb-\\udfff]",mn="[^"+dn+"]",hn="(?:\\ud83c[\\udde6-\\uddff]){2}",vn="[\\ud800-\\udbff][\\udc00-\\udfff]",gn="(?:"+fn+"|"+bn+")"+"?",An="[\\ufe0e\\ufe0f]?",yn=An+gn+("(?:\\u200d(?:"+[mn,hn,vn].join("|")+")"+An+gn+")*"),wn="(?:"+[mn+fn+"?",fn,hn,vn,pn].join("|")+")",_n=RegExp(bn+"(?="+bn+")|"+wn+yn,"g");const jn=function(t){return t.match(_n)||[]};const On=function(t){return ln(t)?jn(t):un(t)};const xn=function(t){return function(e){e=xo(e);var o=ln(e)?On(e):void 0,n=o?o[0]:e.charAt(0),r=o?sn(o,1).join(""):e.slice(1);return n[t]()+r}}("toUpperCase");const In=rn((function(t,e,o){return t+(o?" ":"")+xn(e)}));function Cn(t,e,o,n){e&&Sn(t,e,n),o&&En(t,o,n)}function En(t,e,o){if(e.attributes)for(const[n,r]of Object.entries(e.attributes))t.setAttribute(n,r,o);e.styles&&t.setStyle(e.styles,o),e.classes&&t.addClass(e.classes,o)}function Sn(t,e,o){if(e.attributes)for(const[n]of Object.entries(e.attributes))t.removeAttribute(n,o);if(e.styles)for(const n of Object.keys(e.styles))t.removeStyle(n,o);e.classes&&t.removeClass(e.classes,o)}function Pn(t,e){const o=vo(t);let n="attributes";for(n in e)o[n]="classes"==n?Array.from(new Set([...t[n]||[],...e[n]])):{...t[n],...e[n]};return o}function Bn(t,e,o,n,r){const c=e.getAttribute(o),i={};for(const t of["attributes","styles","classes"]){if(t!=n){c&&c[t]&&(i[t]=c[t]);continue}if("classes"==n){const e=new Set(c&&c.classes||[]);r(e),e.size&&(i[t]=Array.from(e));continue}const e=new Map(Object.entries(c&&c[t]||{}));r(e),e.size&&(i[t]=Object.fromEntries(e))}Object.keys(i).length?e.is("documentSelection")?t.setSelectionAttribute(o,i):t.setAttribute(o,i,e):c&&(e.is("documentSelection")?t.removeSelectionAttribute(o):t.removeAttribute(o,e))}function Mn(t){return In(t).replace(/ /g,"")}function Tn(t){return`html${Mn(t)}Attributes`}}],e={};function o(n){var r=e[n];if(void 0!==r)return r.exports;var c=e[n]={exports:{}};return t[n].call(c.exports,c,c.exports,o),c.exports}o.d=(t,e)=>{for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),o.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var n=o(7);return n=n.default})())); \ No newline at end of file diff --git a/js/build/box.js b/js/build/box.js index f8dea69..23f7a22 100644 --- a/js/build/box.js +++ b/js/build/box.js @@ -1 +1 @@ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.CKEditor5=e():(t.CKEditor5=t.CKEditor5||{},t.CKEditor5.box=e())}(self,(()=>(()=>{var t=[(t,e,n)=>{t.exports=n(1)("./src/core.js")},t=>{"use strict";t.exports=CKEditor5.dll},(t,e,n)=>{t.exports=n(1)("./src/widget.js")},,(t,e,n)=>{t.exports=n(1)("./src/engine.js")},(t,e,n)=>{t.exports=n(1)("./src/ui.js")},(t,e,n)=>{"use strict";const o=n(0),r=n(7);class c extends o.Plugin{static get pluginName(){return"BoxGeneralHtmlSupport"}init(){const{editor:t}=this,{plugins:e}=t;if(!e.has("GeneralHtmlSupport")||!e.has("DataFilter"))return;const{model:n,conversion:o}=t,{schema:c}=n,i=e.get("DataFilter");c.extend("box",{allowAttributes:["htmlAttributes"]}),o.for("upcast").add((t=>{t.on("element:div",((t,e,n)=>{var o;const r=e.viewItem;if(!(null===(o=r.getAttribute("class"))||void 0===o?void 0:o.match(/ucb\-box(\-inner|\-title|\-content)?/)))return;((t,o)=>{const r=i.processViewAttributes(t,n);r&&n.writer.setAttribute(o,r,e.modelRange)})(r,"htmlAttributes")}),{priority:"low"})})),o.for("dataDowncast").add((t=>{t.on("attribute:htmlAttributes",((t,e,n)=>{const o=e.item;if(!["box","boxInner","boxTitle","boxContent"].includes(o.name)||!n.consumable.consume(o,t.name))return;const c=n.mapper.toViewElement(o);(null==c?void 0:c.is("element","div"))&&(0,r.setViewAttributes)(n.writer,e.attributeNewValue,c)}),{priority:"low"})}))}}e.Z=c},(t,e,n)=>{"use strict";n.r(e),n.d(e,{getHtmlAttributeName:()=>No,mergeViewElementAttributes:()=>Co,modifyGhsAttribute:()=>Bo,removeViewAttributes:()=>So,setViewAttributes:()=>zo,toPascalCase:()=>Io,updateViewAttributes:()=>To});const o=function(){this.__data__=[],this.size=0};const r=function(t,e){return t===e||t!=t&&e!=e};const c=function(t,e){for(var n=t.length;n--;)if(r(t[n][0],e))return n;return-1};var i=Array.prototype.splice;const s=function(t){var e=this.__data__,n=c(e,t);return!(n<0)&&(n==e.length-1?e.pop():i.call(e,n,1),--this.size,!0)};const a=function(t){var e=this.__data__,n=c(e,t);return n<0?void 0:e[n][1]};const u=function(t){return c(this.__data__,t)>-1};const l=function(t,e){var n=this.__data__,o=c(n,t);return o<0?(++this.size,n.push([t,e])):n[o][1]=e,this};function f(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e-1&&t%1==0&&t-1&&t%1==0&&t<=9007199254740991};var Ut={};Ut["[object Float32Array]"]=Ut["[object Float64Array]"]=Ut["[object Int8Array]"]=Ut["[object Int16Array]"]=Ut["[object Int32Array]"]=Ut["[object Uint8Array]"]=Ut["[object Uint8ClampedArray]"]=Ut["[object Uint16Array]"]=Ut["[object Uint32Array]"]=!0,Ut["[object Arguments]"]=Ut["[object Array]"]=Ut["[object ArrayBuffer]"]=Ut["[object Boolean]"]=Ut["[object DataView]"]=Ut["[object Date]"]=Ut["[object Error]"]=Ut["[object Function]"]=Ut["[object Map]"]=Ut["[object Number]"]=Ut["[object Object]"]=Ut["[object RegExp]"]=Ut["[object Set]"]=Ut["[object String]"]=Ut["[object WeakMap]"]=!1;const kt=function(t){return _t(t)&&Vt(t.length)&&!!Ut[S(t)]};const Rt=function(t){return function(e){return t(e)}};var Lt="object"==typeof exports&&exports&&!exports.nodeType&&exports,Mt=Lt&&"object"==typeof module&&module&&!module.nodeType&&module,Ht=Mt&&Mt.exports===Lt&&m.process;const Wt=function(){try{var t=Mt&&Mt.require&&Mt.require("util").types;return t||Ht&&Ht.binding&&Ht.binding("util")}catch(t){}}();var Zt=Wt&&Wt.isTypedArray;const $t=Zt?Rt(Zt):kt;var Gt=Object.prototype.hasOwnProperty;const Kt=function(t,e){var n=St(t),o=!n&&zt(t),r=!n&&!o&&Dt(t),c=!n&&!o&&!r&&$t(t),i=n||o||r||c,s=i?jt(t.length,String):[],a=s.length;for(var u in t)!e&&!Gt.call(t,u)||i&&("length"==u||r&&("offset"==u||"parent"==u)||c&&("buffer"==u||"byteLength"==u||"byteOffset"==u)||Ft(u,a))||s.push(u);return s};var qt=Object.prototype;const Yt=function(t){var e=t&&t.constructor;return t===("function"==typeof e&&e.prototype||qt)};const Jt=function(t,e){return function(n){return t(e(n))}};const Qt=Jt(Object.keys,Object);var Xt=Object.prototype.hasOwnProperty;const te=function(t){if(!Yt(t))return Qt(t);var e=[];for(var n in Object(t))Xt.call(t,n)&&"constructor"!=n&&e.push(n);return e};const ee=function(t){return null!=t&&Vt(t.length)&&!B(t)};const ne=function(t){return ee(t)?Kt(t):te(t)};const oe=function(t,e){return t&&wt(e,ne(e),t)};const re=function(t){var e=[];if(null!=t)for(var n in Object(t))e.push(n);return e};var ce=Object.prototype.hasOwnProperty;const ie=function(t){if(!C(t))return re(t);var e=Yt(t),n=[];for(var o in t)("constructor"!=o||!e&&ce.call(t,o))&&n.push(o);return n};const se=function(t){return ee(t)?Kt(t,!0):ie(t)};const ae=function(t,e){return t&&wt(e,se(e),t)};var ue="object"==typeof exports&&exports&&!exports.nodeType&&exports,le=ue&&"object"==typeof module&&module&&!module.nodeType&&module,fe=le&&le.exports===ue?x.Buffer:void 0,be=fe?fe.allocUnsafe:void 0;const de=function(t,e){if(e)return t.slice();var n=t.length,o=be?be(n):new t.constructor(n);return t.copy(o),o};const he=function(t,e){var n=-1,o=t.length;for(e||(e=Array(o));++nr?0:r+e),(n=n>r?r:n)<0&&(n+=r),r=e>n?0:n-e>>>0,e>>>=0;for(var c=Array(r);++o=o?t:co(t,e,n)};var so=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]");const ao=function(t){return so.test(t)};const uo=function(t){return t.split("")};var lo="\\ud800-\\udfff",fo="["+lo+"]",bo="[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]",ho="\\ud83c[\\udffb-\\udfff]",vo="[^"+lo+"]",po="(?:\\ud83c[\\udde6-\\uddff]){2}",mo="[\\ud800-\\udbff][\\udc00-\\udfff]",go="(?:"+bo+"|"+ho+")"+"?",xo="[\\ufe0e\\ufe0f]?",yo=xo+go+("(?:\\u200d(?:"+[vo,po,mo].join("|")+")"+xo+go+")*"),wo="(?:"+[vo+bo+"?",bo,po,mo,fo].join("|")+")",jo=RegExp(ho+"(?="+ho+")|"+wo+yo,"g");const _o=function(t){return t.match(jo)||[]};const Ao=function(t){return ao(t)?_o(t):uo(t)};const Oo=function(t){return function(e){e=On(e);var n=ao(e)?Ao(e):void 0,o=n?n[0]:e.charAt(0),r=n?io(n,1).join(""):e.slice(1);return o[t]()+r}}("toUpperCase");const Eo=ro((function(t,e,n){return t+(n?" ":"")+Oo(e)}));function To(t,e,n,o){e&&So(t,e,o),n&&zo(t,n,o)}function zo(t,e,n){if(e.attributes)for(const[o,r]of Object.entries(e.attributes))t.setAttribute(o,r,n);e.styles&&t.setStyle(e.styles,n),e.classes&&t.addClass(e.classes,n)}function So(t,e,n){if(e.attributes)for(const[o]of Object.entries(e.attributes))t.removeAttribute(o,n);if(e.styles)for(const o of Object.keys(e.styles))t.removeStyle(o,n);e.classes&&t.removeClass(e.classes,n)}function Co(t,e){const n=mn(t);let o="attributes";for(o in e)n[o]="classes"==o?Array.from(new Set([...t[o]||[],...e[o]])):{...t[o],...e[o]};return n}function Bo(t,e,n,o,r){const c=e.getAttribute(n),i={};for(const t of["attributes","styles","classes"]){if(t!=o){c&&c[t]&&(i[t]=c[t]);continue}if("classes"==o){const e=new Set(c&&c.classes||[]);r(e),e.size&&(i[t]=Array.from(e));continue}const e=new Map(Object.entries(c&&c[t]||{}));r(e),e.size&&(i[t]=Object.fromEntries(e))}Object.keys(i).length?e.is("documentSelection")?t.setSelectionAttribute(n,i):t.setAttribute(n,i,e):c&&(e.is("documentSelection")?t.removeSelectionAttribute(n):t.removeAttribute(n,e))}function Io(t){return Eo(t).replace(/ /g,"")}function No(t){return`html${Io(t)}Attributes`}}],e={};function n(o){var r=e[o];if(void 0!==r)return r.exports;var c=e[o]={exports:{}};return t[o](c,c.exports,n),c.exports}n.d=(t,e)=>{for(var o in e)n.o(e,o)&&!n.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),n.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var o={};return(()=>{"use strict";n.d(o,{default:()=>_});var t=n(0),e=n(2);const r={left:{label:"Align left",icon:'',className:"ucb-box-title-left"},center:{label:"Align center",icon:'',className:"ucb-box-title-center"},right:{label:"Align right",icon:'',className:"ucb-box-title-right"},hidden:{label:"Hide",icon:'',className:"ucb-box-title-hidden"}},c="left",i={left:{label:"Float left",icon:t.icons.objectLeft,className:"ucb-box-alignment-left"},none:{label:"Fill width",icon:t.icons.objectFullWidth,className:"ucb-box-alignment-none"},right:{label:"Float right",icon:t.icons.objectRight,className:"ucb-box-alignment-right"}},s="none",a={fill:{label:"Fill",icon:'',className:"ucb-box-style-fill"},outline:{label:"Outline",icon:'',className:"ucb-box-style-outline"},none:{label:"None",icon:'',className:"ucb-box-style-none"}},u="fill",l={black:{label:"Black",className:"ucb-box-theme-black"},darkgray:{label:"Dark Gray",className:"ucb-box-theme-darkgray"},lightgray:{label:"Light Gray",className:"ucb-box-theme-lightgray"},white:{label:"White",className:"ucb-box-theme-white"}},f="lightgray";class b extends t.Command{execute(){const{model:t}=this.editor;t.change((e=>{t.insertContent(function(t){const e=t.createElement("box",{boxTitle:c,boxAlignment:s,boxStyle:u,boxTheme:f}),n=t.createElement("boxInner"),o=t.createElement("boxTitle"),r=t.createElement("boxContent");return t.append(n,e),t.append(o,n),t.append(r,n),t.appendElement("paragraph",r),e}(e))}))}refresh(){const{model:t}=this.editor,{selection:e}=t.document,n=t.schema.findAllowedParent(e.getFirstPosition(),"box");this.isEnabled=null!==n}}var d=n(4);function h(t){const e=t.getFirstPosition();if(!e)return null;let n=e.parent;for(;n;){if(n.is("element")&&"box"===n.name)return n;n=n.parent}return null}class v extends t.Command{attributeName;defaultValue;constructor(t,e,n){super(t),this.attributeName=e,this.defaultValue=n}refresh(){const t=h(this.editor.model.document.selection),e=this.attributeName,n=this.defaultValue;this.isEnabled=!!t,this.isEnabled?this.value=t.getAttribute(e):this.value=n}execute(t={value:""}){const e=this.editor.model,n=h(e.document.selection),o=this.attributeName,r=this.defaultValue;n&&e.change((e=>e.setAttribute(o,t.value||r,n)))}}class p extends v{refresh(){const t=h(this.editor.model.document.selection),e=this.attributeName,n=this.defaultValue;this.isEnabled=!!t&&"none"!==t.getAttribute("boxStyle"),this.isEnabled?this.value=t.getAttribute(e):this.value=n}}class m extends t.Plugin{static get requires(){return[e.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){const t=this.editor.model.schema;t.register("box",{isObject:!0,allowWhere:"$block",allowAttributes:["boxTitle","boxAlignment","boxStyle","boxTheme"]}),t.register("boxInner",{isLimit:!0,allowIn:"box"}),t.register("boxTitle",{isLimit:!0,allowIn:"boxInner",allowContentOf:"$block"}),t.register("boxContent",{isLimit:!0,allowIn:"boxInner",allowContentOf:"$root"}),t.addChildCheck(((t,e)=>{if(t.endsWith("boxContent")&&"box"===e.name)return!1}))}_defineConverters(){const{conversion:t,editing:n}=this.editor;t.attributeToAttribute(g("boxTitle",r)),t.attributeToAttribute(g("boxAlignment",i)),t.attributeToAttribute(g("boxStyle",a)),t.attributeToAttribute(g("boxTheme",l)),t.for("upcast").elementToElement({model:"box",view:{name:"div",classes:"ucb-box"}}),t.for("upcast").elementToElement({model:"boxInner",view:{name:"div",classes:"ucb-box-inner"}}),t.for("upcast").elementToElement({model:"boxTitle",view:{name:"div",classes:"ucb-box-title"}}),t.for("upcast").elementToElement({model:"boxContent",view:{name:"div",classes:"ucb-box-content"}}),t.for("dataDowncast").elementToElement({model:"box",view:(t,{writer:e})=>x(e)}),t.for("dataDowncast").elementToElement({model:"boxInner",view:{name:"div",classes:"ucb-box-inner"}}),t.for("dataDowncast").elementToElement({model:"boxTitle",view:{name:"div",classes:"ucb-box-title"}}),t.for("dataDowncast").elementToElement({model:"boxContent",view:{name:"div",classes:"ucb-box-content"}}),t.for("editingDowncast").elementToElement({model:"box",view:(t,{writer:e})=>x(e,!0)}),t.for("editingDowncast").elementToElement({model:"boxInner",view:(t,{writer:e})=>e.createContainerElement("div",{class:"ucb-box-inner"})}),t.for("editingDowncast").elementToElement({model:"boxTitle",view:(t,{writer:o})=>{const r=o.createEditableElement("div",{class:"ucb-box-title"});return(0,d.enablePlaceholder)({view:n.view,element:r,text:"Title"}),(0,e.toWidgetEditable)(r,o)}}),t.for("editingDowncast").elementToElement({model:"boxContent",view:(t,{writer:n})=>{const o=n.createEditableElement("div",{class:"ucb-box-content"});return(0,e.toWidgetEditable)(o,n)}})}_defineCommands(){const t=this.editor.commands;t.add("insertBox",new b(this.editor)),t.add("modifyBoxTitle",new v(this.editor,"boxTitle",c)),t.add("alignBox",new v(this.editor,"boxAlignment",s)),t.add("styleBox",new v(this.editor,"boxStyle",u)),t.add("themeBox",new p(this.editor,"boxTheme",f))}}function g(t,e){const n={};for(const[t,o]of Object.entries(e))n[t]={key:"class",value:o.className};return{model:{key:t,values:Object.keys(e)},view:n}}function x(t,n=!1){const o=t.createContainerElement("div",{class:"ucb-box"});return n?(0,e.toWidget)(o,t,{label:"box widget",hasSelectionHandle:!0}):o}var y=n(5);class w extends t.Plugin{static get requires(){return[e.WidgetToolbarRepository]}init(){const t=this.editor,e=t.commands,n=t.ui.componentFactory;n.add("box",(n=>{const o=e.get("insertBox"),r=new y.ButtonView(n);return r.set({label:n.t("Box"),icon:'',tooltip:!0}),r.bind("isOn","isEnabled").to(o,"value","isEnabled"),this.listenTo(r,"execute",(()=>t.execute("insertBox"))),r})),n.add("boxTitle",(t=>this._createDropdown(t,"Box title",r[c].icon,e.get("modifyBoxTitle"),r,c))),n.add("boxAlignment",(t=>this._createDropdown(t,"Box alignment",i[s].icon,e.get("alignBox"),i,s))),n.add("boxStyle",(t=>this._createDropdown(t,"Box style",a[u].icon,e.get("styleBox"),a,u))),n.add("boxTheme",(t=>this._createDropdown(t,"Box theme",'\x3c!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --\x3e',e.get("themeBox"),l,f)))}afterInit(){this.editor.plugins.get(e.WidgetToolbarRepository).register("box",{items:["boxTitle","boxAlignment","boxStyle","boxTheme"],getRelatedElement:t=>t.focus?t.focus.getAncestors().find((t=>t.is("element")&&t.hasClass("ucb-box"))):null})}_createDropdown(t,e,n,o,r,c){const i=(0,y.createDropdown)(t);return(0,y.addToolbarToDropdown)(i,Object.entries(r).map((([e,n])=>this._createButton(t,n.label,n.icon,o,e)))),i.buttonView.set({label:t.t(e),icon:n,tooltip:!0,withText:!n}),n===r[c].icon&&i.buttonView.bind("icon").to(o,"value",(t=>r[t]?r[t].icon:r[c].icon)),i.bind("isEnabled").to(o,"isEnabled"),i}_createButton(t,e,n,o,r){const c=this.editor,i=new y.ButtonView;return i.set({label:t.t(e),icon:n,tooltip:!0,isToggleable:!0,withText:!n}),i.bind("isEnabled").to(o),i.bind("isOn").to(o,"value",(t=>t===r)),this.listenTo(i,"execute",(()=>{o.execute({value:r}),c.editing.view.focus()})),i}}class j extends t.Plugin{static get requires(){return[m,w]}}const _={Box:j,BoxGeneralHtmlSupport:n(6).Z}})(),o=o.default})())); \ No newline at end of file +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.CKEditor5=e():(t.CKEditor5=t.CKEditor5||{},t.CKEditor5.box=e())}(self,(()=>(()=>{var t=[t=>{"use strict";t.exports=CKEditor5.dll},(t,e,n)=>{t.exports=n(0)("./src/core.js")},(t,e,n)=>{t.exports=n(0)("./src/widget.js")},,(t,e,n)=>{t.exports=n(0)("./src/engine.js")},(t,e,n)=>{t.exports=n(0)("./src/ui.js")},(t,e,n)=>{"use strict";const o=n(1),r=n(7);class c extends o.Plugin{static get pluginName(){return"BoxGeneralHtmlSupport"}init(){const{editor:t}=this,{plugins:e}=t;if(!e.has("GeneralHtmlSupport")||!e.has("DataFilter"))return;const{model:n,conversion:o}=t,{schema:c}=n,i=e.get("DataFilter");c.extend("box",{allowAttributes:["htmlAttributes"]}),o.for("upcast").add((t=>{t.on("element:div",((t,e,n)=>{var o;const r=e.viewItem;if(!(null===(o=r.getAttribute("class"))||void 0===o?void 0:o.match(/ucb\-box(\-inner|\-title|\-content)?/)))return;((t,o)=>{const r=i.processViewAttributes(t,n);r&&n.writer.setAttribute(o,r,e.modelRange)})(r,"htmlAttributes")}),{priority:"low"})})),o.for("dataDowncast").add((t=>{t.on("attribute:htmlAttributes",((t,e,n)=>{const o=e.item;if(!["box","boxInner","boxTitle","boxContent"].includes(o.name)||!n.consumable.consume(o,t.name))return;const c=n.mapper.toViewElement(o);(null==c?void 0:c.is("element","div"))&&(0,r.setViewAttributes)(n.writer,e.attributeNewValue,c)}),{priority:"low"})}))}}e.A=c},(t,e,n)=>{"use strict";n.r(e),n.d(e,{getHtmlAttributeName:()=>No,mergeViewElementAttributes:()=>Co,modifyGhsAttribute:()=>Bo,removeViewAttributes:()=>So,setViewAttributes:()=>zo,toPascalCase:()=>Io,updateViewAttributes:()=>To});const o=function(){this.__data__=[],this.size=0};const r=function(t,e){return t===e||t!=t&&e!=e};const c=function(t,e){for(var n=t.length;n--;)if(r(t[n][0],e))return n;return-1};var i=Array.prototype.splice;const s=function(t){var e=this.__data__,n=c(e,t);return!(n<0)&&(n==e.length-1?e.pop():i.call(e,n,1),--this.size,!0)};const a=function(t){var e=this.__data__,n=c(e,t);return n<0?void 0:e[n][1]};const u=function(t){return c(this.__data__,t)>-1};const l=function(t,e){var n=this.__data__,o=c(n,t);return o<0?(++this.size,n.push([t,e])):n[o][1]=e,this};function f(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e-1&&t%1==0&&t-1&&t%1==0&&t<=9007199254740991};var Ut={};Ut["[object Float32Array]"]=Ut["[object Float64Array]"]=Ut["[object Int8Array]"]=Ut["[object Int16Array]"]=Ut["[object Int32Array]"]=Ut["[object Uint8Array]"]=Ut["[object Uint8ClampedArray]"]=Ut["[object Uint16Array]"]=Ut["[object Uint32Array]"]=!0,Ut["[object Arguments]"]=Ut["[object Array]"]=Ut["[object ArrayBuffer]"]=Ut["[object Boolean]"]=Ut["[object DataView]"]=Ut["[object Date]"]=Ut["[object Error]"]=Ut["[object Function]"]=Ut["[object Map]"]=Ut["[object Number]"]=Ut["[object Object]"]=Ut["[object RegExp]"]=Ut["[object Set]"]=Ut["[object String]"]=Ut["[object WeakMap]"]=!1;const kt=function(t){return _t(t)&&Vt(t.length)&&!!Ut[S(t)]};const Rt=function(t){return function(e){return t(e)}};var Lt="object"==typeof exports&&exports&&!exports.nodeType&&exports,Mt=Lt&&"object"==typeof module&&module&&!module.nodeType&&module,Ht=Mt&&Mt.exports===Lt&&m.process;const Wt=function(){try{var t=Mt&&Mt.require&&Mt.require("util").types;return t||Ht&&Ht.binding&&Ht.binding("util")}catch(t){}}();var $t=Wt&&Wt.isTypedArray;const Zt=$t?Rt($t):kt;var Gt=Object.prototype.hasOwnProperty;const Kt=function(t,e){var n=St(t),o=!n&&zt(t),r=!n&&!o&&Dt(t),c=!n&&!o&&!r&&Zt(t),i=n||o||r||c,s=i?jt(t.length,String):[],a=s.length;for(var u in t)!e&&!Gt.call(t,u)||i&&("length"==u||r&&("offset"==u||"parent"==u)||c&&("buffer"==u||"byteLength"==u||"byteOffset"==u)||Ft(u,a))||s.push(u);return s};var qt=Object.prototype;const Yt=function(t){var e=t&&t.constructor;return t===("function"==typeof e&&e.prototype||qt)};const Jt=function(t,e){return function(n){return t(e(n))}};const Qt=Jt(Object.keys,Object);var Xt=Object.prototype.hasOwnProperty;const te=function(t){if(!Yt(t))return Qt(t);var e=[];for(var n in Object(t))Xt.call(t,n)&&"constructor"!=n&&e.push(n);return e};const ee=function(t){return null!=t&&Vt(t.length)&&!B(t)};const ne=function(t){return ee(t)?Kt(t):te(t)};const oe=function(t,e){return t&&wt(e,ne(e),t)};const re=function(t){var e=[];if(null!=t)for(var n in Object(t))e.push(n);return e};var ce=Object.prototype.hasOwnProperty;const ie=function(t){if(!C(t))return re(t);var e=Yt(t),n=[];for(var o in t)("constructor"!=o||!e&&ce.call(t,o))&&n.push(o);return n};const se=function(t){return ee(t)?Kt(t,!0):ie(t)};const ae=function(t,e){return t&&wt(e,se(e),t)};var ue="object"==typeof exports&&exports&&!exports.nodeType&&exports,le=ue&&"object"==typeof module&&module&&!module.nodeType&&module,fe=le&&le.exports===ue?x.Buffer:void 0,be=fe?fe.allocUnsafe:void 0;const de=function(t,e){if(e)return t.slice();var n=t.length,o=be?be(n):new t.constructor(n);return t.copy(o),o};const he=function(t,e){var n=-1,o=t.length;for(e||(e=Array(o));++nr?0:r+e),(n=n>r?r:n)<0&&(n+=r),r=e>n?0:n-e>>>0,e>>>=0;for(var c=Array(r);++o=o?t:co(t,e,n)};var so=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]");const ao=function(t){return so.test(t)};const uo=function(t){return t.split("")};var lo="\\ud800-\\udfff",fo="["+lo+"]",bo="[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]",ho="\\ud83c[\\udffb-\\udfff]",vo="[^"+lo+"]",po="(?:\\ud83c[\\udde6-\\uddff]){2}",mo="[\\ud800-\\udbff][\\udc00-\\udfff]",go="(?:"+bo+"|"+ho+")"+"?",xo="[\\ufe0e\\ufe0f]?",yo=xo+go+("(?:\\u200d(?:"+[vo,po,mo].join("|")+")"+xo+go+")*"),wo="(?:"+[vo+bo+"?",bo,po,mo,fo].join("|")+")",jo=RegExp(ho+"(?="+ho+")|"+wo+yo,"g");const _o=function(t){return t.match(jo)||[]};const Ao=function(t){return ao(t)?_o(t):uo(t)};const Oo=function(t){return function(e){e=On(e);var n=ao(e)?Ao(e):void 0,o=n?n[0]:e.charAt(0),r=n?io(n,1).join(""):e.slice(1);return o[t]()+r}}("toUpperCase");const Eo=ro((function(t,e,n){return t+(n?" ":"")+Oo(e)}));function To(t,e,n,o){e&&So(t,e,o),n&&zo(t,n,o)}function zo(t,e,n){if(e.attributes)for(const[o,r]of Object.entries(e.attributes))t.setAttribute(o,r,n);e.styles&&t.setStyle(e.styles,n),e.classes&&t.addClass(e.classes,n)}function So(t,e,n){if(e.attributes)for(const[o]of Object.entries(e.attributes))t.removeAttribute(o,n);if(e.styles)for(const o of Object.keys(e.styles))t.removeStyle(o,n);e.classes&&t.removeClass(e.classes,n)}function Co(t,e){const n=mn(t);let o="attributes";for(o in e)n[o]="classes"==o?Array.from(new Set([...t[o]||[],...e[o]])):{...t[o],...e[o]};return n}function Bo(t,e,n,o,r){const c=e.getAttribute(n),i={};for(const t of["attributes","styles","classes"]){if(t!=o){c&&c[t]&&(i[t]=c[t]);continue}if("classes"==o){const e=new Set(c&&c.classes||[]);r(e),e.size&&(i[t]=Array.from(e));continue}const e=new Map(Object.entries(c&&c[t]||{}));r(e),e.size&&(i[t]=Object.fromEntries(e))}Object.keys(i).length?e.is("documentSelection")?t.setSelectionAttribute(n,i):t.setAttribute(n,i,e):c&&(e.is("documentSelection")?t.removeSelectionAttribute(n):t.removeAttribute(n,e))}function Io(t){return Eo(t).replace(/ /g,"")}function No(t){return`html${Io(t)}Attributes`}}],e={};function n(o){var r=e[o];if(void 0!==r)return r.exports;var c=e[o]={exports:{}};return t[o](c,c.exports,n),c.exports}n.d=(t,e)=>{for(var o in e)n.o(e,o)&&!n.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),n.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var o={};return(()=>{"use strict";n.d(o,{default:()=>_});var t=n(1),e=n(2);const r={left:{label:"Align left",icon:'',className:"ucb-box-title-left"},center:{label:"Align center",icon:'',className:"ucb-box-title-center"},right:{label:"Align right",icon:'',className:"ucb-box-title-right"},hidden:{label:"Hide",icon:'',className:"ucb-box-title-hidden"}},c="left",i={left:{label:"Float left",icon:t.icons.objectLeft,className:"ucb-box-alignment-left"},none:{label:"Fill width",icon:t.icons.objectFullWidth,className:"ucb-box-alignment-none"},right:{label:"Float right",icon:t.icons.objectRight,className:"ucb-box-alignment-right"}},s="none",a={fill:{label:"Fill",icon:'',className:"ucb-box-style-fill"},outline:{label:"Outline",icon:'',className:"ucb-box-style-outline"},none:{label:"None",icon:'',className:"ucb-box-style-none"}},u="fill",l={black:{label:"Black",className:"ucb-box-theme-black"},darkgray:{label:"Dark Gray",className:"ucb-box-theme-darkgray"},lightgray:{label:"Light Gray",className:"ucb-box-theme-lightgray"},white:{label:"White",className:"ucb-box-theme-white"}},f="lightgray";class b extends t.Command{execute(){const{model:t}=this.editor;t.change((e=>{t.insertContent(function(t){const e=t.createElement("box",{boxTitle:c,boxAlignment:s,boxStyle:u,boxTheme:f}),n=t.createElement("boxInner"),o=t.createElement("boxTitle"),r=t.createElement("boxContent");return t.append(n,e),t.append(o,n),t.append(r,n),t.appendElement("paragraph",r),e}(e))}))}refresh(){const{model:t}=this.editor,{selection:e}=t.document,n=t.schema.findAllowedParent(e.getFirstPosition(),"box");this.isEnabled=null!==n}}var d=n(4);function h(t){const e=t.getFirstPosition();if(!e)return null;let n=e.parent;for(;n;){if(n.is("element")&&"box"===n.name)return n;n=n.parent}return null}class v extends t.Command{attributeName;defaultValue;constructor(t,e,n){super(t),this.attributeName=e,this.defaultValue=n}refresh(){const t=h(this.editor.model.document.selection),e=this.attributeName,n=this.defaultValue;this.isEnabled=!!t,this.isEnabled?this.value=t.getAttribute(e):this.value=n}execute(t={value:""}){const e=this.editor.model,n=h(e.document.selection),o=this.attributeName,r=this.defaultValue;n&&e.change((e=>e.setAttribute(o,t.value||r,n)))}}class p extends v{refresh(){const t=h(this.editor.model.document.selection),e=this.attributeName,n=this.defaultValue;this.isEnabled=!!t&&"none"!==t.getAttribute("boxStyle"),this.isEnabled?this.value=t.getAttribute(e):this.value=n}}class m extends t.Plugin{static get requires(){return[e.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){const t=this.editor.model.schema;t.register("box",{isObject:!0,allowWhere:"$block",allowAttributes:["boxTitle","boxAlignment","boxStyle","boxTheme"]}),t.register("boxInner",{isLimit:!0,allowIn:"box"}),t.register("boxTitle",{isLimit:!0,allowIn:"boxInner",allowContentOf:"$block"}),t.register("boxContent",{isLimit:!0,allowIn:"boxInner",allowContentOf:"$root"}),t.addChildCheck(((t,e)=>{if(t.endsWith("boxContent")&&"box"===e.name)return!1}))}_defineConverters(){const{conversion:t,editing:n}=this.editor;t.attributeToAttribute(g("boxTitle",r)),t.attributeToAttribute(g("boxAlignment",i)),t.attributeToAttribute(g("boxStyle",a)),t.attributeToAttribute(g("boxTheme",l)),t.for("upcast").elementToElement({model:"box",view:{name:"div",classes:"ucb-box"}}),t.for("upcast").elementToElement({model:"boxInner",view:{name:"div",classes:"ucb-box-inner"}}),t.for("upcast").elementToElement({model:"boxTitle",view:{name:"div",classes:"ucb-box-title"}}),t.for("upcast").elementToElement({model:"boxContent",view:{name:"div",classes:"ucb-box-content"}}),t.for("dataDowncast").elementToElement({model:"box",view:(t,{writer:e})=>x(e)}),t.for("dataDowncast").elementToElement({model:"boxInner",view:{name:"div",classes:"ucb-box-inner"}}),t.for("dataDowncast").elementToElement({model:"boxTitle",view:{name:"div",classes:"ucb-box-title"}}),t.for("dataDowncast").elementToElement({model:"boxContent",view:{name:"div",classes:"ucb-box-content"}}),t.for("editingDowncast").elementToElement({model:"box",view:(t,{writer:e})=>x(e,!0)}),t.for("editingDowncast").elementToElement({model:"boxInner",view:(t,{writer:e})=>e.createContainerElement("div",{class:"ucb-box-inner"})}),t.for("editingDowncast").elementToElement({model:"boxTitle",view:(t,{writer:o})=>{const r=o.createEditableElement("div",{class:"ucb-box-title"});return(0,d.enablePlaceholder)({view:n.view,element:r,text:"Title"}),(0,e.toWidgetEditable)(r,o)}}),t.for("editingDowncast").elementToElement({model:"boxContent",view:(t,{writer:n})=>{const o=n.createEditableElement("div",{class:"ucb-box-content"});return(0,e.toWidgetEditable)(o,n)}})}_defineCommands(){const t=this.editor.commands;t.add("insertBox",new b(this.editor)),t.add("modifyBoxTitle",new v(this.editor,"boxTitle",c)),t.add("alignBox",new v(this.editor,"boxAlignment",s)),t.add("styleBox",new v(this.editor,"boxStyle",u)),t.add("themeBox",new p(this.editor,"boxTheme",f))}}function g(t,e){const n={};for(const[t,o]of Object.entries(e))n[t]={key:"class",value:o.className};return{model:{key:t,values:Object.keys(e)},view:n}}function x(t,n=!1){const o=t.createContainerElement("div",{class:"ucb-box"});return n?(0,e.toWidget)(o,t,{label:"box widget",hasSelectionHandle:!0}):o}var y=n(5);class w extends t.Plugin{static get requires(){return[e.WidgetToolbarRepository]}init(){const t=this.editor,e=t.commands,n=t.ui.componentFactory;n.add("box",(n=>{const o=e.get("insertBox"),r=new y.ButtonView(n);return r.set({label:n.t("Box"),icon:'',tooltip:!0}),r.bind("isOn","isEnabled").to(o,"value","isEnabled"),this.listenTo(r,"execute",(()=>t.execute("insertBox"))),r})),n.add("boxTitle",(t=>this._createDropdown(t,"Box title",r[c].icon,e.get("modifyBoxTitle"),r,c))),n.add("boxAlignment",(t=>this._createDropdown(t,"Box alignment",i[s].icon,e.get("alignBox"),i,s))),n.add("boxStyle",(t=>this._createDropdown(t,"Box style",a[u].icon,e.get("styleBox"),a,u))),n.add("boxTheme",(t=>this._createDropdown(t,"Box theme",'\x3c!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --\x3e',e.get("themeBox"),l,f)))}afterInit(){this.editor.plugins.get(e.WidgetToolbarRepository).register("box",{items:["boxTitle","boxAlignment","boxStyle","boxTheme"],getRelatedElement:t=>t.focus?t.focus.getAncestors().find((t=>t.is("element")&&t.hasClass("ucb-box"))):null})}_createDropdown(t,e,n,o,r,c){const i=(0,y.createDropdown)(t);return(0,y.addToolbarToDropdown)(i,Object.entries(r).map((([e,n])=>this._createButton(t,n.label,n.icon,o,e)))),i.buttonView.set({label:t.t(e),icon:n,tooltip:!0,withText:!n}),n===r[c].icon&&i.buttonView.bind("icon").to(o,"value",(t=>r[t]?r[t].icon:r[c].icon)),i.bind("isEnabled").to(o,"isEnabled"),i}_createButton(t,e,n,o,r){const c=this.editor,i=new y.ButtonView;return i.set({label:t.t(e),icon:n,tooltip:!0,isToggleable:!0,withText:!n}),i.bind("isEnabled").to(o),i.bind("isOn").to(o,"value",(t=>t===r)),this.listenTo(i,"execute",(()=>{o.execute({value:r}),c.editing.view.focus()})),i}}class j extends t.Plugin{static get requires(){return[m,w]}}const _={Box:j,BoxGeneralHtmlSupport:n(6).A}})(),o=o.default})())); \ No newline at end of file diff --git a/js/build/button.js b/js/build/button.js index 7e525ea..9edf50d 100644 --- a/js/build/button.js +++ b/js/build/button.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.button=t())}(self,(()=>(()=>{var e=[(e,t,i)=>{e.exports=i(1)("./src/core.js")},e=>{"use strict";e.exports=CKEditor5.dll},(e,t,i)=>{e.exports=i(1)("./src/ui.js")},,(e,t,i)=>{e.exports=i(1)("./src/widget.js")},(e,t,i)=>{e.exports=i(1)("./src/utils.js")}],t={};function i(o){var n=t[o];if(void 0!==n)return n.exports;var s=t[o]={exports:{}};return e[o](s,s.exports,i),s.exports}i.d=(e,t)=>{for(var o in t)i.o(t,o)&&!i.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var o={};return(()=>{"use strict";i.d(o,{default:()=>p});var e=i(0);const t={large:{label:"Large",icon:e.icons.large,className:"ucb-link-button-large"},regular:{label:"Regular",icon:e.icons.regular,className:"ucb-link-button-regular"},small:{label:"Small",icon:e.icons.small,className:"ucb-link-button-small"}},n="regular",s={blue:{label:"Blue",className:"ucb-link-button-blue"},black:{label:"Black",className:"ucb-link-button-black"},gray:{label:"Gray",className:"ucb-link-button-gray"},white:{label:"White",className:"ucb-link-button-white"},gold:{label:"Gold",className:"ucb-link-button-gold"}},l="blue",c={default:{label:"Default",icon:e.icons.objectCenter,className:"ucb-link-button-default"},full:{label:"Full",icon:e.icons.objectFullWidth,className:"ucb-link-button-full"}},r="default";class a extends e.Command{constructor(e){super(e),this.set("existingButtonSelected",!1)}execute({value:e="",size:t=n,style:i=r,color:o=l,href:s="",classes:c=""}){const a=this.editor.model,u=a.document.selection;a.change((e=>{const n=u.getFirstRange(),l=e.createElement("linkButton",{linkButtonColor:o,linkButtonSize:t,linkButtonStyle:i,linkButtonHref:s}),c=e.createElement("linkButtonContents");for(const t of n.getItems()){let i;t.is("textProxy")?i=e.createText(t.data,t.textNode.getAttributes()):t.is("element")&&(i=e.cloneElement(t)),i&&a.schema.checkChild(c,i)&&e.append(i,c)}e.append(c,l),a.insertContent(l),e.setSelection(c,"in")}))}refresh(){const e=this.editor.model,t=e.document.selection,i=t.getSelectedElement(),o=e.schema.findAllowedParent(t.getFirstPosition(),"linkButton");var n;this.isEnabled=null!==o,this.existingButtonSelected=(n=i)&&"linkButton"===n.name?i:null}}var u=i(4);class d extends e.Plugin{static get requires(){return[u.Widget]}init(){this._defineSchema(),this._defineConverters(),this.editor.commands.add("addButton",new a(this.editor))}_defineSchema(){const e=this.editor.model.schema;e.register("linkButton",{allowWhere:"$text",isObject:!0,isInline:!0,allowAttributes:["linkButtonColor","linkButtonStyle","linkButtonSize","linkButtonHref"]}),e.register("linkButtonContents",{isLimit:!0,allowIn:"linkButton",allowContentOf:"$block"}),e.addChildCheck(((e,t)=>{if(e.endsWith("linkButtonContents")&&"linkButton"===t.name)return!1}))}_defineConverters(){const{conversion:e}=this.editor;e.attributeToAttribute(h("linkButtonColor",s)),e.attributeToAttribute(h("linkButtonStyle",c)),e.attributeToAttribute(h("linkButtonSize",t)),e.for("upcast").add((e=>{e.on("element:a",((e,t,i)=>{if(i.consumable.consume(t.viewItem,{name:!0,classes:"ucb-link-button",attributes:["href"]})){const e=i.writer.createElement("linkButton",{linkButtonHref:t.viewItem.getAttribute("href")});if(!i.safeInsert(e,t.modelCursor))return;i.convertChildren(t.viewItem,e),i.updateConversionResult(e,t)}}))})),e.for("upcast").elementToElement({model:"linkButtonContents",view:{name:"span",classes:"ucb-link-button-contents"}}),e.for("downcast").attributeToAttribute({model:"linkButtonHref",view:"href"}),e.for("dataDowncast").elementToElement({model:"linkButton",view:{name:"a",classes:"ucb-link-button"}}),e.for("dataDowncast").elementToElement({model:"linkButtonContents",view:{name:"span",classes:"ucb-link-button-contents"}}),e.for("editingDowncast").elementToElement({model:"linkButton",view:(e,{writer:t})=>(0,u.toWidget)(t.createContainerElement("a",{class:"ucb-link-button",onclick:"event.preventDefault()"},{renderUnsafeAttributes:["onclick"]}),t,{label:"button widget"})}),e.for("editingDowncast").elementToElement({model:"linkButtonContents",view:(e,{writer:t})=>(0,u.toWidgetEditable)(t.createEditableElement("span",{class:"ucb-link-button-contents"}),t)})}}function h(e,t){const i={};for(const[e,o]of Object.entries(t))i[e]={key:"class",value:o.className};return{model:{key:e,values:Object.keys(t)},view:i}}var w=i(2),b=i(5);class m extends w.View{constructor(i,o){super(i),this.focusTracker=new b.FocusTracker,this.keystrokes=new b.KeystrokeHandler,this.colorDropdown=this._createSelectionDropdown(i,"Color",'\x3c!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --\x3e\n',"color",s,l),this.sizeDropdown=this._createSelectionDropdown(i,"Size",t[n].icon,"size",t,n),this.styleDropdown=this._createSelectionDropdown(i,"Style",c[r].icon,"style",c,r),this.linkInputView=this._createInput("Add Link"),this.set("size",n),this.set("color",l),this.set("style",r),this.linkInputView.fieldView.bind("href").to(this,"href"),this.set("href",""),this.saveButtonView=this._createButton("Save",e.icons.check,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton("Cancel",e.icons.cancel,"ck-button-cancel"),this.cancelButtonView.delegate("execute").to(this,"cancel"),this.childViews=this.createCollection([this.sizeDropdown,this.colorDropdown,this.styleDropdown,this.linkInputView,this.saveButtonView,this.cancelButtonView]),this._focusCycler=new w.FocusCycler({focusables:this.childViews,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-button-form"],tabindex:"-1"},children:this.childViews})}render(){super.render(),(0,w.submitHandler)({view:this}),this.childViews._items.forEach((e=>{this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this.linkInputView.isEnabled,this.linkInputView.focus()}_createInput(e){const t=new w.LabeledFieldView(this.locale,w.createLabeledInputText);return t.label=e,t}_createButton(e,t,i){const o=new w.ButtonView;return o.set({label:e,icon:t,tooltip:!0,class:i}),o}_createSelectionDropdown(e,t,i,o,n,s){const l=(0,w.createDropdown)(e),c=n[s];return(0,w.addToolbarToDropdown)(l,Object.entries(n).map((([t,i])=>this._createSelectableButton(e,i.label,i.icon,o,t)))),l.buttonView.set({icon:i,tooltip:e.t(t),withText:!i}),l.buttonView.bind("label").to(this,o,(t=>e.t(n[t]?n[t].label:c.label))),i===n[s].icon&&l.buttonView.bind("icon").to(this,o,(e=>n[e]?n[e].icon:c.icon)),l}_createSelectableButton(e,t,i,o,n){const s=new w.ButtonView;return s.set({label:e.t(t),icon:i,tooltip:!!i,isToggleable:!0,withText:!i}),s.bind("isOn").to(this,o,(e=>e===n)),this.listenTo(s,"execute",(()=>{this.set(o,n)})),s}}class f extends e.Plugin{static get requires(){return[w.ContextualBalloon]}static get pluginName(){return"ButtonUI"}init(){const e=this.editor,t=e.ui.componentFactory,i=e.commands.get("addButton"),o=e.editing.view.document;this._balloon=this.editor.plugins.get(w.ContextualBalloon),this.formView=this._createFormView(e.locale),this.buttonView=null,t.add("button",(e=>{const t=new w.ButtonView(e);t.label="Button",t.icon='\x3c!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --\x3e',t.tooltip=!0,t.withText=!1,t.isToggleable=!0,this.listenTo(t,"execute",(()=>{this._showUI(i.existingButtonSelected)})),this.buttonView=t;const n=()=>{const e=i.existingButtonSelected;t.isOn=!!e};return this.listenTo(i,"change:value",n),this.listenTo(i,"change:existingButtonSelected",n),this.listenTo(o,"click",(()=>{i.existingButtonSelected&&this._showUI(i.existingButtonSelected)})),this.on("showUI",((e,t)=>{this._showUI(t)})),t.bind("isOn","isEnabled").to(i,"value","isEnabled"),t}))}_createFormView(e){const t=this.editor,i=t.ui.componentFactory,o=new m(e,i);return this.listenTo(o,"submit",(()=>{const e={href:o.linkInputView.fieldView.element.value,color:o.color,size:o.size,style:o.style};t.execute("addButton",e),this._hideUI()})),this.listenTo(o,"cancel",(()=>{this._hideUI()})),o.keystrokes.set("Esc",((e,t)=>{this._hideUI(),t()})),(0,w.clickOutsideHandler)({emitter:o,activator:()=>this._balloon.visibleView===o,contextElements:[this._balloon.view.element],callback:()=>this._hideUI()}),o}_showUI(e){this.buttonView.isOn=!0,this._balloon.visibleView&&this._hideUI();const t=this.editor.commands.get("addButton").value;if(this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),e){const t=e.getAttribute("linkButtonSize"),i=e.getAttribute("linkButtonColor"),o=e.getAttribute("linkButtonStyle"),n=e.getAttribute("linkButtonHref");this.formView.color=i,this.formView.style=o,this.formView.size=t,this.formView.linkInputView.fieldView.value=n,this.formView.linkInputView.fieldView.element.value=n,this.formView.linkInputView.fieldView.set("value",n)}t&&(this.formView.linkInputView.fieldView.value=t.link,this.formView.colorDropdown.fieldView.value=t.color,this.formView.sizeDropdown.fieldView.value=t.size,this.formView.styleDropdown.fieldView.value=t.style),setTimeout((()=>{this.formView.linkInputView.fieldView.focus()}),0)}_hideUI(){this._balloon.hasView(this.formView)&&(this.formView.element.reset(),this.buttonView.isOn=!1,this._balloon.remove(this.formView),this.editor.editing.view.focus())}_getBalloonPositionData(){const e=this.editor.editing.view,t=e.document;let i=null;return i=()=>e.domConverter.viewRangeToDom(t.selection.getFirstRange()),{target:i}}}class k extends e.Plugin{static get requires(){return[d,f]}}const p={Button:k}})(),o=o.default})())); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.button=t())}(self,(()=>(()=>{var e=[e=>{"use strict";e.exports=CKEditor5.dll},(e,t,i)=>{e.exports=i(0)("./src/core.js")},(e,t,i)=>{e.exports=i(0)("./src/ui.js")},,(e,t,i)=>{e.exports=i(0)("./src/widget.js")},(e,t,i)=>{e.exports=i(0)("./src/utils.js")}],t={};function i(o){var n=t[o];if(void 0!==n)return n.exports;var s=t[o]={exports:{}};return e[o](s,s.exports,i),s.exports}i.d=(e,t)=>{for(var o in t)i.o(t,o)&&!i.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var o={};return(()=>{"use strict";i.d(o,{default:()=>p});var e=i(1);const t={large:{label:"Large",icon:e.icons.large,className:"ucb-link-button-large"},regular:{label:"Regular",icon:e.icons.regular,className:"ucb-link-button-regular"},small:{label:"Small",icon:e.icons.small,className:"ucb-link-button-small"}},n="regular",s={blue:{label:"Blue",className:"ucb-link-button-blue"},black:{label:"Black",className:"ucb-link-button-black"},gray:{label:"Gray",className:"ucb-link-button-gray"},white:{label:"White",className:"ucb-link-button-white"},gold:{label:"Gold",className:"ucb-link-button-gold"}},l="blue",c={default:{label:"Default",icon:e.icons.objectCenter,className:"ucb-link-button-default"},full:{label:"Full",icon:e.icons.objectFullWidth,className:"ucb-link-button-full"}},r="default";class a extends e.Command{constructor(e){super(e),this.set("existingButtonSelected",!1)}execute({value:e="",size:t=n,style:i=r,color:o=l,href:s="",classes:c=""}){const a=this.editor.model,u=a.document.selection;a.change((e=>{const n=u.getFirstRange(),l=e.createElement("linkButton",{linkButtonColor:o,linkButtonSize:t,linkButtonStyle:i,linkButtonHref:s}),c=e.createElement("linkButtonContents");for(const t of n.getItems()){let i;t.is("textProxy")?i=e.createText(t.data,t.textNode.getAttributes()):t.is("element")&&(i=e.cloneElement(t)),i&&a.schema.checkChild(c,i)&&e.append(i,c)}e.append(c,l),a.insertContent(l),e.setSelection(c,"in")}))}refresh(){const e=this.editor.model,t=e.document.selection,i=t.getSelectedElement(),o=e.schema.findAllowedParent(t.getFirstPosition(),"linkButton");var n;this.isEnabled=null!==o,this.existingButtonSelected=(n=i)&&"linkButton"===n.name?i:null}}var u=i(4);class d extends e.Plugin{static get requires(){return[u.Widget]}init(){this._defineSchema(),this._defineConverters(),this.editor.commands.add("addButton",new a(this.editor))}_defineSchema(){const e=this.editor.model.schema;e.register("linkButton",{allowWhere:"$text",isObject:!0,isInline:!0,allowAttributes:["linkButtonColor","linkButtonStyle","linkButtonSize","linkButtonHref"]}),e.register("linkButtonContents",{isLimit:!0,allowIn:"linkButton",allowContentOf:"$block"}),e.addChildCheck(((e,t)=>{if(e.endsWith("linkButtonContents")&&"linkButton"===t.name)return!1}))}_defineConverters(){const{conversion:e}=this.editor;e.attributeToAttribute(h("linkButtonColor",s)),e.attributeToAttribute(h("linkButtonStyle",c)),e.attributeToAttribute(h("linkButtonSize",t)),e.for("upcast").add((e=>{e.on("element:a",((e,t,i)=>{if(i.consumable.consume(t.viewItem,{name:!0,classes:"ucb-link-button",attributes:["href"]})){const e=i.writer.createElement("linkButton",{linkButtonHref:t.viewItem.getAttribute("href")});if(!i.safeInsert(e,t.modelCursor))return;i.convertChildren(t.viewItem,e),i.updateConversionResult(e,t)}}))})),e.for("upcast").elementToElement({model:"linkButtonContents",view:{name:"span",classes:"ucb-link-button-contents"}}),e.for("downcast").attributeToAttribute({model:"linkButtonHref",view:"href"}),e.for("dataDowncast").elementToElement({model:"linkButton",view:{name:"a",classes:"ucb-link-button"}}),e.for("dataDowncast").elementToElement({model:"linkButtonContents",view:{name:"span",classes:"ucb-link-button-contents"}}),e.for("editingDowncast").elementToElement({model:"linkButton",view:(e,{writer:t})=>(0,u.toWidget)(t.createContainerElement("a",{class:"ucb-link-button",onclick:"event.preventDefault()"},{renderUnsafeAttributes:["onclick"]}),t,{label:"button widget"})}),e.for("editingDowncast").elementToElement({model:"linkButtonContents",view:(e,{writer:t})=>(0,u.toWidgetEditable)(t.createEditableElement("span",{class:"ucb-link-button-contents"}),t)})}}function h(e,t){const i={};for(const[e,o]of Object.entries(t))i[e]={key:"class",value:o.className};return{model:{key:e,values:Object.keys(t)},view:i}}var w=i(2),b=i(5);class m extends w.View{constructor(i,o){super(i),this.focusTracker=new b.FocusTracker,this.keystrokes=new b.KeystrokeHandler,this.colorDropdown=this._createSelectionDropdown(i,"Color",'\x3c!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --\x3e\n',"color",s,l),this.sizeDropdown=this._createSelectionDropdown(i,"Size",t[n].icon,"size",t,n),this.styleDropdown=this._createSelectionDropdown(i,"Style",c[r].icon,"style",c,r),this.linkInputView=this._createInput("Add Link"),this.set("size",n),this.set("color",l),this.set("style",r),this.linkInputView.fieldView.bind("href").to(this,"href"),this.set("href",""),this.saveButtonView=this._createButton("Save",e.icons.check,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton("Cancel",e.icons.cancel,"ck-button-cancel"),this.cancelButtonView.delegate("execute").to(this,"cancel"),this.childViews=this.createCollection([this.sizeDropdown,this.colorDropdown,this.styleDropdown,this.linkInputView,this.saveButtonView,this.cancelButtonView]),this._focusCycler=new w.FocusCycler({focusables:this.childViews,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-button-form"],tabindex:"-1"},children:this.childViews})}render(){super.render(),(0,w.submitHandler)({view:this}),this.childViews._items.forEach((e=>{this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this.linkInputView.isEnabled,this.linkInputView.focus()}_createInput(e){const t=new w.LabeledFieldView(this.locale,w.createLabeledInputText);return t.label=e,t}_createButton(e,t,i){const o=new w.ButtonView;return o.set({label:e,icon:t,tooltip:!0,class:i}),o}_createSelectionDropdown(e,t,i,o,n,s){const l=(0,w.createDropdown)(e),c=n[s];return(0,w.addToolbarToDropdown)(l,Object.entries(n).map((([t,i])=>this._createSelectableButton(e,i.label,i.icon,o,t)))),l.buttonView.set({icon:i,tooltip:e.t(t),withText:!i}),l.buttonView.bind("label").to(this,o,(t=>e.t(n[t]?n[t].label:c.label))),i===n[s].icon&&l.buttonView.bind("icon").to(this,o,(e=>n[e]?n[e].icon:c.icon)),l}_createSelectableButton(e,t,i,o,n){const s=new w.ButtonView;return s.set({label:e.t(t),icon:i,tooltip:!!i,isToggleable:!0,withText:!i}),s.bind("isOn").to(this,o,(e=>e===n)),this.listenTo(s,"execute",(()=>{this.set(o,n)})),s}}class f extends e.Plugin{static get requires(){return[w.ContextualBalloon]}static get pluginName(){return"ButtonUI"}init(){const e=this.editor,t=e.ui.componentFactory,i=e.commands.get("addButton"),o=e.editing.view.document;this._balloon=this.editor.plugins.get(w.ContextualBalloon),this.formView=this._createFormView(e.locale),this.buttonView=null,t.add("button",(e=>{const t=new w.ButtonView(e);t.label="Button",t.icon='\x3c!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --\x3e',t.tooltip=!0,t.withText=!1,t.isToggleable=!0,this.listenTo(t,"execute",(()=>{this._showUI(i.existingButtonSelected)})),this.buttonView=t;const n=()=>{const e=i.existingButtonSelected;t.isOn=!!e};return this.listenTo(i,"change:value",n),this.listenTo(i,"change:existingButtonSelected",n),this.listenTo(o,"click",(()=>{i.existingButtonSelected&&this._showUI(i.existingButtonSelected)})),this.on("showUI",((e,t)=>{this._showUI(t)})),t.bind("isOn","isEnabled").to(i,"value","isEnabled"),t}))}_createFormView(e){const t=this.editor,i=t.ui.componentFactory,o=new m(e,i);return this.listenTo(o,"submit",(()=>{const e={href:o.linkInputView.fieldView.element.value,color:o.color,size:o.size,style:o.style};t.execute("addButton",e),this._hideUI()})),this.listenTo(o,"cancel",(()=>{this._hideUI()})),o.keystrokes.set("Esc",((e,t)=>{this._hideUI(),t()})),(0,w.clickOutsideHandler)({emitter:o,activator:()=>this._balloon.visibleView===o,contextElements:[this._balloon.view.element],callback:()=>this._hideUI()}),o}_showUI(e){this.buttonView.isOn=!0,this._balloon.visibleView&&this._hideUI();const t=this.editor.commands.get("addButton").value;if(this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),e){const t=e.getAttribute("linkButtonSize"),i=e.getAttribute("linkButtonColor"),o=e.getAttribute("linkButtonStyle"),n=e.getAttribute("linkButtonHref");this.formView.color=i,this.formView.style=o,this.formView.size=t,this.formView.linkInputView.fieldView.value=n,this.formView.linkInputView.fieldView.element.value=n,this.formView.linkInputView.fieldView.set("value",n)}t&&(this.formView.linkInputView.fieldView.value=t.link,this.formView.colorDropdown.fieldView.value=t.color,this.formView.sizeDropdown.fieldView.value=t.size,this.formView.styleDropdown.fieldView.value=t.style),setTimeout((()=>{this.formView.linkInputView.fieldView.focus()}),0)}_hideUI(){this._balloon.hasView(this.formView)&&(this.formView.element.reset(),this.buttonView.isOn=!1,this._balloon.remove(this.formView),this.editor.editing.view.focus())}_getBalloonPositionData(){const e=this.editor.editing.view,t=e.document;let i=null;return i=()=>e.domConverter.viewRangeToDom(t.selection.getFirstRange()),{target:i}}}class k extends e.Plugin{static get requires(){return[d,f]}}const p={Button:k}})(),o=o.default})())); \ No newline at end of file diff --git a/js/build/buttongroup.js b/js/build/buttongroup.js index 8de0298..4100601 100644 --- a/js/build/buttongroup.js +++ b/js/build/buttongroup.js @@ -1 +1 @@ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.CKEditor5=e():(t.CKEditor5=t.CKEditor5||{},t.CKEditor5.buttongroup=e())}(self,(()=>(()=>{var t=[(t,e,o)=>{t.exports=o(1)("./src/core.js")},t=>{"use strict";t.exports=CKEditor5.dll},(t,e,o)=>{t.exports=o(1)("./src/ui.js")},(t,e,o)=>{t.exports=o(1)("./src/widget.js")},,(t,e,o)=>{t.exports=o(1)("./src/utils.js")}],e={};function o(n){var i=e[n];if(void 0!==i)return i.exports;var r=e[n]={exports:{}};return t[n](r,r.exports,o),r.exports}o.d=(t,e)=>{for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);var n={};return(()=>{"use strict";o.d(n,{default:()=>f});var t=o(0),e=o(3),i=o(2);const r={large:{label:"Large",icon:t.icons.objectSizeLarge,className:"ucb-link-button-large"},regular:{label:"Regular",icon:t.icons.objectSizeMedium,className:"ucb-link-button-regular"},small:{label:"Small",icon:t.icons.objectSizeSmall,className:"ucb-link-button-small"}},l="regular",u={blue:{label:"Blue",className:"ucb-link-button-blue"},black:{label:"Black",className:"ucb-link-button-black"},gray:{label:"Gray",className:"ucb-link-button-gray"},white:{label:"White",className:"ucb-link-button-white"},gold:{label:"Gold",className:"ucb-link-button-gold"}},s="blue";class c extends t.Plugin{static get requires(){return[e.WidgetToolbarRepository]}init(){const e=this.editor,o=e.commands,n=e.ui.componentFactory;n.add("buttonGroup",(t=>{const n=new i.ButtonView(t),r=o.get("insertButtonGroup");return n.label="Button Group",n.icon='\x3c!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --\x3e',n.tooltip=!0,n.withText=!1,n.isToggleable=!0,n.bind("isOn","isEnabled").to(r,"value","isEnabled"),this.listenTo(n,"execute",(()=>e.execute("insertButtonGroup"))),n})),n.add("buttonGroupSize",(t=>this._createDropdown(t,"Size",r[l].icon,o.get("buttonGroupSize"),r,l))),n.add("buttonGroupColor",(t=>this._createDropdown(t,"Color",u[s].icon,o.get("buttonGroupColor"),u,s))),n.add("addNewButtonBG",(e=>this._createButton(e,"Add Button",t.icons.plus,o.get("addNewButtonBG"),null)))}afterInit(){this.editor.plugins.get(e.WidgetToolbarRepository).register("buttonGroup",{items:["buttonGroupSize","buttonGroupColor","addNewButtonBG"],getRelatedElement:t=>{const e=t.getSelectedElement();return e&&e.is("element")&&e.hasClass("ucb-button-group")?e:null}})}_createDropdown(t,e,o,n,r,l){const u=(0,i.createDropdown)(t);return(0,i.addToolbarToDropdown)(u,Object.entries(r).map((([e,o])=>this._createButton(t,o.label,o.icon,n,e)))),u.buttonView.set({label:t.t(e),icon:o,tooltip:!0,withText:!o}),o?o===r[l].icon&&u.buttonView.bind("icon").to(n,"value",(t=>r[t]?r[t].icon:r[l].icon)):u.buttonView.bind("label").to(n,"value",(t=>r[t]?r[t].label:r[l].label)),u.bind("isEnabled").to(n,"isEnabled"),u}_createButton(t,e,o,n,r){const l=this.editor,u=new i.ButtonView;return u.set({label:t.t(e),icon:o,tooltip:!0,isToggleable:!0,withText:!o}),u.bind("isEnabled").to(n),u.bind("isOn").to(n,"value",(t=>t===r)),this.listenTo(u,"execute",(()=>{n.execute({value:r}),l.editing.view.focus()})),u}}class a extends t.Command{execute(){const{model:t}=this.editor;t.change((e=>{t.insertContent(function(t){const e=t.model,o=e.document.selection,n=t.createElement("buttonGroup",{buttonGroupColor:s,buttonGroupSize:l}),i=o.getFirstRange();for(const e of i.getItems())if("linkButton"==e.name){const o=!!e._children&&t.cloneElement(e._children._nodes[0]),i=e._clone();i._setAttribute("linkButtonColor",s),i._setAttribute("linkButtonSize",l),o&&t.append(o,i),t.append(i,n)}return n}(e))}))}refresh(){const t=this.editor.model,e=t.document.selection,o=e.getSelectedElement();if(o&&"buttonGroup"==o.name){const t=o.getAttribute("buttonGroupColor"),e=o.getAttribute("buttonGroupSize");Array.from(o.getChildren()).forEach((o=>{o._setAttribute("linkButtonColor",t),o._setAttribute("linkButtonSize",e)}))}const n=t.schema.findAllowedParent(e.getFirstPosition(),"buttonGroup");var i;this.isEnabled=null!==n,this.existingButtonGroupSelected=(i=o)&&"buttonGroup"===i.name?o:null}}class d extends t.Command{attributeName;defaultValue;constructor(t,e,o){super(t),this.attributeName=e,this.defaultValue=o}refresh(){const t=this.editor.model.document.selection.getSelectedElement(),e=this.attributeName,o=this.defaultValue;this.isEnabled=!!t,this.isEnabled?this.value=t.getAttribute(e):this.value=o}execute(t={value:""}){const e=this.editor.model,o=e.document.selection.getSelectedElement(),n=this.attributeName,i=this.defaultValue;o&&e.change((e=>{e.setAttribute(n,t.value||i,o);for(const t of o.getChildren())"linkButton"===t.name&&(e.setAttribute("linkButtonColor",o.getAttribute("buttonGroupColor")||defaultColor,t),e.setAttribute("linkButtonSize",o.getAttribute("buttonGroupSize")||defaultSize,t))}))}}o(5);t.icons.large,t.icons.regular,t.icons.small,t.icons.objectCenter,t.icons.objectFullWidth;class b extends t.Command{execute(){const{model:t}=this.editor,e=t.document.selection.getSelectedElement();t.change((t=>{if(m(e)){const o=function(t){const e=t.model,o=e.document.selection,n=o.getSelectedElement();if(m(n)){const e=n.getAttribute("buttonGroupColor"),o=n.getAttribute("buttonGroupSize");return t.createElement("linkButton",{linkButtonColor:e,linkButtonSize:o,linkButtonHref:""})}return null}(t);t.append(o,e),t.setSelection(o,"on"),this.editor.plugins.get("ButtonUI").fire("showUI",o)}}))}refresh(){const t=this.editor.model,e=t.document.selection,o=e.getSelectedElement(),n=t.schema.findAllowedParent(e.getFirstPosition(),"buttonGroup");this.isEnabled=null!==n,this.existingButtonGroupSelected=m(o)?o:null}}function m(t){return t&&"buttonGroup"===t.name}class p extends t.Plugin{static get requires(){return[e.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){this.editor.model.schema.register("buttonGroup",{allowWhere:"$block",isObject:!0,isInline:!0,allowAttributes:["buttonGroupColor","buttonGroupSize"],allowChildren:"linkButton"})}_defineConverters(){const{conversion:t,editing:o}=this.editor;t.attributeToAttribute(g("buttonGroupColor",u)),t.attributeToAttribute(g("buttonGroupSize",r)),t.for("upcast").elementToElement({model:"buttonGroup",view:{name:"div",classes:"ucb-button-group"}}),t.for("dataDowncast").elementToElement({model:"buttonGroup",view:{name:"div",classes:"ucb-button-group"}}),t.for("editingDowncast").elementToElement({model:"buttonGroup",view:(t,{writer:o})=>function(t,o=!1){const n=t.createContainerElement("div",{class:"ucb-button-group"});return o?(0,e.toWidget)(n,t,{label:"button group widget",hasSelectionHandle:!0}):n}(o,!0)})}_defineCommands(){const t=this.editor.commands;t.add("insertButtonGroup",new a(this.editor)),t.add("buttonGroupSize",new d(this.editor,"buttonGroupSize",l)),t.add("buttonGroupColor",new d(this.editor,"buttonGroupColor",s)),t.add("addNewButtonBG",new b(this.editor))}}function g(t,e){const o={};for(const[t,n]of Object.entries(e))o[t]={key:"class",value:n.className};return{model:{key:t,values:Object.keys(e)},view:o}}class h extends t.Plugin{static get requires(){return[p,c]}}const f={ButtonGroup:h}})(),n=n.default})())); \ No newline at end of file +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.CKEditor5=e():(t.CKEditor5=t.CKEditor5||{},t.CKEditor5.buttongroup=e())}(self,(()=>(()=>{var t=[t=>{"use strict";t.exports=CKEditor5.dll},(t,e,o)=>{t.exports=o(0)("./src/core.js")},(t,e,o)=>{t.exports=o(0)("./src/ui.js")},(t,e,o)=>{t.exports=o(0)("./src/widget.js")},,(t,e,o)=>{t.exports=o(0)("./src/utils.js")}],e={};function o(n){var i=e[n];if(void 0!==i)return i.exports;var r=e[n]={exports:{}};return t[n](r,r.exports,o),r.exports}o.d=(t,e)=>{for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);var n={};return(()=>{"use strict";o.d(n,{default:()=>f});var t=o(1),e=o(3),i=o(2);const r={large:{label:"Large",icon:t.icons.objectSizeLarge,className:"ucb-link-button-large"},regular:{label:"Regular",icon:t.icons.objectSizeMedium,className:"ucb-link-button-regular"},small:{label:"Small",icon:t.icons.objectSizeSmall,className:"ucb-link-button-small"}},l="regular",u={blue:{label:"Blue",className:"ucb-link-button-blue"},black:{label:"Black",className:"ucb-link-button-black"},gray:{label:"Gray",className:"ucb-link-button-gray"},white:{label:"White",className:"ucb-link-button-white"},gold:{label:"Gold",className:"ucb-link-button-gold"}},s="blue";class c extends t.Plugin{static get requires(){return[e.WidgetToolbarRepository]}init(){const e=this.editor,o=e.commands,n=e.ui.componentFactory;n.add("buttonGroup",(t=>{const n=new i.ButtonView(t),r=o.get("insertButtonGroup");return n.label="Button Group",n.icon='\x3c!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --\x3e',n.tooltip=!0,n.withText=!1,n.isToggleable=!0,n.bind("isOn","isEnabled").to(r,"value","isEnabled"),this.listenTo(n,"execute",(()=>e.execute("insertButtonGroup"))),n})),n.add("buttonGroupSize",(t=>this._createDropdown(t,"Size",r[l].icon,o.get("buttonGroupSize"),r,l))),n.add("buttonGroupColor",(t=>this._createDropdown(t,"Color",u[s].icon,o.get("buttonGroupColor"),u,s))),n.add("addNewButtonBG",(e=>this._createButton(e,"Add Button",t.icons.plus,o.get("addNewButtonBG"),null)))}afterInit(){this.editor.plugins.get(e.WidgetToolbarRepository).register("buttonGroup",{items:["buttonGroupSize","buttonGroupColor","addNewButtonBG"],getRelatedElement:t=>{const e=t.getSelectedElement();return e&&e.is("element")&&e.hasClass("ucb-button-group")?e:null}})}_createDropdown(t,e,o,n,r,l){const u=(0,i.createDropdown)(t);return(0,i.addToolbarToDropdown)(u,Object.entries(r).map((([e,o])=>this._createButton(t,o.label,o.icon,n,e)))),u.buttonView.set({label:t.t(e),icon:o,tooltip:!0,withText:!o}),o?o===r[l].icon&&u.buttonView.bind("icon").to(n,"value",(t=>r[t]?r[t].icon:r[l].icon)):u.buttonView.bind("label").to(n,"value",(t=>r[t]?r[t].label:r[l].label)),u.bind("isEnabled").to(n,"isEnabled"),u}_createButton(t,e,o,n,r){const l=this.editor,u=new i.ButtonView;return u.set({label:t.t(e),icon:o,tooltip:!0,isToggleable:!0,withText:!o}),u.bind("isEnabled").to(n),u.bind("isOn").to(n,"value",(t=>t===r)),this.listenTo(u,"execute",(()=>{n.execute({value:r}),l.editing.view.focus()})),u}}class a extends t.Command{execute(){const{model:t}=this.editor;t.change((e=>{t.insertContent(function(t){const e=t.model,o=e.document.selection,n=t.createElement("buttonGroup",{buttonGroupColor:s,buttonGroupSize:l}),i=o.getFirstRange();for(const e of i.getItems())if("linkButton"==e.name){const o=!!e._children&&t.cloneElement(e._children._nodes[0]),i=e._clone();i._setAttribute("linkButtonColor",s),i._setAttribute("linkButtonSize",l),o&&t.append(o,i),t.append(i,n)}return n}(e))}))}refresh(){const t=this.editor.model,e=t.document.selection,o=e.getSelectedElement();if(o&&"buttonGroup"==o.name){const t=o.getAttribute("buttonGroupColor"),e=o.getAttribute("buttonGroupSize");Array.from(o.getChildren()).forEach((o=>{o._setAttribute("linkButtonColor",t),o._setAttribute("linkButtonSize",e)}))}const n=t.schema.findAllowedParent(e.getFirstPosition(),"buttonGroup");var i;this.isEnabled=null!==n,this.existingButtonGroupSelected=(i=o)&&"buttonGroup"===i.name?o:null}}class d extends t.Command{attributeName;defaultValue;constructor(t,e,o){super(t),this.attributeName=e,this.defaultValue=o}refresh(){const t=this.editor.model.document.selection.getSelectedElement(),e=this.attributeName,o=this.defaultValue;this.isEnabled=!!t,this.isEnabled?this.value=t.getAttribute(e):this.value=o}execute(t={value:""}){const e=this.editor.model,o=e.document.selection.getSelectedElement(),n=this.attributeName,i=this.defaultValue;o&&e.change((e=>{e.setAttribute(n,t.value||i,o);for(const t of o.getChildren())"linkButton"===t.name&&(e.setAttribute("linkButtonColor",o.getAttribute("buttonGroupColor")||defaultColor,t),e.setAttribute("linkButtonSize",o.getAttribute("buttonGroupSize")||defaultSize,t))}))}}o(5);t.icons.large,t.icons.regular,t.icons.small,t.icons.objectCenter,t.icons.objectFullWidth;i.View;class b extends t.Command{execute(){const{model:t}=this.editor,e=t.document.selection.getSelectedElement();t.change((t=>{if(m(e)){const o=function(t){const e=t.model,o=e.document.selection,n=o.getSelectedElement();if(m(n)){const e=n.getAttribute("buttonGroupColor"),o=n.getAttribute("buttonGroupSize");return t.createElement("linkButton",{linkButtonColor:e,linkButtonSize:o,linkButtonHref:""})}return null}(t);t.append(o,e),t.setSelection(o,"on"),this.editor.plugins.get("ButtonUI").fire("showUI",o)}}))}refresh(){const t=this.editor.model,e=t.document.selection,o=e.getSelectedElement(),n=t.schema.findAllowedParent(e.getFirstPosition(),"buttonGroup");this.isEnabled=null!==n,this.existingButtonGroupSelected=m(o)?o:null}}function m(t){return t&&"buttonGroup"===t.name}class p extends t.Plugin{static get requires(){return[e.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){this.editor.model.schema.register("buttonGroup",{allowWhere:"$block",isObject:!0,isInline:!0,allowAttributes:["buttonGroupColor","buttonGroupSize"],allowChildren:"linkButton"})}_defineConverters(){const{conversion:t,editing:o}=this.editor;t.attributeToAttribute(g("buttonGroupColor",u)),t.attributeToAttribute(g("buttonGroupSize",r)),t.for("upcast").elementToElement({model:"buttonGroup",view:{name:"div",classes:"ucb-button-group"}}),t.for("dataDowncast").elementToElement({model:"buttonGroup",view:{name:"div",classes:"ucb-button-group"}}),t.for("editingDowncast").elementToElement({model:"buttonGroup",view:(t,{writer:o})=>function(t,o=!1){const n=t.createContainerElement("div",{class:"ucb-button-group"});return o?(0,e.toWidget)(n,t,{label:"button group widget",hasSelectionHandle:!0}):n}(o,!0)})}_defineCommands(){const t=this.editor.commands;t.add("insertButtonGroup",new a(this.editor)),t.add("buttonGroupSize",new d(this.editor,"buttonGroupSize",l)),t.add("buttonGroupColor",new d(this.editor,"buttonGroupColor",s)),t.add("addNewButtonBG",new b(this.editor))}}function g(t,e){const o={};for(const[t,n]of Object.entries(e))o[t]={key:"class",value:n.className};return{model:{key:t,values:Object.keys(e)},view:o}}class h extends t.Plugin{static get requires(){return[p,c]}}const f={ButtonGroup:h}})(),n=n.default})())); \ No newline at end of file diff --git a/js/build/calendar.js b/js/build/calendar.js index de59029..610cb9b 100644 --- a/js/build/calendar.js +++ b/js/build/calendar.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.calendar=t())}(self,(()=>(()=>{var e=[(e,t,i)=>{e.exports=i(1)("./src/core.js")},e=>{"use strict";e.exports=CKEditor5.dll},(e,t,i)=>{e.exports=i(1)("./src/widget.js")},(e,t,i)=>{e.exports=i(1)("./src/ui.js")},,(e,t,i)=>{e.exports=i(1)("./src/utils.js")}],t={};function i(n){var s=t[n];if(void 0!==s)return s.exports;var r=t[n]={exports:{}};return e[n](r,r.exports,i),r.exports}i.d=(e,t)=>{for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n={};return(()=>{"use strict";i.d(n,{default:()=>g});var e=i(0),t=i(2);function s(e){if("<"===e[0]&&!(e=function(e){const t=(new DOMParser).parseFromString(e,"text/html").querySelector("iframe");return t?t.getAttribute("src"):null}(e)))return null;let t;try{t=new URL(e)}catch(e){return null}return t.hostname.match(/(www|calendar)\.google\.com/)&&t.pathname.match(/\/calendar\/embed\/?/)?t.searchParams.toString():null}function r(e){return"https://calendar.google.com/calendar/embed?"+e}class o extends e.Command{constructor(e){super(e),this.set("existingCalendarSelected",!1)}execute(e={value:""}){const t=e.value.trim(),i=this.editor.model;if(!t)return;let n=s(t);n&&i.change((e=>i.insertContent(e.createElement("googleCalendar",{calendarQueryString:n}))))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,i=t.getSelectedElement(),n=e.schema.findAllowedParent(t.getFirstPosition(),"googleCalendar");var s;this.isEnabled=null!==n,this.existingCalendarSelected=(s=i)&&"googleCalendar"===s.name?i:null}}class a extends e.Plugin{static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){this.editor.model.schema.register("googleCalendar",{isObject:!0,allowWhere:"$block",allowAttributes:["calendarQueryString"],allowChildren:!1})}_defineConverters(){const e=this.editor.conversion;e.attributeToAttribute({model:{key:"calendarQueryString",value:e=>e.getAttribute("data-query-string").replace(/&/g,"&")},view:"data-query-string"}),e.for("upcast").elementToElement({model:"googleCalendar",view:{name:"ucb-calendar",classes:["ucb-calendar","ucb-google-calendar"]}}),e.for("dataDowncast").elementToElement({model:"googleCalendar",view:(e,{writer:t})=>l(e,t)}),e.for("editingDowncast").elementToElement({model:"googleCalendar",view:(e,{writer:t})=>l(e,t,!0)})}_defineCommands(){this.editor.commands.add("insertCalendar",new o(this.editor))}}function l(e,i,n=!1){if(n){const n=e.getAttribute("calendarQueryString")||"";return(0,t.toWidget)(i.createContainerElement("div",{class:"ucb-calendar ucb-google-calendar"},[i.createEmptyElement("iframe",{src:r(n),loading:"lazy",referrerpolicy:"no-referrer",frameborder:"0",scrolling:"no"}),i.createEmptyElement("div",{class:"ucb-calendar-editing-cover"})]),i,{label:"calendar widget"})}return i.createContainerElement("ucb-calendar",{class:"ucb-calendar ucb-google-calendar"})}var c=i(3),d=i(5);class u extends c.View{constructor(t){super(t),this.valueInputView=this._createInput(t,"Calendar embed"),this.set("value",""),this.valueInputView.fieldView.bind("value").to(this,"value"),this.saveButtonView=this._createActionButton(t,"Save",e.icons.check,"ck-button-save"),this.cancelButtonView=this._createActionButton(t,"Cancel",e.icons.cancel,"ck-button-cancel"),this.saveButtonView.type="submit",this.cancelButtonView.delegate("execute").to(this,"cancel"),this.childViews=this.createCollection([this.valueInputView,this.saveButtonView,this.cancelButtonView]),this._enableFocusTracking(),this.setTemplate({tag:"form",attributes:{class:["ck","ck-calendar-form"],tabindex:"-1"},children:this.childViews})}render(){super.render();for(const e of this.childViews)this.focusTracker.add(e.element);(0,c.submitHandler)({view:this}),this.keystrokes.listenTo(this.element)}focus(){this.valueInputView.focus()}reset(){this.value="",this.valueInputView.fieldView.element.blur(),this.element.reset()}destroy(){this.keystrokes.destroy()}_createSelectableButton(e,t,i,n,s){const r=new c.ButtonView;return r.set({label:e.t(t),icon:i,tooltip:!!i,isToggleable:!0,withText:!i}),r.bind("isOn").to(this,n,(e=>e===s)),this.listenTo(r,"execute",(()=>{this.set(n,s)})),r}_createActionButton(e,t,i,n){const s=new c.ButtonView;return s.set({label:e.t(t),icon:i,class:n,tooltip:!!i,withText:!i}),s}_createInput(e,t){const i=new c.LabeledFieldView(e,c.createLabeledInputText);return i.label=e.t(t),i}_enableFocusTracking(){this.focusTracker=new d.FocusTracker,this.keystrokes=new d.KeystrokeHandler,this.focusTracker.on("change:focusedElement",((e,t,i)=>{i===this.valueInputView.element&&this.valueInputView.fieldView.element.select()})),this.focusCycler=new c.FocusCycler({focusables:this.childViews,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}})}}class h extends e.Plugin{static get requires(){return[c.ContextualBalloon]}init(){const e=this.editor,t=e.commands.get("insertCalendar"),i=e.editing.view.document,n=e.ui.componentFactory;this._balloon=e.plugins.get(c.ContextualBalloon),this.formView=this._createFormView(e.locale),n.add("calendar",(e=>{const n=new c.ButtonView(e);return n.set({label:e.t("Calendar"),icon:'\x3c!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --\x3e',tooltip:!0,isToggleable:!0}),n.bind("isEnabled").to(t,"isEnabled"),n.bind("isOn").to(t,"existingCalendarSelected"),this.listenTo(n,"execute",(()=>{this._showUI(t.existingCalendarSelected)})),this.listenTo(i,"click",(()=>{t.existingCalendarSelected&&this._showUI(t.existingCalendarSelected)})),n}))}_createFormView(e){const t=this.editor,i=new u(e);return this.listenTo(i,"submit",(()=>{t.execute("insertCalendar",{value:i.valueInputView.fieldView.element.value}),this._hideUI()})),this.listenTo(i,"cancel",(()=>this._hideUI())),(0,c.clickOutsideHandler)({emitter:i,activator:()=>this._balloon.visibleView===i,contextElements:[this._balloon.view.element],callback:()=>this._hideUI()}),i.keystrokes.set("Esc",((e,t)=>{this._hideUI(),t()})),i}_showUI(e){if(this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),e){const t=e.getAttribute("calendarQueryString");t&&"googleCalendar"===e.name&&(this.formView.value=r(t)),this.editor.model.change((t=>t.setSelection(e,"on")))}this.formView.focus()}_hideUI(){this.formView.reset(),this._balloon.remove(this.formView),this.editor.editing.view.focus()}_getBalloonPositionData(){const e=this.editor.editing.view,t=e.document;return{target:()=>e.domConverter.viewRangeToDom(t.selection.getFirstRange())}}}class m extends e.Plugin{static get requires(){return[a,h]}}const g={Calendar:m}})(),n=n.default})())); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.calendar=t())}(self,(()=>(()=>{var e=[e=>{"use strict";e.exports=CKEditor5.dll},(e,t,i)=>{e.exports=i(0)("./src/core.js")},(e,t,i)=>{e.exports=i(0)("./src/widget.js")},(e,t,i)=>{e.exports=i(0)("./src/ui.js")},,(e,t,i)=>{e.exports=i(0)("./src/utils.js")}],t={};function i(n){var s=t[n];if(void 0!==s)return s.exports;var r=t[n]={exports:{}};return e[n](r,r.exports,i),r.exports}i.d=(e,t)=>{for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n={};return(()=>{"use strict";i.d(n,{default:()=>g});var e=i(1),t=i(2);function s(e){if("<"===e[0]&&!(e=function(e){const t=(new DOMParser).parseFromString(e,"text/html").querySelector("iframe");return t?t.getAttribute("src"):null}(e)))return null;let t;try{t=new URL(e)}catch(e){return null}return t.hostname.match(/(www|calendar)\.google\.com/)&&t.pathname.match(/\/calendar\/embed\/?/)?t.searchParams.toString():null}function r(e){return"https://calendar.google.com/calendar/embed?"+e}class o extends e.Command{constructor(e){super(e),this.set("existingCalendarSelected",!1)}execute(e={value:""}){const t=e.value.trim(),i=this.editor.model;if(!t)return;let n=s(t);n&&i.change((e=>i.insertContent(e.createElement("googleCalendar",{calendarQueryString:n}))))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,i=t.getSelectedElement(),n=e.schema.findAllowedParent(t.getFirstPosition(),"googleCalendar");var s;this.isEnabled=null!==n,this.existingCalendarSelected=(s=i)&&"googleCalendar"===s.name?i:null}}class a extends e.Plugin{static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){this.editor.model.schema.register("googleCalendar",{isObject:!0,allowWhere:"$block",allowAttributes:["calendarQueryString"],allowChildren:!1})}_defineConverters(){const e=this.editor.conversion;e.attributeToAttribute({model:{key:"calendarQueryString",value:e=>e.getAttribute("data-query-string").replace(/&/g,"&")},view:"data-query-string"}),e.for("upcast").elementToElement({model:"googleCalendar",view:{name:"ucb-calendar",classes:["ucb-calendar","ucb-google-calendar"]}}),e.for("dataDowncast").elementToElement({model:"googleCalendar",view:(e,{writer:t})=>l(e,t)}),e.for("editingDowncast").elementToElement({model:"googleCalendar",view:(e,{writer:t})=>l(e,t,!0)})}_defineCommands(){this.editor.commands.add("insertCalendar",new o(this.editor))}}function l(e,i,n=!1){if(n){const n=e.getAttribute("calendarQueryString")||"";return(0,t.toWidget)(i.createContainerElement("div",{class:"ucb-calendar ucb-google-calendar"},[i.createEmptyElement("iframe",{src:r(n),loading:"lazy",referrerpolicy:"no-referrer",frameborder:"0",scrolling:"no"}),i.createEmptyElement("div",{class:"ucb-calendar-editing-cover"})]),i,{label:"calendar widget"})}return i.createContainerElement("ucb-calendar",{class:"ucb-calendar ucb-google-calendar"})}var c=i(3),d=i(5);class u extends c.View{constructor(t){super(t),this.valueInputView=this._createInput(t,"Calendar embed"),this.set("value",""),this.valueInputView.fieldView.bind("value").to(this,"value"),this.saveButtonView=this._createActionButton(t,"Save",e.icons.check,"ck-button-save"),this.cancelButtonView=this._createActionButton(t,"Cancel",e.icons.cancel,"ck-button-cancel"),this.saveButtonView.type="submit",this.cancelButtonView.delegate("execute").to(this,"cancel"),this.childViews=this.createCollection([this.valueInputView,this.saveButtonView,this.cancelButtonView]),this._enableFocusTracking(),this.setTemplate({tag:"form",attributes:{class:["ck","ck-calendar-form"],tabindex:"-1"},children:this.childViews})}render(){super.render();for(const e of this.childViews)this.focusTracker.add(e.element);(0,c.submitHandler)({view:this}),this.keystrokes.listenTo(this.element)}focus(){this.valueInputView.focus()}reset(){this.value="",this.valueInputView.fieldView.element.blur(),this.element.reset()}destroy(){this.keystrokes.destroy()}_createSelectableButton(e,t,i,n,s){const r=new c.ButtonView;return r.set({label:e.t(t),icon:i,tooltip:!!i,isToggleable:!0,withText:!i}),r.bind("isOn").to(this,n,(e=>e===s)),this.listenTo(r,"execute",(()=>{this.set(n,s)})),r}_createActionButton(e,t,i,n){const s=new c.ButtonView;return s.set({label:e.t(t),icon:i,class:n,tooltip:!!i,withText:!i}),s}_createInput(e,t){const i=new c.LabeledFieldView(e,c.createLabeledInputText);return i.label=e.t(t),i}_enableFocusTracking(){this.focusTracker=new d.FocusTracker,this.keystrokes=new d.KeystrokeHandler,this.focusTracker.on("change:focusedElement",((e,t,i)=>{i===this.valueInputView.element&&this.valueInputView.fieldView.element.select()})),this.focusCycler=new c.FocusCycler({focusables:this.childViews,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}})}}class h extends e.Plugin{static get requires(){return[c.ContextualBalloon]}init(){const e=this.editor,t=e.commands.get("insertCalendar"),i=e.editing.view.document,n=e.ui.componentFactory;this._balloon=e.plugins.get(c.ContextualBalloon),this.formView=this._createFormView(e.locale),n.add("calendar",(e=>{const n=new c.ButtonView(e);return n.set({label:e.t("Calendar"),icon:'\x3c!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --\x3e',tooltip:!0,isToggleable:!0}),n.bind("isEnabled").to(t,"isEnabled"),n.bind("isOn").to(t,"existingCalendarSelected"),this.listenTo(n,"execute",(()=>{this._showUI(t.existingCalendarSelected)})),this.listenTo(i,"click",(()=>{t.existingCalendarSelected&&this._showUI(t.existingCalendarSelected)})),n}))}_createFormView(e){const t=this.editor,i=new u(e);return this.listenTo(i,"submit",(()=>{t.execute("insertCalendar",{value:i.valueInputView.fieldView.element.value}),this._hideUI()})),this.listenTo(i,"cancel",(()=>this._hideUI())),(0,c.clickOutsideHandler)({emitter:i,activator:()=>this._balloon.visibleView===i,contextElements:[this._balloon.view.element],callback:()=>this._hideUI()}),i.keystrokes.set("Esc",((e,t)=>{this._hideUI(),t()})),i}_showUI(e){if(this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),e){const t=e.getAttribute("calendarQueryString");t&&"googleCalendar"===e.name&&(this.formView.value=r(t)),this.editor.model.change((t=>t.setSelection(e,"on")))}this.formView.focus()}_hideUI(){this.formView.reset(),this._balloon.remove(this.formView),this.editor.editing.view.focus()}_getBalloonPositionData(){const e=this.editor.editing.view,t=e.document;return{target:()=>e.domConverter.viewRangeToDom(t.selection.getFirstRange())}}}class m extends e.Plugin{static get requires(){return[a,h]}}const g={Calendar:m}})(),n=n.default})())); \ No newline at end of file diff --git a/js/build/callout.js b/js/build/callout.js index d16e2f4..f34ac2a 100644 --- a/js/build/callout.js +++ b/js/build/callout.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.callout=t())}(self,(()=>(()=>{var e=[(e,t,o)=>{e.exports=o(1)("./src/core.js")},e=>{"use strict";e.exports=CKEditor5.dll},(e,t,o)=>{e.exports=o(1)("./src/widget.js")},,(e,t,o)=>{e.exports=o(1)("./src/engine.js")},(e,t,o)=>{e.exports=o(1)("./src/ui.js")}],t={};function o(l){var n=t[l];if(void 0!==n)return n.exports;var i=t[l]={exports:{}};return e[l](i,i.exports,o),i.exports}o.d=(e,t)=>{for(var l in t)o.o(t,l)&&!o.o(e,l)&&Object.defineProperty(e,l,{enumerable:!0,get:t[l]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var l={};return(()=>{"use strict";o.d(l,{default:()=>h});var e=o(0),t=o(2);const n={medium:{label:"Medium",icon:e.icons.small,className:"feature-layout-callout-medium"},large:{label:"Large",icon:e.icons.regular,className:"feature-layout-callout-large"},xlarge:{label:"Extra Large",icon:e.icons.large,className:"feature-layout-callout-xlarge"}},i="medium";class a extends e.Command{execute(){const{model:e}=this.editor;e.change((t=>{e.insertContent(function(e){const t=e.createElement("callout",{calloutSize:i}),o=e.createElement("calloutContent");return e.append(o,t),e.appendElement("paragraph",o),t}(t))}))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,o=e.schema.findAllowedParent(t.getFirstPosition(),"callout");this.isEnabled=null!==o}}o(4);function s(e){const t=e.getFirstPosition();if(!t)return null;let o=t.parent;for(;o;){if(o.is("element")&&"callout"===o.name)return o;o=o.parent}return null}class r extends e.Command{attributeName;defaultValue;constructor(e,t,o){super(e),this.attributeName=t,this.defaultValue=o}refresh(){const e=s(this.editor.model.document.selection),t=this.attributeName,o=this.defaultValue;this.isEnabled=!!e,this.isEnabled?this.value=e.getAttribute(t):this.value=o}execute(e={value:""}){const t=this.editor.model,o=s(t.document.selection),l=this.attributeName,n=this.defaultValue;o&&t.change((t=>t.setAttribute(l,e.value||n,o)))}}class c extends e.Plugin{static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){const e=this.editor.model.schema;e.register("callout",{isObject:!0,allowWhere:"$block",allowAttributes:["calloutSize"]}),e.register("calloutContent",{isLimit:!0,allowIn:"callout",allowContentOf:"$root"}),e.addChildCheck(((e,t)=>{if(e.endsWith("calloutContent")&&"callout"===t.name)return!1}))}_defineConverters(){const{conversion:e,editing:o}=this.editor;e.attributeToAttribute(function(e,t){const o={};for(const[e,l]of Object.entries(t))o[e]={key:"class",value:l.className};return{model:{key:e,values:Object.keys(t)},view:o}}("calloutSize",n)),e.for("upcast").elementToElement({model:"callout",view:{name:"div",classes:"feature-layout-callout"}}),e.for("upcast").elementToElement({model:"calloutContent",view:{name:"div",classes:"ucb-callout-content"}}),e.for("dataDowncast").elementToElement({model:"callout",view:(e,{writer:t})=>u(t)}),e.for("dataDowncast").elementToElement({model:"calloutContent",view:{name:"div",classes:"ucb-callout-content"}}),e.for("editingDowncast").elementToElement({model:"callout",view:(e,{writer:t})=>u(t,!0)}),e.for("editingDowncast").elementToElement({model:"calloutContent",view:(e,{writer:o})=>{const l=o.createEditableElement("div",{class:"ucb-callout-content"});return(0,t.toWidgetEditable)(l,o)}})}_defineCommands(){const e=this.editor.commands;e.add("insertCallout",new a(this.editor)),e.add("modifyCalloutSize",new r(this.editor,"calloutSize",i))}}function u(e,o=!1){const l=e.createContainerElement("div",{class:"feature-layout-callout"});return o?(0,t.toWidget)(l,e,{label:"callout widget",hasSelectionHandle:!0}):l}var d=o(5);class m extends e.Plugin{static get requires(){return[t.WidgetToolbarRepository]}init(){const e=this.editor,t=e.commands,o=e.ui.componentFactory;o.add("callout",(o=>{const l=t.get("insertCallout"),n=new d.ButtonView(o);return n.set({label:o.t("Callout"),icon:'\x3c!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --\x3e',tooltip:!0}),n.bind("isOn","isEnabled").to(l,"value","isEnabled"),this.listenTo(n,"execute",(()=>e.execute("insertCallout"))),n})),o.add("calloutSize",(e=>this._createDropdown(e,"Callout size",n[i].icon,t.get("modifyCalloutSize"),n,i)))}afterInit(){this.editor.plugins.get(t.WidgetToolbarRepository).register("callout",{items:["calloutSize"],getRelatedElement:e=>e.focus?e.focus.getAncestors().find((e=>e.is("element")&&e.hasClass("feature-layout-callout"))):null})}_createDropdown(e,t,o,l,n,i){const a=(0,d.createDropdown)(e);return(0,d.addToolbarToDropdown)(a,Object.entries(n).map((([t,o])=>this._createButton(e,o.label,o.icon,l,t)))),a.buttonView.set({label:e.t(t),icon:o,tooltip:!0,withText:!o}),o===n[i].icon&&a.buttonView.bind("icon").to(l,"value",(e=>n[e]?n[e].icon:n[i].icon)),a.bind("isEnabled").to(l,"isEnabled"),a}_createButton(e,t,o,l,n){const i=this.editor,a=new d.ButtonView;return a.set({label:e.t(t),icon:o,tooltip:!0,isToggleable:!0,withText:!o}),a.bind("isEnabled").to(l),a.bind("isOn").to(l,"value",(e=>e===n)),this.listenTo(a,"execute",(()=>{l.execute({value:n}),i.editing.view.focus()})),a}}class f extends e.Plugin{static get requires(){return[c,m]}}const h={Callout:f}})(),l=l.default})())); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.callout=t())}(self,(()=>(()=>{var e=[e=>{"use strict";e.exports=CKEditor5.dll},(e,t,o)=>{e.exports=o(0)("./src/core.js")},(e,t,o)=>{e.exports=o(0)("./src/widget.js")},,(e,t,o)=>{e.exports=o(0)("./src/engine.js")},(e,t,o)=>{e.exports=o(0)("./src/ui.js")}],t={};function o(l){var n=t[l];if(void 0!==n)return n.exports;var i=t[l]={exports:{}};return e[l](i,i.exports,o),i.exports}o.d=(e,t)=>{for(var l in t)o.o(t,l)&&!o.o(e,l)&&Object.defineProperty(e,l,{enumerable:!0,get:t[l]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var l={};return(()=>{"use strict";o.d(l,{default:()=>h});var e=o(1),t=o(2);const n={medium:{label:"Medium",icon:e.icons.small,className:"feature-layout-callout-medium"},large:{label:"Large",icon:e.icons.regular,className:"feature-layout-callout-large"},xlarge:{label:"Extra Large",icon:e.icons.large,className:"feature-layout-callout-xlarge"}},i="medium";class a extends e.Command{execute(){const{model:e}=this.editor;e.change((t=>{e.insertContent(function(e){const t=e.createElement("callout",{calloutSize:i}),o=e.createElement("calloutContent");return e.append(o,t),e.appendElement("paragraph",o),t}(t))}))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,o=e.schema.findAllowedParent(t.getFirstPosition(),"callout");this.isEnabled=null!==o}}o(4);function s(e){const t=e.getFirstPosition();if(!t)return null;let o=t.parent;for(;o;){if(o.is("element")&&"callout"===o.name)return o;o=o.parent}return null}class r extends e.Command{attributeName;defaultValue;constructor(e,t,o){super(e),this.attributeName=t,this.defaultValue=o}refresh(){const e=s(this.editor.model.document.selection),t=this.attributeName,o=this.defaultValue;this.isEnabled=!!e,this.isEnabled?this.value=e.getAttribute(t):this.value=o}execute(e={value:""}){const t=this.editor.model,o=s(t.document.selection),l=this.attributeName,n=this.defaultValue;o&&t.change((t=>t.setAttribute(l,e.value||n,o)))}}class c extends e.Plugin{static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){const e=this.editor.model.schema;e.register("callout",{isObject:!0,allowWhere:"$block",allowAttributes:["calloutSize"]}),e.register("calloutContent",{isLimit:!0,allowIn:"callout",allowContentOf:"$root"}),e.addChildCheck(((e,t)=>{if(e.endsWith("calloutContent")&&"callout"===t.name)return!1}))}_defineConverters(){const{conversion:e,editing:o}=this.editor;e.attributeToAttribute(function(e,t){const o={};for(const[e,l]of Object.entries(t))o[e]={key:"class",value:l.className};return{model:{key:e,values:Object.keys(t)},view:o}}("calloutSize",n)),e.for("upcast").elementToElement({model:"callout",view:{name:"div",classes:"feature-layout-callout"}}),e.for("upcast").elementToElement({model:"calloutContent",view:{name:"div",classes:"ucb-callout-content"}}),e.for("dataDowncast").elementToElement({model:"callout",view:(e,{writer:t})=>u(t)}),e.for("dataDowncast").elementToElement({model:"calloutContent",view:{name:"div",classes:"ucb-callout-content"}}),e.for("editingDowncast").elementToElement({model:"callout",view:(e,{writer:t})=>u(t,!0)}),e.for("editingDowncast").elementToElement({model:"calloutContent",view:(e,{writer:o})=>{const l=o.createEditableElement("div",{class:"ucb-callout-content"});return(0,t.toWidgetEditable)(l,o)}})}_defineCommands(){const e=this.editor.commands;e.add("insertCallout",new a(this.editor)),e.add("modifyCalloutSize",new r(this.editor,"calloutSize",i))}}function u(e,o=!1){const l=e.createContainerElement("div",{class:"feature-layout-callout"});return o?(0,t.toWidget)(l,e,{label:"callout widget",hasSelectionHandle:!0}):l}var d=o(5);class m extends e.Plugin{static get requires(){return[t.WidgetToolbarRepository]}init(){const e=this.editor,t=e.commands,o=e.ui.componentFactory;o.add("callout",(o=>{const l=t.get("insertCallout"),n=new d.ButtonView(o);return n.set({label:o.t("Callout"),icon:'\x3c!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --\x3e',tooltip:!0}),n.bind("isOn","isEnabled").to(l,"value","isEnabled"),this.listenTo(n,"execute",(()=>e.execute("insertCallout"))),n})),o.add("calloutSize",(e=>this._createDropdown(e,"Callout size",n[i].icon,t.get("modifyCalloutSize"),n,i)))}afterInit(){this.editor.plugins.get(t.WidgetToolbarRepository).register("callout",{items:["calloutSize"],getRelatedElement:e=>e.focus?e.focus.getAncestors().find((e=>e.is("element")&&e.hasClass("feature-layout-callout"))):null})}_createDropdown(e,t,o,l,n,i){const a=(0,d.createDropdown)(e);return(0,d.addToolbarToDropdown)(a,Object.entries(n).map((([t,o])=>this._createButton(e,o.label,o.icon,l,t)))),a.buttonView.set({label:e.t(t),icon:o,tooltip:!0,withText:!o}),o===n[i].icon&&a.buttonView.bind("icon").to(l,"value",(e=>n[e]?n[e].icon:n[i].icon)),a.bind("isEnabled").to(l,"isEnabled"),a}_createButton(e,t,o,l,n){const i=this.editor,a=new d.ButtonView;return a.set({label:e.t(t),icon:o,tooltip:!0,isToggleable:!0,withText:!o}),a.bind("isEnabled").to(l),a.bind("isOn").to(l,"value",(e=>e===n)),this.listenTo(a,"execute",(()=>{l.execute({value:n}),i.editing.view.focus()})),a}}class f extends e.Plugin{static get requires(){return[c,m]}}const h={Callout:f}})(),l=l.default})())); \ No newline at end of file diff --git a/js/build/column.js b/js/build/column.js index 2107cac..b34c020 100644 --- a/js/build/column.js +++ b/js/build/column.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.column=t())}(self,(()=>(()=>{var e=[(e,t,o)=>{e.exports=o(1)("./src/core.js")},e=>{"use strict";e.exports=CKEditor5.dll},(e,t,o)=>{e.exports=o(1)("./src/widget.js")},,(e,t,o)=>{e.exports=o(1)("./src/ui.js")}],t={};function o(n){var s=t[n];if(void 0!==s)return s.exports;var i=t[n]={exports:{}};return e[n](i,i.exports,o),i.exports}o.d=(e,t)=>{for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n={};return(()=>{"use strict";o.d(n,{default:()=>g});var e=o(0),t=o(2);class s extends e.Command{execute(){const e=this.editor;e.model.change((t=>{const o=t.createElement("ucb-row"),n=t.createElement("ucb-column"),s=t.createElement("ucb-column"),i=t.createElement("paragraph"),c=t.createElement("paragraph");t.append(i,n),t.append(c,s),t.append(n,o),t.append(s,o),e.model.insertContent(o),t.setSelection(i,"in")}))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,o=e.schema.findAllowedParent(t.getFirstPosition(),"ucb-row");this.isEnabled=null!==o}}function i(e){const t=e.getSelectedElement();return t&&t.is("element")&&"ucb-row"===t.name?t:null}class c extends e.Command{execute(){const e=this.editor.model,t=i(e.document.selection);t&&e.change((e=>{const o=e.createElement("paragraph"),n=e.createElement("ucb-column");e.append(o,n),e.append(n,t),e.setSelection(o,"in")}))}refresh(){const e=i(this.editor.model.document.selection);if(e){const t=Array.from(e.getChildren()).filter((e=>e.is("element","ucb-column"))).length;this.isEnabled=t<4}else this.isEnabled=!1}}class r extends e.Command{execute(){const e=this.editor.model,t=e.document.selection.getFirstPosition().findAncestor("ucb-column");t&&e.change((e=>{e.remove(t)}))}refresh(){const e=this.editor.model.document.selection.getFirstPosition().findAncestor("ucb-column");if(e){const t=e.parent,o=Array.from(t.getChildren()).filter((e=>e.is("element","ucb-column"))).length;this.isEnabled=o>2}else this.isEnabled=!1}}class l extends e.Plugin{static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){const e=this.editor.model.schema;e.register("ucb-row",{isObject:!0,allowWhere:"$block",allowChildren:"ucb-column"}),e.register("ucb-column",{allowIn:"ucb-row",allowContentOf:"$root"}),e.addChildCheck(((e,t)=>{if((e.endsWith("boxTitle")||e.endsWith("bootstrapAccordionHeader"))&&("ucb-row"===t.name||"ucb-column"===t.name))return!1}))}_defineConverters(){const{conversion:e,editing:t}=this.editor;e.for("upcast").elementToElement({model:"ucb-row",view:{name:"div",classes:["row","ucb-column-container"]}}),e.for("upcast").elementToElement({model:"ucb-column",view:{name:"div",classes:["col","ucb-column"]}}),e.for("dataDowncast").elementToElement({model:"ucb-row",view:(e,{writer:t})=>d(t)}),e.for("dataDowncast").elementToElement({model:"ucb-column",view:(e,{writer:t})=>a(t)}),e.for("editingDowncast").elementToElement({model:"ucb-row",view:(e,{writer:t})=>d(t,!0)}),e.for("editingDowncast").elementToElement({model:"ucb-column",view:(e,{writer:t})=>a(t,!0)}),e.for("editingDowncast").add((e=>{e.on("insert:ucb-row",((e,t,o)=>{const n=o.mapper.toViewElement(t.item);o.writer.addClass("ucb-row_selected",n)}))}))}_defineCommands(){const e=this.editor.commands;e.add("insertRowWithColumns",new s(this.editor)),e.add("addColumn",new c(this.editor)),e.add("removeColumn",new r(this.editor))}}function d(e,o=!1){const n=e.createContainerElement("div",{class:"row ucb-column-container"});return o?(0,t.toWidget)(n,e,{label:"row widget",hasSelectionHandle:!0}):n}function a(e,o=!1){const n=e.createEditableElement("div",{class:"col ucb-column"});return o?(0,t.toWidgetEditable)(n,e):n}var m=o(4);class u extends e.Command{execute({position:e}){const t=this.editor.model,o=t.document.selection.getFirstPosition().findAncestor("ucb-column");o&&t.change((t=>{const n=t.createElement("ucb-column"),s=t.createElement("paragraph");t.append(s,n),"left"===e?t.insert(n,o,"before"):"right"===e&&t.insert(n,o,"after"),t.setSelection(s,"in")}))}refresh(){const e=this.editor.model.document.selection.getFirstPosition().findAncestor("ucb-column");if(e){const t=e.parent,o=Array.from(t.getChildren()).filter((e=>e.is("element","ucb-column"))).length;this.isEnabled=o<4}else this.isEnabled=!1}}class h extends e.Plugin{static get requires(){return[t.WidgetToolbarRepository]}init(){const t=this.editor,o=t.commands,n=t.ui.componentFactory;n.add("Column",(e=>{const n=new m.ButtonView(e),s=o.get("insertRowWithColumns");return n.label="Column",n.icon='\x3c!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--\x3e',n.tooltip=!0,n.withText=!1,n.isToggleable=!0,n.bind("isOn","isEnabled").to(s,"value","isEnabled"),this.listenTo(n,"execute",(()=>t.execute("insertRowWithColumns"))),n})),n.add("addColumn",(t=>this._createButton(t,"Add Column",e.icons.plus,o.get("addColumn")))),n.add("removeColumn",(t=>this._createButton(t,"Remove Column",e.icons.eraser,o.get("removeColumn")))),n.add("addColumnLeft",(e=>this._createButton(e,"Add Column Left",'\x3c!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--\x3e',o.get("addColumnPosition"),"left"))),n.add("addColumnRight",(e=>this._createButton(e,"Add Column Right",'\x3c!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--\x3e',o.get("addColumnPosition"),"right"))),t.commands.add("addColumnPosition",new u(t))}afterInit(){const e=this.editor.plugins.get(t.WidgetToolbarRepository);e.register("ucb-row",{items:["addColumn"],getRelatedElement:e=>{const t=e.getSelectedElement();if(t&&t.is("element")&&t.hasClass("ucb-column-container")){return t.childCount>5?null:t}return null}}),e.register("ucb-column",{items:["addColumnLeft","removeColumn","addColumnRight"],getRelatedElement:e=>e.focus?e.focus.getAncestors().find((e=>e.is("element")&&e.hasClass("ucb-column"))):null})}_createButton(e,t,o,n,s){const i=new m.ButtonView(e);return i.set({label:t,icon:o,tooltip:!0,withText:!o}),s?(i.bind("isEnabled").to(n,"isEnabled"),this.listenTo(i,"execute",(()=>{this.editor.execute("addColumnPosition",{position:s}),this.editor.editing.view.focus()}))):(i.bind("isEnabled").to(n,"isEnabled"),this.listenTo(i,"execute",(()=>{n.execute(),this.editor.editing.view.focus()}))),i}}class w extends e.Plugin{static get requires(){return[l,h]}static get pluginName(){return"Column"}}const g={Column:w}})(),n=n.default})())); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.column=t())}(self,(()=>(()=>{var e=[e=>{"use strict";e.exports=CKEditor5.dll},(e,t,o)=>{e.exports=o(0)("./src/core.js")},(e,t,o)=>{e.exports=o(0)("./src/widget.js")},,(e,t,o)=>{e.exports=o(0)("./src/ui.js")}],t={};function o(n){var s=t[n];if(void 0!==s)return s.exports;var i=t[n]={exports:{}};return e[n](i,i.exports,o),i.exports}o.d=(e,t)=>{for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n={};return(()=>{"use strict";o.d(n,{default:()=>g});var e=o(1),t=o(2);class s extends e.Command{execute(){const e=this.editor;e.model.change((t=>{const o=t.createElement("ucb-row"),n=t.createElement("ucb-column"),s=t.createElement("ucb-column"),i=t.createElement("paragraph"),c=t.createElement("paragraph");t.append(i,n),t.append(c,s),t.append(n,o),t.append(s,o),e.model.insertContent(o),t.setSelection(i,"in")}))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,o=e.schema.findAllowedParent(t.getFirstPosition(),"ucb-row");this.isEnabled=null!==o}}function i(e){const t=e.getSelectedElement();return t&&t.is("element")&&"ucb-row"===t.name?t:null}class c extends e.Command{execute(){const e=this.editor.model,t=i(e.document.selection);t&&e.change((e=>{const o=e.createElement("paragraph"),n=e.createElement("ucb-column");e.append(o,n),e.append(n,t),e.setSelection(o,"in")}))}refresh(){const e=i(this.editor.model.document.selection);if(e){const t=Array.from(e.getChildren()).filter((e=>e.is("element","ucb-column"))).length;this.isEnabled=t<4}else this.isEnabled=!1}}class r extends e.Command{execute(){const e=this.editor.model,t=e.document.selection.getFirstPosition().findAncestor("ucb-column");t&&e.change((e=>{e.remove(t)}))}refresh(){const e=this.editor.model.document.selection.getFirstPosition().findAncestor("ucb-column");if(e){const t=e.parent,o=Array.from(t.getChildren()).filter((e=>e.is("element","ucb-column"))).length;this.isEnabled=o>2}else this.isEnabled=!1}}class l extends e.Plugin{static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){const e=this.editor.model.schema;e.register("ucb-row",{isObject:!0,allowWhere:"$block",allowChildren:"ucb-column"}),e.register("ucb-column",{allowIn:"ucb-row",allowContentOf:"$root"}),e.addChildCheck(((e,t)=>{if((e.endsWith("boxTitle")||e.endsWith("bootstrapAccordionHeader"))&&("ucb-row"===t.name||"ucb-column"===t.name))return!1}))}_defineConverters(){const{conversion:e,editing:t}=this.editor;e.for("upcast").elementToElement({model:"ucb-row",view:{name:"div",classes:["row","ucb-column-container"]}}),e.for("upcast").elementToElement({model:"ucb-column",view:{name:"div",classes:["col","ucb-column"]}}),e.for("dataDowncast").elementToElement({model:"ucb-row",view:(e,{writer:t})=>d(t)}),e.for("dataDowncast").elementToElement({model:"ucb-column",view:(e,{writer:t})=>a(t)}),e.for("editingDowncast").elementToElement({model:"ucb-row",view:(e,{writer:t})=>d(t,!0)}),e.for("editingDowncast").elementToElement({model:"ucb-column",view:(e,{writer:t})=>a(t,!0)}),e.for("editingDowncast").add((e=>{e.on("insert:ucb-row",((e,t,o)=>{const n=o.mapper.toViewElement(t.item);o.writer.addClass("ucb-row_selected",n)}))}))}_defineCommands(){const e=this.editor.commands;e.add("insertRowWithColumns",new s(this.editor)),e.add("addColumn",new c(this.editor)),e.add("removeColumn",new r(this.editor))}}function d(e,o=!1){const n=e.createContainerElement("div",{class:"row ucb-column-container"});return o?(0,t.toWidget)(n,e,{label:"row widget",hasSelectionHandle:!0}):n}function a(e,o=!1){const n=e.createEditableElement("div",{class:"col ucb-column"});return o?(0,t.toWidgetEditable)(n,e):n}var m=o(4);class u extends e.Command{execute({position:e}){const t=this.editor.model,o=t.document.selection.getFirstPosition().findAncestor("ucb-column");o&&t.change((t=>{const n=t.createElement("ucb-column"),s=t.createElement("paragraph");t.append(s,n),"left"===e?t.insert(n,o,"before"):"right"===e&&t.insert(n,o,"after"),t.setSelection(s,"in")}))}refresh(){const e=this.editor.model.document.selection.getFirstPosition().findAncestor("ucb-column");if(e){const t=e.parent,o=Array.from(t.getChildren()).filter((e=>e.is("element","ucb-column"))).length;this.isEnabled=o<4}else this.isEnabled=!1}}class h extends e.Plugin{static get requires(){return[t.WidgetToolbarRepository]}init(){const t=this.editor,o=t.commands,n=t.ui.componentFactory;n.add("Column",(e=>{const n=new m.ButtonView(e),s=o.get("insertRowWithColumns");return n.label="Column",n.icon='\x3c!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--\x3e',n.tooltip=!0,n.withText=!1,n.isToggleable=!0,n.bind("isOn","isEnabled").to(s,"value","isEnabled"),this.listenTo(n,"execute",(()=>t.execute("insertRowWithColumns"))),n})),n.add("addColumn",(t=>this._createButton(t,"Add Column",e.icons.plus,o.get("addColumn")))),n.add("removeColumn",(t=>this._createButton(t,"Remove Column",e.icons.eraser,o.get("removeColumn")))),n.add("addColumnLeft",(e=>this._createButton(e,"Add Column Left",'\x3c!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--\x3e',o.get("addColumnPosition"),"left"))),n.add("addColumnRight",(e=>this._createButton(e,"Add Column Right",'\x3c!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--\x3e',o.get("addColumnPosition"),"right"))),t.commands.add("addColumnPosition",new u(t))}afterInit(){const e=this.editor.plugins.get(t.WidgetToolbarRepository);e.register("ucb-row",{items:["addColumn"],getRelatedElement:e=>{const t=e.getSelectedElement();if(t&&t.is("element")&&t.hasClass("ucb-column-container")){return t.childCount>5?null:t}return null}}),e.register("ucb-column",{items:["addColumnLeft","removeColumn","addColumnRight"],getRelatedElement:e=>e.focus?e.focus.getAncestors().find((e=>e.is("element")&&e.hasClass("ucb-column"))):null})}_createButton(e,t,o,n,s){const i=new m.ButtonView(e);return i.set({label:t,icon:o,tooltip:!0,withText:!o}),s?(i.bind("isEnabled").to(n,"isEnabled"),this.listenTo(i,"execute",(()=>{this.editor.execute("addColumnPosition",{position:s}),this.editor.editing.view.focus()}))):(i.bind("isEnabled").to(n,"isEnabled"),this.listenTo(i,"execute",(()=>{n.execute(),this.editor.editing.view.focus()}))),i}}class w extends e.Plugin{static get requires(){return[l,h]}static get pluginName(){return"Column"}}const g={Column:w}})(),n=n.default})())); \ No newline at end of file diff --git a/js/build/countdown.js b/js/build/countdown.js index 308e6ef..b6dda79 100644 --- a/js/build/countdown.js +++ b/js/build/countdown.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.countdown=t())}(self,(()=>(()=>{var e=[(e,t,o)=>{e.exports=o(1)("./src/core.js")},e=>{"use strict";e.exports=CKEditor5.dll},(e,t,o)=>{e.exports=o(1)("./src/ui.js")},,(e,t,o)=>{e.exports=o(1)("./src/widget.js")},(e,t,o)=>{e.exports=o(1)("./src/utils.js")}],t={};function o(n){var i=t[n];if(void 0!==i)return i.exports;var s=t[n]={exports:{}};return e[n](s,s.exports,o),s.exports}o.d=(e,t)=>{for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n={};return(()=>{"use strict";o.d(n,{default:()=>p});var e=o(0);const t={solid:{label:"Solid",className:"countdown-solid"},transparent:{label:"Transparent",className:"countdown-transparent"}},i="transparent",s={inline:{label:"Inline",className:"countdown-inline"},stacked:{label:"Stacked",className:"countdown-stacked"}},c="inline";class a extends e.Command{constructor(e){super(e),this.set("existingCountdownSelected",!1)}execute({style:e=c,background:t=i,date:o}){const n=this.editor.model,s=n.document.selection;n.change((i=>{s.getFirstRange();const c=i.createElement("cuCountdown",{cuCountdownBackground:t,cuCountdownStyle:e});i.insert(o,c),n.insertContent(c)}))}refresh(){const e=this.editor.model,t=e.document.selection,o=t.getSelectedElement(),n=e.schema.findAllowedParent(t.getFirstPosition(),"cuCountdown");var i;this.isEnabled=null!==n,this.existingCountdownSelected=(i=o)&&"cuCountdown"===i.name?o:null}}var r=o(4);class l extends e.Plugin{static get requires(){return[r.Widget]}init(){this._defineSchema(),this._defineConverters(),this.editor.commands.add("addCountdown",new a(this.editor))}_defineSchema(){this.editor.model.schema.register("cuCountdown",{allowWhere:"$text",isObject:!0,isInline:!0,allowAttributes:["cuCountdownBackground","cuCountdownStyle","aria-hidden"],allowContentOf:"$block"})}_defineConverters(){const{conversion:e}=this.editor;e.attributeToAttribute(d("cuCountdownBackground",t)),e.attributeToAttribute(d("cuCountdownStyle",s)),e.for("upcast").elementToElement({model:"cuCountdown",view:{name:"span",classes:"ucb-countdown"}}),e.for("dataDowncast").elementToElement({model:"cuCountdown",view:{name:"span",classes:"ucb-countdown",attributes:{"aria-hidden":"true"}}}),e.for("editingDowncast").elementToElement({model:"cuCountdown",view:(e,{writer:t})=>(0,r.toWidget)(t.createContainerElement("span",{class:"ucb-countdown",attributes:{"aria-hidden":"true"}}),t,{label:"Countdown Widget"})})}}function d(e,t){const o={};for(const[e,n]of Object.entries(t))o[e]={key:"class",value:n.className};return{model:{key:e,values:Object.keys(t)},view:o}}var u=o(2),w=o(5);class h extends u.View{constructor(o,n){super(o),this.focusTracker=new w.FocusTracker,this.keystrokes=new w.KeystrokeHandler,this.backgroundDropdown=this._createSelectionDropdown(o,"Background",'\x3c!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --\x3e\n',"background",t,i),this.styleDropdown=this._createSelectionDropdown(o,"Style",e.icons.objectInline,"style",s,c),this.dateInputView=this._createInput("Add Date (MM/DD/YYYY hh:mm:ss)"),this.set("background",i),this.set("style",c),this.dateInputView.fieldView.bind("date").to(this,"date"),this.set("date","MM/DD/YYYY hh:mm:ss"),this.saveButtonView=this._createButton("Save",e.icons.check,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton("Cancel",e.icons.cancel,"ck-button-cancel"),this.cancelButtonView.delegate("execute").to(this,"cancel"),this.childViews=this.createCollection([this.backgroundDropdown,this.styleDropdown,this.dateInputView,this.saveButtonView,this.cancelButtonView]),this._focusCycler=new u.FocusCycler({focusables:this.childViews,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-countdown-form"],tabindex:"-1"},children:this.childViews})}render(){super.render(),(0,u.submitHandler)({view:this}),this.childViews._items.forEach((e=>{this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this.dateInputView.isEnabled,this.dateInputView.focus()}_createInput(e){const t=new u.LabeledFieldView(this.locale,u.createLabeledInputText);return t.label=e,t}_createButton(e,t,o){const n=new u.ButtonView;return n.set({label:e,icon:t,tooltip:!0,class:o}),n}_createSelectionDropdown(e,t,o,n,i,s){const c=(0,u.createDropdown)(e),a=i[s];return(0,u.addToolbarToDropdown)(c,Object.entries(i).map((([t,o])=>this._createSelectableButton(e,o.label,o.icon,n,t)))),c.buttonView.set({icon:o,tooltip:e.t(t),withText:!o}),c.buttonView.bind("label").to(this,n,(t=>e.t(i[t]?i[t].label:a.label))),o===i[s].icon&&c.buttonView.bind("icon").to(this,n,(e=>i[e]?i[e].icon:a.icon)),c}_createSelectableButton(e,t,o,n,i){const s=new u.ButtonView;return s.set({label:e.t(t),icon:o,tooltip:!!o,isToggleable:!0,withText:!o}),s.bind("isOn").to(this,n,(e=>e===i)),this.listenTo(s,"execute",(()=>{this.set(n,i)})),s}}class m extends e.Plugin{static get requires(){return[u.ContextualBalloon]}static get pluginName(){return"CountdownUI"}init(){const e=this.editor,t=e.ui.componentFactory,o=e.commands.get("addCountdown"),n=e.editing.view.document;this._balloon=this.editor.plugins.get(u.ContextualBalloon),this.formView=this._createFormView(e.locale),this.buttonView=null,t.add("countdown",(e=>{const t=new u.ButtonView(e);t.label="Countdown",t.icon='\x3c!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --\x3e',t.tooltip=!0,t.withText=!1,t.isToggleable=!0,this.listenTo(t,"execute",(()=>{this._showUI(o.existingCountdownSelected)})),this.buttonView=t;const i=()=>{const e=o.existingCountdownSelected;t.isOn=!!e};return this.listenTo(o,"change:value",i),this.listenTo(o,"change:existingCountdownSelected",i),this.listenTo(n,"click",(()=>{o.existingCountdownSelected&&this._showUI(o.existingCountdownSelected)})),this.on("showUI",((e,t)=>{this._showUI(t)})),t.bind("isOn","isEnabled").to(o,"value","isEnabled"),t}))}_createFormView(e){const t=this.editor,o=t.ui.componentFactory,n=new h(e,o);return this.listenTo(n,"submit",(()=>{const e={date:n.dateInputView.fieldView.element.value,background:n.background,style:n.style};t.execute("addCountdown",e),this._hideUI()})),this.listenTo(n,"cancel",(()=>{this._hideUI()})),n.keystrokes.set("Esc",((e,t)=>{this._hideUI(),t()})),(0,u.clickOutsideHandler)({emitter:n,activator:()=>this._balloon.visibleView===n,contextElements:[this._balloon.view.element],callback:()=>this._hideUI()}),n}_showUI(e){this.buttonView.isOn=!0,this._balloon.visibleView&&this._hideUI();const t=this.editor.commands.get("addCountdown").value;if(this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),e){const t=e.getAttribute("cuCountdownBackground"),o=e.getAttribute("cuCountdownStyle"),n=e.getChild(0);if(n&&n.data){const e=n.data;this.formView.background=t,this.formView.style=o,this.formView.dateInputView.fieldView.value=e,this.formView.dateInputView.fieldView.element.value=e,this.formView.dateInputView.fieldView.set("value",e)}}t&&(this.formView.dateInputView.fieldView.value=t.date,this.formView.backgroundDropdown.fieldView.value=t.background,this.formView.styleDropdown.fieldView.value=t.style),setTimeout((()=>{this.formView.dateInputView.fieldView.focus()}),0)}_hideUI(){this._balloon.hasView(this.formView)&&(this.formView.element.reset(),this.buttonView.isOn=!1,this._balloon.remove(this.formView),this.editor.editing.view.focus())}_getBalloonPositionData(){const e=this.editor.editing.view,t=e.document;let o=null;return o=()=>e.domConverter.viewRangeToDom(t.selection.getFirstRange()),{target:o}}}class b extends e.Plugin{static get requires(){return[l,m]}}const p={Countdown:b}})(),n=n.default})())); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.countdown=t())}(self,(()=>(()=>{var e=[e=>{"use strict";e.exports=CKEditor5.dll},(e,t,o)=>{e.exports=o(0)("./src/core.js")},(e,t,o)=>{e.exports=o(0)("./src/ui.js")},,(e,t,o)=>{e.exports=o(0)("./src/widget.js")},(e,t,o)=>{e.exports=o(0)("./src/utils.js")}],t={};function o(n){var i=t[n];if(void 0!==i)return i.exports;var s=t[n]={exports:{}};return e[n](s,s.exports,o),s.exports}o.d=(e,t)=>{for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n={};return(()=>{"use strict";o.d(n,{default:()=>p});var e=o(1);const t={solid:{label:"Solid",className:"countdown-solid"},transparent:{label:"Transparent",className:"countdown-transparent"}},i="transparent",s={inline:{label:"Inline",className:"countdown-inline"},stacked:{label:"Stacked",className:"countdown-stacked"}},c="inline";class a extends e.Command{constructor(e){super(e),this.set("existingCountdownSelected",!1)}execute({style:e=c,background:t=i,date:o}){const n=this.editor.model,s=n.document.selection;n.change((i=>{s.getFirstRange();const c=i.createElement("cuCountdown",{cuCountdownBackground:t,cuCountdownStyle:e});i.insert(o,c),n.insertContent(c)}))}refresh(){const e=this.editor.model,t=e.document.selection,o=t.getSelectedElement(),n=e.schema.findAllowedParent(t.getFirstPosition(),"cuCountdown");var i;this.isEnabled=null!==n,this.existingCountdownSelected=(i=o)&&"cuCountdown"===i.name?o:null}}var r=o(4);class l extends e.Plugin{static get requires(){return[r.Widget]}init(){this._defineSchema(),this._defineConverters(),this.editor.commands.add("addCountdown",new a(this.editor))}_defineSchema(){this.editor.model.schema.register("cuCountdown",{allowWhere:"$text",isObject:!0,isInline:!0,allowAttributes:["cuCountdownBackground","cuCountdownStyle","aria-hidden"],allowContentOf:"$block"})}_defineConverters(){const{conversion:e}=this.editor;e.attributeToAttribute(d("cuCountdownBackground",t)),e.attributeToAttribute(d("cuCountdownStyle",s)),e.for("upcast").elementToElement({model:"cuCountdown",view:{name:"span",classes:"ucb-countdown"}}),e.for("dataDowncast").elementToElement({model:"cuCountdown",view:{name:"span",classes:"ucb-countdown",attributes:{"aria-hidden":"true"}}}),e.for("editingDowncast").elementToElement({model:"cuCountdown",view:(e,{writer:t})=>(0,r.toWidget)(t.createContainerElement("span",{class:"ucb-countdown",attributes:{"aria-hidden":"true"}}),t,{label:"Countdown Widget"})})}}function d(e,t){const o={};for(const[e,n]of Object.entries(t))o[e]={key:"class",value:n.className};return{model:{key:e,values:Object.keys(t)},view:o}}var u=o(2),w=o(5);class h extends u.View{constructor(o,n){super(o),this.focusTracker=new w.FocusTracker,this.keystrokes=new w.KeystrokeHandler,this.backgroundDropdown=this._createSelectionDropdown(o,"Background",'\x3c!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --\x3e\n',"background",t,i),this.styleDropdown=this._createSelectionDropdown(o,"Style",e.icons.objectInline,"style",s,c),this.dateInputView=this._createInput("Add Date (MM/DD/YYYY hh:mm:ss)"),this.set("background",i),this.set("style",c),this.dateInputView.fieldView.bind("date").to(this,"date"),this.set("date","MM/DD/YYYY hh:mm:ss"),this.saveButtonView=this._createButton("Save",e.icons.check,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton("Cancel",e.icons.cancel,"ck-button-cancel"),this.cancelButtonView.delegate("execute").to(this,"cancel"),this.childViews=this.createCollection([this.backgroundDropdown,this.styleDropdown,this.dateInputView,this.saveButtonView,this.cancelButtonView]),this._focusCycler=new u.FocusCycler({focusables:this.childViews,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-countdown-form"],tabindex:"-1"},children:this.childViews})}render(){super.render(),(0,u.submitHandler)({view:this}),this.childViews._items.forEach((e=>{this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this.dateInputView.isEnabled,this.dateInputView.focus()}_createInput(e){const t=new u.LabeledFieldView(this.locale,u.createLabeledInputText);return t.label=e,t}_createButton(e,t,o){const n=new u.ButtonView;return n.set({label:e,icon:t,tooltip:!0,class:o}),n}_createSelectionDropdown(e,t,o,n,i,s){const c=(0,u.createDropdown)(e),a=i[s];return(0,u.addToolbarToDropdown)(c,Object.entries(i).map((([t,o])=>this._createSelectableButton(e,o.label,o.icon,n,t)))),c.buttonView.set({icon:o,tooltip:e.t(t),withText:!o}),c.buttonView.bind("label").to(this,n,(t=>e.t(i[t]?i[t].label:a.label))),o===i[s].icon&&c.buttonView.bind("icon").to(this,n,(e=>i[e]?i[e].icon:a.icon)),c}_createSelectableButton(e,t,o,n,i){const s=new u.ButtonView;return s.set({label:e.t(t),icon:o,tooltip:!!o,isToggleable:!0,withText:!o}),s.bind("isOn").to(this,n,(e=>e===i)),this.listenTo(s,"execute",(()=>{this.set(n,i)})),s}}class m extends e.Plugin{static get requires(){return[u.ContextualBalloon]}static get pluginName(){return"CountdownUI"}init(){const e=this.editor,t=e.ui.componentFactory,o=e.commands.get("addCountdown"),n=e.editing.view.document;this._balloon=this.editor.plugins.get(u.ContextualBalloon),this.formView=this._createFormView(e.locale),this.buttonView=null,t.add("countdown",(e=>{const t=new u.ButtonView(e);t.label="Countdown",t.icon='\x3c!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --\x3e',t.tooltip=!0,t.withText=!1,t.isToggleable=!0,this.listenTo(t,"execute",(()=>{this._showUI(o.existingCountdownSelected)})),this.buttonView=t;const i=()=>{const e=o.existingCountdownSelected;t.isOn=!!e};return this.listenTo(o,"change:value",i),this.listenTo(o,"change:existingCountdownSelected",i),this.listenTo(n,"click",(()=>{o.existingCountdownSelected&&this._showUI(o.existingCountdownSelected)})),this.on("showUI",((e,t)=>{this._showUI(t)})),t.bind("isOn","isEnabled").to(o,"value","isEnabled"),t}))}_createFormView(e){const t=this.editor,o=t.ui.componentFactory,n=new h(e,o);return this.listenTo(n,"submit",(()=>{const e={date:n.dateInputView.fieldView.element.value,background:n.background,style:n.style};t.execute("addCountdown",e),this._hideUI()})),this.listenTo(n,"cancel",(()=>{this._hideUI()})),n.keystrokes.set("Esc",((e,t)=>{this._hideUI(),t()})),(0,u.clickOutsideHandler)({emitter:n,activator:()=>this._balloon.visibleView===n,contextElements:[this._balloon.view.element],callback:()=>this._hideUI()}),n}_showUI(e){this.buttonView.isOn=!0,this._balloon.visibleView&&this._hideUI();const t=this.editor.commands.get("addCountdown").value;if(this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),e){const t=e.getAttribute("cuCountdownBackground"),o=e.getAttribute("cuCountdownStyle"),n=e.getChild(0);if(n&&n.data){const e=n.data;this.formView.background=t,this.formView.style=o,this.formView.dateInputView.fieldView.value=e,this.formView.dateInputView.fieldView.element.value=e,this.formView.dateInputView.fieldView.set("value",e)}}t&&(this.formView.dateInputView.fieldView.value=t.date,this.formView.backgroundDropdown.fieldView.value=t.background,this.formView.styleDropdown.fieldView.value=t.style),setTimeout((()=>{this.formView.dateInputView.fieldView.focus()}),0)}_hideUI(){this._balloon.hasView(this.formView)&&(this.formView.element.reset(),this.buttonView.isOn=!1,this._balloon.remove(this.formView),this.editor.editing.view.focus())}_getBalloonPositionData(){const e=this.editor.editing.view,t=e.document;let o=null;return o=()=>e.domConverter.viewRangeToDom(t.selection.getFirstRange()),{target:o}}}class b extends e.Plugin{static get requires(){return[l,m]}}const p={Countdown:b}})(),n=n.default})())); \ No newline at end of file diff --git a/js/build/cuiconextras.js b/js/build/cuiconextras.js index 06249a1..cd4d3ae 100644 --- a/js/build/cuiconextras.js +++ b/js/build/cuiconextras.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.cuiconextras=t())}(self,(()=>(()=>{var e=[(e,t,o)=>{e.exports=o(2)("./src/core.js")},function(e,t,o){"use strict";var c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.backgroundStyleDefault=t.backgroundStyleOptions=t.colorDefault=t.colorOptions=void 0;const n=c(o(10)),i=c(o(11)),s=c(o(12)),l=c(o(13));t.colorOptions={none:{label:"Same as text"},black:{label:"Black",className:"ucb-icon-color-black"},white:{label:"White",className:"ucb-icon-color-white"},lightGray:{label:"Light Gray",className:"ucb-icon-color-lightgray"},gray:{label:"Gray",className:"ucb-icon-color-gray"},darkGray:{label:"Dark Gray",className:"ucb-icon-color-darkgray"},gold:{label:"Gold",className:"ucb-icon-color-gold"}},t.colorDefault="none",t.backgroundStyleOptions={none:{label:"No background",icon:n.default},square:{label:"Square",icon:i.default,className:"ucb-icon-style-square"},squareRounded:{label:"Rounded Square",icon:s.default,className:"ucb-icon-style-square-rounded"},circle:{label:"Circle",icon:l.default,className:"ucb-icon-style-circle"}},t.backgroundStyleDefault="none"},e=>{"use strict";e.exports=CKEditor5.dll},function(e,t,o){"use strict";var c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const n=c(o(4));t.default={CUIconExtras:n.default}},function(e,t,o){"use strict";var c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const n=c(o(5)),i=c(o(6)),s=o(0);class l extends s.Plugin{static get requires(){return[n.default,i.default]}}t.default=l},function(e,t,o){"use strict";var c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const n=o(0),i=o(7),s=c(o(8)),l=o(1);class r extends n.Plugin{static get requires(){return[i.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){this.editor.model.schema.extend("icon",{allowAttributes:["iconCUColor","iconCUBackgroundStyle"]})}_defineConverters(){const{conversion:e}=this.editor;e.attributeToAttribute(a("iconCUColor",l.colorOptions)),e.attributeToAttribute(a("iconCUBackgroundStyle",l.backgroundStyleOptions))}_defineCommands(){const e=this.editor.commands;e.add("changeIconCUColor",new s.default(this.editor,"iconCUColor",l.colorDefault)),e.add("changeIconCUBackgroundStyle",new s.default(this.editor,"iconCUBackgroundStyle",l.backgroundStyleDefault))}}function a(e,t){const o={},c=[];for(const[e,n]of Object.entries(t))n.className&&(c.push(e),o[e]={key:"class",value:n.className});return{model:{key:e,values:c},view:o}}t.default=r},function(e,t,o){"use strict";var c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const n=o(14),i=o(1),s=o(0),l=o(7),r=c(o(15));class a extends s.Plugin{static get requires(){return[l.WidgetToolbarRepository]}init(){const e=this.editor,t=e.commands,o=e.ui.componentFactory;o.add("iconCUColor",(e=>u(e,"Icon theme color",r.default,t.get("changeIconCUColor"),i.colorOptions,i.colorDefault))),o.add("iconCUBackgroundStyle",(e=>u(e,"Icon background style",i.backgroundStyleOptions[i.backgroundStyleDefault].icon,t.get("changeIconCUBackgroundStyle"),i.backgroundStyleOptions,i.backgroundStyleDefault))),e.config.set("icon.toolbarItems",["iconSize","iconAlignment","iconStyle","iconCUColor","iconCUBackgroundStyle"])}}function u(e,t,o,c,i,s){const l=(0,n.createDropdown)(e),r=l.buttonView,a=e.t;return(0,n.addToolbarToDropdown)(l,Object.entries(i).map((([t,o])=>function(e,t,o,c,i){const s=c.editor,l=function(e,t,o,c,i){const s=new n.ButtonView(e);return s.set({label:"string"==typeof i?i:t,icon:o,tooltip:!!o&&t,withText:i||!o,class:c}),s}(e,t,o);return l.tooltip=!!o,l.isToggleable=!0,l.bind("isEnabled").to(c),l.bind("isOn").to(c,"value",(e=>e===i)),l.on("execute",(()=>{c.execute({value:i}),s.editing.view.focus()})),l}(e,o.label,o.icon,c,t)))),r.set({label:a(t),icon:o,tooltip:a(t),withText:!o,class:"ck-dropdown__button_label-width_auto"}),o===i[s].icon&&c.on("change:value",((e,t,o)=>{const c=i[o];r.label=a(c.label),r.icon&&!c.icon?r.children.remove(r.iconView):!r.icon&&c.icon&&r.children.add(r.iconView,0),r.icon=c.icon,r.withText=!c.icon})),l.bind("isEnabled").to(c,"isEnabled"),l}t.default=a},(e,t,o)=>{e.exports=o(2)("./src/widget.js")},(e,t,o)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const c=o(0),n=o(9);class i extends c.Command{constructor(e,t,o){super(e),this.iconWidget=null,this.attributeName=t,this.defaultValue=o,this.value=o}refresh(){const e=this.editor.model,t=this.attributeName,o=this.defaultValue;this.iconWidget=(0,n.getSelectedIconWidget)(e.document.selection),this.isEnabled=!!this.iconWidget,this.isEnabled?this.value=this.iconWidget.hasAttribute(t)?this.iconWidget.getAttribute(t):o:this.value=o}execute(e={value:this.defaultValue}){const t=this.editor.model,o=this.iconWidget,c=this.attributeName,n=this.defaultValue;o&&t.change((t=>t.setAttribute(c,e.value||n,o)))}}t.default=i},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getSelectedIconWidget=void 0,t.getSelectedIconWidget=function(e){const t=e.getSelectedElement();return t&&t.is("element")&&"icon"===t.name?t:null}},(e,t,o)=>{"use strict";o.r(t),o.d(t,{default:()=>c});const c=''},(e,t,o)=>{"use strict";o.r(t),o.d(t,{default:()=>c});const c=''},(e,t,o)=>{"use strict";o.r(t),o.d(t,{default:()=>c});const c=''},(e,t,o)=>{"use strict";o.r(t),o.d(t,{default:()=>c});const c=''},(e,t,o)=>{e.exports=o(2)("./src/ui.js")},(e,t,o)=>{"use strict";o.r(t),o.d(t,{default:()=>c});const c='\x3c!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --\x3e'}],t={};function o(c){var n=t[c];if(void 0!==n)return n.exports;var i=t[c]={exports:{}};return e[c].call(i.exports,i,i.exports,o),i.exports}o.d=(e,t)=>{for(var c in t)o.o(t,c)&&!o.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:t[c]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var c=o(3);return c=c.default})())); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.cuiconextras=t())}(self,(()=>(()=>{var e=[(e,t,o)=>{e.exports=o(2)("./src/core.js")},function(e,t,o){"use strict";var c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.backgroundStyleDefault=t.backgroundStyleOptions=t.colorDefault=t.colorOptions=void 0;const n=c(o(10)),i=c(o(11)),s=c(o(12)),l=c(o(13));t.colorOptions={none:{label:"Same as text"},black:{label:"Black",className:"ucb-icon-color-black"},white:{label:"White",className:"ucb-icon-color-white"},lightGray:{label:"Light Gray",className:"ucb-icon-color-lightgray"},gray:{label:"Gray",className:"ucb-icon-color-gray"},darkGray:{label:"Dark Gray",className:"ucb-icon-color-darkgray"},gold:{label:"Gold",className:"ucb-icon-color-gold"}},t.colorDefault="none",t.backgroundStyleOptions={none:{label:"No background",icon:n.default},square:{label:"Square",icon:i.default,className:"ucb-icon-style-square"},squareRounded:{label:"Rounded Square",icon:s.default,className:"ucb-icon-style-square-rounded"},circle:{label:"Circle",icon:l.default,className:"ucb-icon-style-circle"}},t.backgroundStyleDefault="none"},e=>{"use strict";e.exports=CKEditor5.dll},function(e,t,o){"use strict";var c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const n=c(o(4));t.default={CUIconExtras:n.default}},function(e,t,o){"use strict";var c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const n=c(o(5)),i=c(o(6)),s=o(0);class l extends s.Plugin{static get requires(){return[n.default,i.default]}}t.default=l},function(e,t,o){"use strict";var c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const n=o(0),i=o(7),s=c(o(8)),l=o(1);class r extends n.Plugin{static get requires(){return[i.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){this.editor.model.schema.extend("icon",{allowAttributes:["iconCUColor","iconCUBackgroundStyle"]})}_defineConverters(){const{conversion:e}=this.editor;e.attributeToAttribute(a("iconCUColor",l.colorOptions)),e.attributeToAttribute(a("iconCUBackgroundStyle",l.backgroundStyleOptions))}_defineCommands(){const e=this.editor.commands;e.add("changeIconCUColor",new s.default(this.editor,"iconCUColor",l.colorDefault)),e.add("changeIconCUBackgroundStyle",new s.default(this.editor,"iconCUBackgroundStyle",l.backgroundStyleDefault))}}function a(e,t){const o={},c=[];for(const[e,n]of Object.entries(t))n.className&&(c.push(e),o[e]={key:"class",value:n.className});return{model:{key:e,values:c},view:o}}t.default=r},function(e,t,o){"use strict";var c=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});const n=o(14),i=o(1),s=o(0),l=o(7),r=c(o(15));class a extends s.Plugin{static get requires(){return[l.WidgetToolbarRepository]}init(){const e=this.editor,t=e.commands,o=e.ui.componentFactory;o.add("iconCUColor",(e=>u(e,"Icon theme color",r.default,t.get("changeIconCUColor"),i.colorOptions,i.colorDefault))),o.add("iconCUBackgroundStyle",(e=>u(e,"Icon background style",i.backgroundStyleOptions[i.backgroundStyleDefault].icon,t.get("changeIconCUBackgroundStyle"),i.backgroundStyleOptions,i.backgroundStyleDefault))),e.config.set("icon.toolbarItems",["iconSize","iconAlignment","iconStyle","iconCUColor","iconCUBackgroundStyle"])}}function u(e,t,o,c,i,s){const l=(0,n.createDropdown)(e),r=l.buttonView,a=e.t;return(0,n.addToolbarToDropdown)(l,Object.entries(i).map((([t,o])=>function(e,t,o,c,i){const s=c.editor,l=function(e,t,o,c,i){const s=new n.ButtonView(e);return s.set({label:"string"==typeof i?i:t,icon:o,tooltip:!!o&&t,withText:i||!o,class:c}),s}(e,t,o);return l.tooltip=!!o,l.isToggleable=!0,l.bind("isEnabled").to(c),l.bind("isOn").to(c,"value",(e=>e===i)),l.on("execute",(()=>{c.execute({value:i}),s.editing.view.focus()})),l}(e,o.label,o.icon,c,t)))),r.set({label:a(t),icon:o,tooltip:a(t),withText:!o,class:"ck-dropdown__button_label-width_auto"}),o===i[s].icon&&c.on("change:value",((e,t,o)=>{const c=i[o];r.label=a(c.label),r.icon&&!c.icon?r.children.remove(r.iconView):!r.icon&&c.icon&&r.children.add(r.iconView,0),r.icon=c.icon,r.withText=!c.icon})),l.bind("isEnabled").to(c,"isEnabled"),l}t.default=a},(e,t,o)=>{e.exports=o(2)("./src/widget.js")},(e,t,o)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const c=o(0),n=o(9);class i extends c.Command{constructor(e,t,o){super(e),this.iconWidget=null,this.attributeName=t,this.defaultValue=o,this.value=o}refresh(){const e=this.editor.model,t=this.attributeName,o=this.defaultValue;this.iconWidget=(0,n.getSelectedIconWidget)(e.document.selection),this.isEnabled=!!this.iconWidget,this.isEnabled?this.value=this.iconWidget.hasAttribute(t)?this.iconWidget.getAttribute(t):o:this.value=o}execute(e={value:this.defaultValue}){const t=this.editor.model,o=this.iconWidget,c=this.attributeName,n=this.defaultValue;o&&t.change((t=>t.setAttribute(c,e.value||n,o)))}}t.default=i},(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getSelectedIconWidget=function(e){const t=e.getSelectedElement();return t&&t.is("element")&&function(e){return"icon"===e.name}(t)?t:null}},(e,t,o)=>{"use strict";o.r(t),o.d(t,{default:()=>c});const c=''},(e,t,o)=>{"use strict";o.r(t),o.d(t,{default:()=>c});const c=''},(e,t,o)=>{"use strict";o.r(t),o.d(t,{default:()=>c});const c=''},(e,t,o)=>{"use strict";o.r(t),o.d(t,{default:()=>c});const c=''},(e,t,o)=>{e.exports=o(2)("./src/ui.js")},(e,t,o)=>{"use strict";o.r(t),o.d(t,{default:()=>c});const c='\x3c!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --\x3e'}],t={};function o(c){var n=t[c];if(void 0!==n)return n.exports;var i=t[c]={exports:{}};return e[c].call(i.exports,i,i.exports,o),i.exports}o.d=(e,t)=>{for(var c in t)o.o(t,c)&&!o.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:t[c]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var c=o(3);return c=c.default})())); \ No newline at end of file diff --git a/js/build/invisible.js b/js/build/invisible.js index d2c76cc..7f6cf87 100644 --- a/js/build/invisible.js +++ b/js/build/invisible.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.invisible=t())}(self,(()=>(()=>{var e=[(e,t,i)=>{e.exports=i(1)("./src/core.js")},e=>{"use strict";e.exports=CKEditor5.dll},(e,t,i)=>{e.exports=i(1)("./src/widget.js")},,(e,t,i)=>{e.exports=i(1)("./src/ui.js")}],t={};function i(n){var s=t[n];if(void 0!==s)return s.exports;var o=t[n]={exports:{}};return e[n](o,o.exports,i),o.exports}i.d=(e,t)=>{for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n={};return(()=>{"use strict";i.d(n,{default:()=>m});var e=i(0);function t(e){return e&&"ucb-invisible"===e.name}function s(e){return t(e)?e:null}class o extends e.Command{constructor(e){super(e)}execute(e){const i=this.editor.model,n=i.document.selection,o=t(n.getSelectedElement())?s(n.getSelectedElement()):null,l=function(e){const t=e.getFirstRange();let i="";for(const e of t.getItems())e.data&&(i+=e.data);return i}(n);i.change((t=>{let n=!1;if(o){const i=o.getChild(0);i&&t.remove(i),t.appendText(null!==e?e:"",o)}else{const s=t.createElement("ucb-invisible");l?t.appendText(l||"Invisible Content",s):t.appendText(e||"Invisible Content",s),i.insertContent(s),t.setSelection(s,"on"),n=!0,n&&setTimeout((()=>{const t=this.editor.ui.labeledInput;t&&(t.fieldView.value=e||l,t.fieldView.focus())}),0)}}))}refresh(){const e=this.editor.model,t=e.document.selection,i=e.schema.findAllowedParent(t.getFirstPosition(),"ucb-invisible"),n=s(t.getSelectedElement());this.isEnabled=null!==i||null!==n,this.value=!!n;const o=this.editor.ui.labeledInput;if(o)if(n){const e=n.getChild(0);o.fieldView.value=e?e.data:""}else o.fieldView.value=""}}class l extends e.Command{execute(){const e=this.editor.model,t=s(e.document.selection.getSelectedElement());t&&e.change((e=>{!function(e,t){const i=e.createRangeOn(t).getContainedElement();t.parent,e.unwrap(t),i&&e.setSelection(i,"after")}(e,t)}))}refresh(){const e=s(this.editor.model.document.selection.getSelectedElement());this.isEnabled=!!e}}var r=i(2);class c extends e.Plugin{static get requires(){return[r.Widget]}init(){this._defineSchema(),this._defineConverters(),this.editor.commands.add("addInvisible",new o(this.editor)),this.editor.commands.add("removeInvisible",new l(this.editor))}_defineSchema(){this.editor.model.schema.register("ucb-invisible",{isObject:!0,allowWhere:"$text",allowContentOf:"$block",isInline:!0})}_defineConverters(){const{conversion:e}=this.editor;e.for("upcast").elementToElement({model:(e,{writer:t})=>t.createElement("ucb-invisible"),view:{name:"span",classes:"visually-hidden"}}),e.for("dataDowncast").elementToElement({model:"ucb-invisible",view:{name:"span",classes:"visually-hidden"}}),e.for("editingDowncast").elementToElement({model:"ucb-invisible",view:(e,{writer:t})=>{const i=function(e){const t=e.createContainerElement("span",{class:"ucb-invisible"});return(0,r.toWidget)(t,e,{label:"invisible widget",hasSelectionHandle:!0})}(t);return i}})}}var d=i(4);class a extends e.Plugin{static get requires(){return[r.WidgetToolbarRepository]}init(){const e=this.editor,i=e.commands,n=e.ui.componentFactory;n.add("invisible",(n=>{const s=new d.ButtonView(n),o=i.get("addInvisible");return s.label="Screen-Reader Only",s.icon='\x3c!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --\x3e',s.tooltip=!0,s.withText=!1,s.isToggleable=!0,s.bind("isOn","isEnabled").to(o,"value","isEnabled"),this.listenTo(s,"execute",(()=>{const i=e.model.document.selection.getSelectedElement();i&&t(i)?e.execute("removeInvisible",i):e.execute("addInvisible")})),s})),n.add("invisibleInnerText",(e=>this._createInput(e,"Screen-Reader Text")))}afterInit(){this.editor.plugins.get(r.WidgetToolbarRepository).register("invisible",{items:["invisibleInnerText"],getRelatedElement:e=>{const t=e.getSelectedElement();if(t&&t.is("element")&&t.hasClass("ucb-invisible")){const e=t.getChild(0),i=e?e.data:"",n=this.editor.ui.labeledInput;return n&&(n.fieldView.value=i),t}return null}})}_createInput(e,t){const i=new d.LabeledFieldView(e,d.createLabeledInputText);return i.label=e.t(t),this.listenTo(i.fieldView,"input",(()=>{const e=i.fieldView.element.value,t=this.editor.commands.get("addInvisible");t&&t.execute(e)})),this.editor.ui.labeledInput=i,i}}class u extends e.Plugin{static get requires(){return[c,a]}static get pluginName(){return"ucb-invisible"}}const m={Invisible:u}})(),n=n.default})())); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.invisible=t())}(self,(()=>(()=>{var e=[e=>{"use strict";e.exports=CKEditor5.dll},(e,t,i)=>{e.exports=i(0)("./src/core.js")},(e,t,i)=>{e.exports=i(0)("./src/widget.js")},,(e,t,i)=>{e.exports=i(0)("./src/ui.js")}],t={};function i(n){var s=t[n];if(void 0!==s)return s.exports;var o=t[n]={exports:{}};return e[n](o,o.exports,i),o.exports}i.d=(e,t)=>{for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n={};return(()=>{"use strict";i.d(n,{default:()=>m});var e=i(1);function t(e){return e&&"ucb-invisible"===e.name}function s(e){return t(e)?e:null}class o extends e.Command{constructor(e){super(e)}execute(e){const i=this.editor.model,n=i.document.selection,o=t(n.getSelectedElement())?s(n.getSelectedElement()):null,l=function(e){const t=e.getFirstRange();let i="";for(const e of t.getItems())e.data&&(i+=e.data);return i}(n);i.change((t=>{let n=!1;if(o){const i=o.getChild(0);i&&t.remove(i),t.appendText(null!==e?e:"",o)}else{const s=t.createElement("ucb-invisible");l?t.appendText(l||"Invisible Content",s):t.appendText(e||"Invisible Content",s),i.insertContent(s),t.setSelection(s,"on"),n=!0,n&&setTimeout((()=>{const t=this.editor.ui.labeledInput;t&&(t.fieldView.value=e||l,t.fieldView.focus())}),0)}}))}refresh(){const e=this.editor.model,t=e.document.selection,i=e.schema.findAllowedParent(t.getFirstPosition(),"ucb-invisible"),n=s(t.getSelectedElement());this.isEnabled=null!==i||null!==n,this.value=!!n;const o=this.editor.ui.labeledInput;if(o)if(n){const e=n.getChild(0);o.fieldView.value=e?e.data:""}else o.fieldView.value=""}}class l extends e.Command{execute(){const e=this.editor.model,t=s(e.document.selection.getSelectedElement());t&&e.change((e=>{!function(e,t){const i=e.createRangeOn(t).getContainedElement();t.parent,e.unwrap(t),i&&e.setSelection(i,"after")}(e,t)}))}refresh(){const e=s(this.editor.model.document.selection.getSelectedElement());this.isEnabled=!!e}}var r=i(2);class c extends e.Plugin{static get requires(){return[r.Widget]}init(){this._defineSchema(),this._defineConverters(),this.editor.commands.add("addInvisible",new o(this.editor)),this.editor.commands.add("removeInvisible",new l(this.editor))}_defineSchema(){this.editor.model.schema.register("ucb-invisible",{isObject:!0,allowWhere:"$text",allowContentOf:"$block",isInline:!0})}_defineConverters(){const{conversion:e}=this.editor;e.for("upcast").elementToElement({model:(e,{writer:t})=>t.createElement("ucb-invisible"),view:{name:"span",classes:"visually-hidden"}}),e.for("dataDowncast").elementToElement({model:"ucb-invisible",view:{name:"span",classes:"visually-hidden"}}),e.for("editingDowncast").elementToElement({model:"ucb-invisible",view:(e,{writer:t})=>{const i=function(e){const t=e.createContainerElement("span",{class:"ucb-invisible"});return(0,r.toWidget)(t,e,{label:"invisible widget",hasSelectionHandle:!0})}(t);return i}})}}var d=i(4);class a extends e.Plugin{static get requires(){return[r.WidgetToolbarRepository]}init(){const e=this.editor,i=e.commands,n=e.ui.componentFactory;n.add("invisible",(n=>{const s=new d.ButtonView(n),o=i.get("addInvisible");return s.label="Screen-Reader Only",s.icon='\x3c!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --\x3e',s.tooltip=!0,s.withText=!1,s.isToggleable=!0,s.bind("isOn","isEnabled").to(o,"value","isEnabled"),this.listenTo(s,"execute",(()=>{const i=e.model.document.selection.getSelectedElement();i&&t(i)?e.execute("removeInvisible",i):e.execute("addInvisible")})),s})),n.add("invisibleInnerText",(e=>this._createInput(e,"Screen-Reader Text")))}afterInit(){this.editor.plugins.get(r.WidgetToolbarRepository).register("invisible",{items:["invisibleInnerText"],getRelatedElement:e=>{const t=e.getSelectedElement();if(t&&t.is("element")&&t.hasClass("ucb-invisible")){const e=t.getChild(0),i=e?e.data:"",n=this.editor.ui.labeledInput;return n&&(n.fieldView.value=i),t}return null}})}_createInput(e,t){const i=new d.LabeledFieldView(e,d.createLabeledInputText);return i.label=e.t(t),this.listenTo(i.fieldView,"input",(()=>{const e=i.fieldView.element.value,t=this.editor.commands.get("addInvisible");t&&t.execute(e)})),this.editor.ui.labeledInput=i,i}}class u extends e.Plugin{static get requires(){return[c,a]}static get pluginName(){return"ucb-invisible"}}const m={Invisible:u}})(),n=n.default})())); \ No newline at end of file diff --git a/js/build/jumpmenu.js b/js/build/jumpmenu.js index 6c32a5b..33d32fd 100644 --- a/js/build/jumpmenu.js +++ b/js/build/jumpmenu.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.jumpmenu=t())}(self,(()=>(()=>{var e=[(e,t,n)=>{e.exports=n(1)("./src/core.js")},e=>{"use strict";e.exports=CKEditor5.dll},(e,t,n)=>{e.exports=n(1)("./src/widget.js")},,(e,t,n)=>{e.exports=n(1)("./src/ui.js")}],t={};function n(i){var u=t[i];if(void 0!==u)return u.exports;var o=t[i]={exports:{}};return e[i](o,o.exports,n),o.exports}n.d=(e,t)=>{for(var i in t)n.o(t,i)&&!n.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var i={};return(()=>{"use strict";n.d(i,{default:()=>c});var e=n(0),t=n(2);class u extends e.Command{constructor(e){super(e),this.set("isEnabled",!0)}execute(e={jumpMenuHeaderTag:"h2",jumpMenuTitle:"On this page:"}){const t=e.jumpMenuHeaderTag.trim(),n=e.jumpMenuTitle.trim(),i=this.editor.model;i.change((e=>{const u=e.createElement("ucbJumpMenu",{jumpMenuHeaderTag:t,jumpMenuTitle:n});i.insertContent(u,i.document.selection)}))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,n=(t.getSelectedElement(),e.schema.findAllowedParent(t.getFirstPosition(),"ucbJumpMenu"));this.isEnabled=null!==n}}class o extends e.Command{constructor(e,t,n){super(e),this.attributeName=t,this.defaultValue=n,this.set("value",this.defaultValue)}execute(e={}){const{value:t}=e,n=this.editor.model,i=n.document.selection.getSelectedElement();n.change((e=>{if(i&&"ucbJumpMenu"===i.name){e.setAttribute(this.attributeName,t,i);this.editor.editing.mapper.toViewElement(i)._setAttribute(this.attributeName,t)}})),this.value=t}refresh(){const e=this.editor.model.document.selection.getSelectedElement();e&&"ucbJumpMenu"===e.name?(this.value=e.getAttribute(this.attributeName)||this.defaultValue,this.isEnabled=!0):(this.value=this.defaultValue,this.isEnabled=!1)}}class r extends e.Plugin{static get pluginName(){return"JumpMenuEditing"}static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){this.editor.model.schema.register("ucbJumpMenu",{isObject:!0,allowWhere:"$block",allowAttributes:["jumpMenuHeaderTag","jumpMenuTitle"]})}_defineConverters(){const e=this.editor.conversion;e.for("upcast").attributeToAttribute({model:"jumpMenuHeaderTag",view:"headertag"}),e.for("dataDowncast").attributeToAttribute({model:"jumpMenuHeaderTag",view:"headertag"}),e.for("upcast").attributeToAttribute({model:"jumpMenuTitle",view:"data-title"}),e.for("dataDowncast").attributeToAttribute({model:"jumpMenuTitle",view:"data-title"}),e.for("upcast").elementToElement({model:"ucbJumpMenu",view:"ucb-jump-menu"}),e.for("dataDowncast").elementToElement({model:"ucbJumpMenu",view:"ucb-jump-menu"}),e.for("editingDowncast").elementToElement({model:"ucbJumpMenu",view:(e,{writer:n})=>function(e,n){const i=n.createContainerElement("div",{class:"ckeditor5-jumpmenu__widget"},[n.createRawElement("div",{},(t=>{const n=function(e){return e.getAttribute("jumpMenuHeaderTag")||"h2"}(e),i=function(e){return e.getAttribute("jumpMenuTitle")||""}(e);t.innerHTML=``}))]);return(0,t.toWidget)(i,n,{label:"jump menu widget"})}(e,n)}),e.for("editingDowncast").add((e=>{e.on("attribute:jumpMenuHeaderTag",((e,t,n)=>s(t,n))),e.on("attribute:jumpMenuTitle",((e,t,n)=>s(t,n)))}))}_defineCommands(){const e=this.editor;e.commands.add("jumpmenu",new u(e)),e.commands.add("modifyJumpMenuHeaderTag",new o(e,"jumpMenuHeaderTag","h2")),e.commands.add("modifyJumpMenuTitle",new o(e,"jumpMenuTitle",""))}}function a(e){return e.replace(/&/g,"&").replace(/"/g,""")}function s(e,t){e.attributeOldValue&&!t.consumable.consume(e.item,"insert")&&(t.writer.remove(t.mapper.toViewRange(e.range)),t.convertItem(e.item))}var d=n(4);class l extends e.Plugin{static get requires(){return[t.WidgetToolbarRepository]}init(){const e=this.editor,t=e.ui.componentFactory;t.add("jumpmenu",(t=>{const n=e.commands.get("jumpmenu"),i=new d.ButtonView(t);return i.set({label:"Insert Jump Menu",icon:'\x3c!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--\x3e',tooltip:!0}),i.bind("isEnabled").to(n,"isEnabled"),i.on("execute",(()=>{e.execute("jumpmenu"),e.editing.view.focus()})),i})),t.add("setHeaderTag",(t=>{const n=e.commands.get("modifyJumpMenuHeaderTag");return this._createDropdown(t,"Set Header Tag",n,{h2:{label:"H2"},h3:{label:"H3"},h4:{label:"H4"},h5:{label:"H5"}},"h2")})),t.add("setTitle",(t=>{const n=e.commands.get("modifyJumpMenuTitle"),i=new d.LabeledFieldView(t,d.createLabeledInputText);return i.label="Title",i.fieldView.bind("value").to(n,"value"),i.fieldView.on("input",(()=>{e.execute("modifyJumpMenuTitle",{value:i.fieldView.element.value})})),i})),this._registerWidgetToolbar()}_createDropdown(e,t,n,i,u){const o=(0,d.createDropdown)(e);return(0,d.addToolbarToDropdown)(o,Object.entries(i).map((([t,i])=>this._createButton(e,i.label,n,t)))),o.buttonView.set({label:e.t(t),withText:!0}),o.buttonView.bind("label").to(n,"value",(e=>i[e]?i[e].label:i[u].label)),o.bind("isEnabled").to(n,"isEnabled"),o}_createButton(e,t,n,i){const u=this.editor,o=new d.ButtonView(e);return o.set({label:e.t(t),withText:!0,isToggleable:!0}),o.bind("isEnabled").to(n),o.bind("isOn").to(n,"value",(e=>e===i)),o.on("execute",(()=>{u.execute("modifyJumpMenuHeaderTag",{value:i}),u.editing.view.focus()})),o}_registerWidgetToolbar(){this.editor.plugins.get(t.WidgetToolbarRepository).register("ucbJumpMenu",{items:["setHeaderTag","setTitle"],getRelatedElement:e=>{const t=e.getSelectedElement();return t&&t.is("element")&&t.hasClass("ckeditor5-jumpmenu__widget")?t:null}})}}class m extends e.Plugin{static get requires(){return[r,l]}}const c={JumpMenu:m}})(),i=i.default})())); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.jumpmenu=t())}(self,(()=>(()=>{var e=[e=>{"use strict";e.exports=CKEditor5.dll},(e,t,n)=>{e.exports=n(0)("./src/core.js")},(e,t,n)=>{e.exports=n(0)("./src/widget.js")},,(e,t,n)=>{e.exports=n(0)("./src/ui.js")}],t={};function n(i){var u=t[i];if(void 0!==u)return u.exports;var o=t[i]={exports:{}};return e[i](o,o.exports,n),o.exports}n.d=(e,t)=>{for(var i in t)n.o(t,i)&&!n.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var i={};return(()=>{"use strict";n.d(i,{default:()=>c});var e=n(1),t=n(2);class u extends e.Command{constructor(e){super(e),this.set("isEnabled",!0)}execute(e={jumpMenuHeaderTag:"h2",jumpMenuTitle:"On this page:"}){const t=e.jumpMenuHeaderTag.trim(),n=e.jumpMenuTitle.trim(),i=this.editor.model;i.change((e=>{const u=e.createElement("ucbJumpMenu",{jumpMenuHeaderTag:t,jumpMenuTitle:n});i.insertContent(u,i.document.selection)}))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,n=(t.getSelectedElement(),e.schema.findAllowedParent(t.getFirstPosition(),"ucbJumpMenu"));this.isEnabled=null!==n}}class o extends e.Command{constructor(e,t,n){super(e),this.attributeName=t,this.defaultValue=n,this.set("value",this.defaultValue)}execute(e={}){const{value:t}=e,n=this.editor.model,i=n.document.selection.getSelectedElement();n.change((e=>{if(i&&"ucbJumpMenu"===i.name){e.setAttribute(this.attributeName,t,i);this.editor.editing.mapper.toViewElement(i)._setAttribute(this.attributeName,t)}})),this.value=t}refresh(){const e=this.editor.model.document.selection.getSelectedElement();e&&"ucbJumpMenu"===e.name?(this.value=e.getAttribute(this.attributeName)||this.defaultValue,this.isEnabled=!0):(this.value=this.defaultValue,this.isEnabled=!1)}}class r extends e.Plugin{static get pluginName(){return"JumpMenuEditing"}static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){this.editor.model.schema.register("ucbJumpMenu",{isObject:!0,allowWhere:"$block",allowAttributes:["jumpMenuHeaderTag","jumpMenuTitle"]})}_defineConverters(){const e=this.editor.conversion;e.for("upcast").attributeToAttribute({model:"jumpMenuHeaderTag",view:"headertag"}),e.for("dataDowncast").attributeToAttribute({model:"jumpMenuHeaderTag",view:"headertag"}),e.for("upcast").attributeToAttribute({model:"jumpMenuTitle",view:"data-title"}),e.for("dataDowncast").attributeToAttribute({model:"jumpMenuTitle",view:"data-title"}),e.for("upcast").elementToElement({model:"ucbJumpMenu",view:"ucb-jump-menu"}),e.for("dataDowncast").elementToElement({model:"ucbJumpMenu",view:"ucb-jump-menu"}),e.for("editingDowncast").elementToElement({model:"ucbJumpMenu",view:(e,{writer:n})=>function(e,n){const i=n.createContainerElement("div",{class:"ckeditor5-jumpmenu__widget"},[n.createRawElement("div",{},(t=>{const n=function(e){return e.getAttribute("jumpMenuHeaderTag")||"h2"}(e),i=function(e){return e.getAttribute("jumpMenuTitle")||""}(e);t.innerHTML=``}))]);return(0,t.toWidget)(i,n,{label:"jump menu widget"})}(e,n)}),e.for("editingDowncast").add((e=>{e.on("attribute:jumpMenuHeaderTag",((e,t,n)=>s(t,n))),e.on("attribute:jumpMenuTitle",((e,t,n)=>s(t,n)))}))}_defineCommands(){const e=this.editor;e.commands.add("jumpmenu",new u(e)),e.commands.add("modifyJumpMenuHeaderTag",new o(e,"jumpMenuHeaderTag","h2")),e.commands.add("modifyJumpMenuTitle",new o(e,"jumpMenuTitle",""))}}function a(e){return e.replace(/&/g,"&").replace(/"/g,""")}function s(e,t){e.attributeOldValue&&!t.consumable.consume(e.item,"insert")&&(t.writer.remove(t.mapper.toViewRange(e.range)),t.convertItem(e.item))}var d=n(4);class l extends e.Plugin{static get requires(){return[t.WidgetToolbarRepository]}init(){const e=this.editor,t=e.ui.componentFactory;t.add("jumpmenu",(t=>{const n=e.commands.get("jumpmenu"),i=new d.ButtonView(t);return i.set({label:"Insert Jump Menu",icon:'\x3c!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--\x3e',tooltip:!0}),i.bind("isEnabled").to(n,"isEnabled"),i.on("execute",(()=>{e.execute("jumpmenu"),e.editing.view.focus()})),i})),t.add("setHeaderTag",(t=>{const n=e.commands.get("modifyJumpMenuHeaderTag");return this._createDropdown(t,"Set Header Tag",n,{h2:{label:"H2"},h3:{label:"H3"},h4:{label:"H4"},h5:{label:"H5"}},"h2")})),t.add("setTitle",(t=>{const n=e.commands.get("modifyJumpMenuTitle"),i=new d.LabeledFieldView(t,d.createLabeledInputText);return i.label="Title",i.fieldView.bind("value").to(n,"value"),i.fieldView.on("input",(()=>{e.execute("modifyJumpMenuTitle",{value:i.fieldView.element.value})})),i})),this._registerWidgetToolbar()}_createDropdown(e,t,n,i,u){const o=(0,d.createDropdown)(e);return(0,d.addToolbarToDropdown)(o,Object.entries(i).map((([t,i])=>this._createButton(e,i.label,n,t)))),o.buttonView.set({label:e.t(t),withText:!0}),o.buttonView.bind("label").to(n,"value",(e=>i[e]?i[e].label:i[u].label)),o.bind("isEnabled").to(n,"isEnabled"),o}_createButton(e,t,n,i){const u=this.editor,o=new d.ButtonView(e);return o.set({label:e.t(t),withText:!0,isToggleable:!0}),o.bind("isEnabled").to(n),o.bind("isOn").to(n,"value",(e=>e===i)),o.on("execute",(()=>{u.execute("modifyJumpMenuHeaderTag",{value:i}),u.editing.view.focus()})),o}_registerWidgetToolbar(){this.editor.plugins.get(t.WidgetToolbarRepository).register("ucbJumpMenu",{items:["setHeaderTag","setTitle"],getRelatedElement:e=>{const t=e.getSelectedElement();return t&&t.is("element")&&t.hasClass("ckeditor5-jumpmenu__widget")?t:null}})}}class m extends e.Plugin{static get requires(){return[r,l]}}const c={JumpMenu:m}})(),i=i.default})())); \ No newline at end of file diff --git a/js/build/map.js b/js/build/map.js index af278b1..7517054 100644 --- a/js/build/map.js +++ b/js/build/map.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.map=t())}(self,(()=>(()=>{var e=[(e,t,i)=>{e.exports=i(1)("./src/core.js")},e=>{"use strict";e.exports=CKEditor5.dll},(e,t,i)=>{e.exports=i(1)("./src/widget.js")},(e,t,i)=>{e.exports=i(1)("./src/ui.js")},,(e,t,i)=>{e.exports=i(1)("./src/utils.js")}],t={};function i(o){var s=t[o];if(void 0!==s)return s.exports;var a=t[o]={exports:{}};return e[o](a,a.exports,i),a.exports}i.d=(e,t)=>{for(var o in t)i.o(t,o)&&!i.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var o={};return(()=>{"use strict";i.d(o,{default:()=>f});var e=i(0),t=i(2);const s={small:{label:"Small",className:"ucb-map-size-small"},medium:{label:"Medium",className:"ucb-map-size-medium"},large:{label:"Large",className:"ucb-map-size-large"}},a="small";function n(e){const t=(new DOMParser).parseFromString(e,"text/html").querySelector("iframe");return t?t.getAttribute("src"):null}function c(e){return"https://www.colorado.edu/map/?id=336"+(e?"#!m/"+e:"")}function r(e){return"?"===e[0]?"https://www.google.com/maps/d/embed"+e:"https://www.google.com/maps/embed?pb="+e}class l extends e.Command{constructor(e){super(e),this.set("existingMapSelected",!1)}execute(e={value:"",size:a}){const t=e.value.trim(),i=this.editor.model,o=e.size;if(!t)return;let s="campusMap",c=function(e){if("<"===e[0]&&!(e=n(e)))return null;let t;try{t=new URL(e)}catch(e){return null}if(t.hostname.match(/^(www\.)?colorado\.edu$/)&&t.pathname.match(/^\/map/)&&t.hash){const e=t.hash.match(/m\/(\d+)/);if(e)return e[1]}return null}(t);c||(s="googleMap",c=function(e){if("<"===e[0]&&!(e=n(e)))return null;let t;try{t=new URL(e)}catch(e){return null}if(t.hostname.match(/^(www\.)?google\.com$/)){if(t.pathname.match(/^\/maps\/embed/))return decodeURIComponent(t.searchParams.get("pb")||"");if(t.pathname.match(/^\/maps\/d/))return"?"+t.searchParams}return null}(t)),c&&i.change((e=>i.insertContent(e.createElement(s,{mapLocation:c,mapSize:o}))))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,i=t.getSelectedElement(),o=e.schema.findAllowedParent(t.getFirstPosition(),"campusMap");var s;this.isEnabled=null!==o,this.existingMapSelected=!(s=i)||"campusMap"!==s.name&&"googleMap"!==s.name?null:i}}class u extends e.Plugin{static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){const e=this.editor.model.schema;e.register("campusMap",{isObject:!0,allowWhere:"$block",allowAttributes:["mapLocation","mapSize"],allowChildren:!1}),e.register("googleMap",{isObject:!0,allowWhere:"$block",allowAttributes:["mapLocation","mapSize"],allowChildren:!1})}_defineConverters(){const e=this.editor.conversion;e.attributeToAttribute({model:{key:"mapLocation",value:e=>e.getAttribute("data-map-location").replace(/&/g,"&")},view:"data-map-location"}),e.attributeToAttribute(function(e,t){const i={};for(const[e,o]of Object.entries(t))i[e]={key:"class",value:o.className};return{model:{key:e,values:Object.keys(t)},view:i}}("mapSize",s)),e.for("upcast").elementToElement({model:"campusMap",view:{name:"ucb-map",classes:["ucb-map","ucb-campus-map"]}}),e.for("upcast").elementToElement({model:"googleMap",view:{name:"ucb-map",classes:["ucb-map","ucb-google-map"]}}),e.for("dataDowncast").elementToElement({model:"campusMap",view:(e,{writer:t})=>m(e,t)}),e.for("dataDowncast").elementToElement({model:"googleMap",view:(e,{writer:t})=>p(e,t)}),e.for("editingDowncast").elementToElement({model:"campusMap",view:(e,{writer:t})=>m(e,t,!0)}),e.for("editingDowncast").elementToElement({model:"googleMap",view:(e,{writer:t})=>p(e,t,!0)})}_defineCommands(){this.editor.commands.add("insertMap",new l(this.editor))}}function m(e,i,o=!1){if(o){const o=(e.getAttribute("mapLocation")||"").replace(/\D/g,"");return(0,t.toWidget)(i.createContainerElement("div",{class:"ucb-map ucb-campus-map",style:`background-image: url('https://staticmap.concept3d.com/map/static-map/?map=336&loc=${o}&scale=2')`},[i.createRawElement("a",{href:c(o)},(e=>{e.innerHTML="View location on the Campus Map",e.onclick=e=>e.preventDefault()}))]),i,{label:"map widget"})}return i.createContainerElement("ucb-map",{class:"ucb-map ucb-campus-map"})}function p(e,i,o=!1){if(o){const o=e.getAttribute("mapLocation")||"";return(0,t.toWidget)(i.createContainerElement("div",{class:"ucb-map ucb-google-map"},[i.createEmptyElement("iframe",{src:r(o),loading:"lazy",referrerpolicy:"no-referrer"}),i.createEmptyElement("div",{class:"ucb-map-editing-cover"})]),i,{label:"map widget"})}return i.createContainerElement("ucb-map",{class:"ucb-map ucb-google-map"})}var d=i(3),h=i(5);class w extends d.View{constructor(t){super(t),this.valueInputView=this._createInput(t,"Map embed"),this.set("value",""),this.valueInputView.fieldView.bind("value").to(this,"value"),this.sizeDropdownView=this._createSelectionDropdown(t,"Map size",null,"size",s,a),this.set("size",a),this.saveButtonView=this._createActionButton(t,"Save",e.icons.check,"ck-button-save"),this.cancelButtonView=this._createActionButton(t,"Cancel",e.icons.cancel,"ck-button-cancel"),this.saveButtonView.type="submit",this.cancelButtonView.delegate("execute").to(this,"cancel"),this.childViews=this.createCollection([this.valueInputView,this.sizeDropdownView,this.saveButtonView,this.cancelButtonView]),this._enableFocusTracking(),this.setTemplate({tag:"form",attributes:{class:["ck","ck-map-form"],tabindex:"-1"},children:this.childViews})}render(){super.render();for(const e of this.childViews)this.focusTracker.add(e.element);(0,d.submitHandler)({view:this}),this.keystrokes.listenTo(this.element)}focus(){this.valueInputView.focus()}reset(){this.value="",this.size=a,this.valueInputView.fieldView.element.blur(),this.element.reset()}destroy(){this.keystrokes.destroy()}_createSelectionDropdown(e,t,i,o,s,a){const n=(0,d.createDropdown)(e),c=s[a];return(0,d.addToolbarToDropdown)(n,Object.entries(s).map((([t,i])=>this._createSelectableButton(e,i.label,i.icon,o,t)))),n.buttonView.set({icon:i,tooltip:e.t(t),withText:!i}),n.buttonView.bind("label").to(this,o,(t=>e.t(s[t]?s[t].label:c.label))),i===s[a].icon&&n.buttonView.bind("icon").to(this,o,(e=>s[e]?s[e].icon:c.icon)),n}_createSelectableButton(e,t,i,o,s){const a=new d.ButtonView;return a.set({label:e.t(t),icon:i,tooltip:!!i,isToggleable:!0,withText:!i}),a.bind("isOn").to(this,o,(e=>e===s)),this.listenTo(a,"execute",(()=>{this.set(o,s)})),a}_createActionButton(e,t,i,o){const s=new d.ButtonView;return s.set({label:e.t(t),icon:i,class:o,tooltip:!!i,withText:!i}),s}_createInput(e,t){const i=new d.LabeledFieldView(e,d.createLabeledInputText);return i.label=e.t(t),i}_enableFocusTracking(){this.focusTracker=new h.FocusTracker,this.keystrokes=new h.KeystrokeHandler,this.focusTracker.on("change:focusedElement",((e,t,i)=>{i===this.valueInputView.element&&this.valueInputView.fieldView.element.select()})),this.focusCycler=new d.FocusCycler({focusables:this.childViews,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}})}}class b extends e.Plugin{static get requires(){return[d.ContextualBalloon]}init(){const e=this.editor,t=e.commands.get("insertMap"),i=e.editing.view.document,o=e.ui.componentFactory;this._balloon=e.plugins.get(d.ContextualBalloon),this.formView=this._createFormView(e.locale),o.add("map",(e=>{const o=new d.ButtonView(e);return o.set({label:e.t("Map"),icon:'\x3c!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --\x3e',tooltip:!0,isToggleable:!0}),o.bind("isEnabled").to(t,"isEnabled"),o.bind("isOn").to(t,"existingMapSelected"),this.listenTo(o,"execute",(()=>{this._showUI(t.existingMapSelected)})),this.listenTo(i,"click",(()=>{t.existingMapSelected&&this._showUI(t.existingMapSelected)})),o}))}_createFormView(e){const t=this.editor,i=new w(e);return this.listenTo(i,"submit",(()=>{t.execute("insertMap",{value:i.valueInputView.fieldView.element.value,size:i.size}),this._hideUI()})),this.listenTo(i,"cancel",(()=>this._hideUI())),(0,d.clickOutsideHandler)({emitter:i,activator:()=>this._balloon.visibleView===i,contextElements:[this._balloon.view.element],callback:()=>this._hideUI()}),i.keystrokes.set("Esc",((e,t)=>{this._hideUI(),t()})),i}_showUI(e){if(this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),e){const t=e.getAttribute("mapLocation");t&&"campusMap"===e.name?this.formView.value=c(t):t&&"googleMap"===e.name&&(this.formView.value=r(t)),this.formView.size=e.getAttribute("mapSize"),this.editor.model.change((t=>t.setSelection(e,"on")))}this.formView.focus()}_hideUI(){this.formView.reset(),this._balloon.remove(this.formView),this.editor.editing.view.focus()}_getBalloonPositionData(){const e=this.editor.editing.view,t=e.document;return{target:()=>e.domConverter.viewRangeToDom(t.selection.getFirstRange())}}}class g extends e.Plugin{static get requires(){return[u,b]}}const f={Map:g}})(),o=o.default})())); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.map=t())}(self,(()=>(()=>{var e=[e=>{"use strict";e.exports=CKEditor5.dll},(e,t,i)=>{e.exports=i(0)("./src/core.js")},(e,t,i)=>{e.exports=i(0)("./src/widget.js")},(e,t,i)=>{e.exports=i(0)("./src/ui.js")},,(e,t,i)=>{e.exports=i(0)("./src/utils.js")}],t={};function i(o){var s=t[o];if(void 0!==s)return s.exports;var a=t[o]={exports:{}};return e[o](a,a.exports,i),a.exports}i.d=(e,t)=>{for(var o in t)i.o(t,o)&&!i.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var o={};return(()=>{"use strict";i.d(o,{default:()=>f});var e=i(1),t=i(2);const s={small:{label:"Small",className:"ucb-map-size-small"},medium:{label:"Medium",className:"ucb-map-size-medium"},large:{label:"Large",className:"ucb-map-size-large"}},a="small";function n(e){const t=(new DOMParser).parseFromString(e,"text/html").querySelector("iframe");return t?t.getAttribute("src"):null}function c(e){return"https://www.colorado.edu/map/?id=336"+(e?"#!m/"+e:"")}function r(e){return"?"===e[0]?"https://www.google.com/maps/d/embed"+e:"https://www.google.com/maps/embed?pb="+e}class l extends e.Command{constructor(e){super(e),this.set("existingMapSelected",!1)}execute(e={value:"",size:a}){const t=e.value.trim(),i=this.editor.model,o=e.size;if(!t)return;let s="campusMap",c=function(e){if("<"===e[0]&&!(e=n(e)))return null;let t;try{t=new URL(e)}catch(e){return null}if(t.hostname.match(/^(www\.)?colorado\.edu$/)&&t.pathname.match(/^\/map/)&&t.hash){const e=t.hash.match(/m\/(\d+)/);if(e)return e[1]}return null}(t);c||(s="googleMap",c=function(e){if("<"===e[0]&&!(e=n(e)))return null;let t;try{t=new URL(e)}catch(e){return null}if(t.hostname.match(/^(www\.)?google\.com$/)){if(t.pathname.match(/^\/maps\/embed/))return decodeURIComponent(t.searchParams.get("pb")||"");if(t.pathname.match(/^\/maps\/d/))return"?"+t.searchParams}return null}(t)),c&&i.change((e=>i.insertContent(e.createElement(s,{mapLocation:c,mapSize:o}))))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,i=t.getSelectedElement(),o=e.schema.findAllowedParent(t.getFirstPosition(),"campusMap");var s;this.isEnabled=null!==o,this.existingMapSelected=!(s=i)||"campusMap"!==s.name&&"googleMap"!==s.name?null:i}}class u extends e.Plugin{static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this._defineCommands()}_defineSchema(){const e=this.editor.model.schema;e.register("campusMap",{isObject:!0,allowWhere:"$block",allowAttributes:["mapLocation","mapSize"],allowChildren:!1}),e.register("googleMap",{isObject:!0,allowWhere:"$block",allowAttributes:["mapLocation","mapSize"],allowChildren:!1})}_defineConverters(){const e=this.editor.conversion;e.attributeToAttribute({model:{key:"mapLocation",value:e=>e.getAttribute("data-map-location").replace(/&/g,"&")},view:"data-map-location"}),e.attributeToAttribute(function(e,t){const i={};for(const[e,o]of Object.entries(t))i[e]={key:"class",value:o.className};return{model:{key:e,values:Object.keys(t)},view:i}}("mapSize",s)),e.for("upcast").elementToElement({model:"campusMap",view:{name:"ucb-map",classes:["ucb-map","ucb-campus-map"]}}),e.for("upcast").elementToElement({model:"googleMap",view:{name:"ucb-map",classes:["ucb-map","ucb-google-map"]}}),e.for("dataDowncast").elementToElement({model:"campusMap",view:(e,{writer:t})=>m(e,t)}),e.for("dataDowncast").elementToElement({model:"googleMap",view:(e,{writer:t})=>p(e,t)}),e.for("editingDowncast").elementToElement({model:"campusMap",view:(e,{writer:t})=>m(e,t,!0)}),e.for("editingDowncast").elementToElement({model:"googleMap",view:(e,{writer:t})=>p(e,t,!0)})}_defineCommands(){this.editor.commands.add("insertMap",new l(this.editor))}}function m(e,i,o=!1){if(o){const o=(e.getAttribute("mapLocation")||"").replace(/\D/g,"");return(0,t.toWidget)(i.createContainerElement("div",{class:"ucb-map ucb-campus-map",style:`background-image: url('https://staticmap.concept3d.com/map/static-map/?map=336&loc=${o}&scale=2')`},[i.createRawElement("a",{href:c(o)},(e=>{e.innerHTML="View location on the Campus Map",e.onclick=e=>e.preventDefault()}))]),i,{label:"map widget"})}return i.createContainerElement("ucb-map",{class:"ucb-map ucb-campus-map"})}function p(e,i,o=!1){if(o){const o=e.getAttribute("mapLocation")||"";return(0,t.toWidget)(i.createContainerElement("div",{class:"ucb-map ucb-google-map"},[i.createEmptyElement("iframe",{src:r(o),loading:"lazy",referrerpolicy:"no-referrer"}),i.createEmptyElement("div",{class:"ucb-map-editing-cover"})]),i,{label:"map widget"})}return i.createContainerElement("ucb-map",{class:"ucb-map ucb-google-map"})}var d=i(3),h=i(5);class w extends d.View{constructor(t){super(t),this.valueInputView=this._createInput(t,"Map embed"),this.set("value",""),this.valueInputView.fieldView.bind("value").to(this,"value"),this.sizeDropdownView=this._createSelectionDropdown(t,"Map size",null,"size",s,a),this.set("size",a),this.saveButtonView=this._createActionButton(t,"Save",e.icons.check,"ck-button-save"),this.cancelButtonView=this._createActionButton(t,"Cancel",e.icons.cancel,"ck-button-cancel"),this.saveButtonView.type="submit",this.cancelButtonView.delegate("execute").to(this,"cancel"),this.childViews=this.createCollection([this.valueInputView,this.sizeDropdownView,this.saveButtonView,this.cancelButtonView]),this._enableFocusTracking(),this.setTemplate({tag:"form",attributes:{class:["ck","ck-map-form"],tabindex:"-1"},children:this.childViews})}render(){super.render();for(const e of this.childViews)this.focusTracker.add(e.element);(0,d.submitHandler)({view:this}),this.keystrokes.listenTo(this.element)}focus(){this.valueInputView.focus()}reset(){this.value="",this.size=a,this.valueInputView.fieldView.element.blur(),this.element.reset()}destroy(){this.keystrokes.destroy()}_createSelectionDropdown(e,t,i,o,s,a){const n=(0,d.createDropdown)(e),c=s[a];return(0,d.addToolbarToDropdown)(n,Object.entries(s).map((([t,i])=>this._createSelectableButton(e,i.label,i.icon,o,t)))),n.buttonView.set({icon:i,tooltip:e.t(t),withText:!i}),n.buttonView.bind("label").to(this,o,(t=>e.t(s[t]?s[t].label:c.label))),i===s[a].icon&&n.buttonView.bind("icon").to(this,o,(e=>s[e]?s[e].icon:c.icon)),n}_createSelectableButton(e,t,i,o,s){const a=new d.ButtonView;return a.set({label:e.t(t),icon:i,tooltip:!!i,isToggleable:!0,withText:!i}),a.bind("isOn").to(this,o,(e=>e===s)),this.listenTo(a,"execute",(()=>{this.set(o,s)})),a}_createActionButton(e,t,i,o){const s=new d.ButtonView;return s.set({label:e.t(t),icon:i,class:o,tooltip:!!i,withText:!i}),s}_createInput(e,t){const i=new d.LabeledFieldView(e,d.createLabeledInputText);return i.label=e.t(t),i}_enableFocusTracking(){this.focusTracker=new h.FocusTracker,this.keystrokes=new h.KeystrokeHandler,this.focusTracker.on("change:focusedElement",((e,t,i)=>{i===this.valueInputView.element&&this.valueInputView.fieldView.element.select()})),this.focusCycler=new d.FocusCycler({focusables:this.childViews,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}})}}class b extends e.Plugin{static get requires(){return[d.ContextualBalloon]}init(){const e=this.editor,t=e.commands.get("insertMap"),i=e.editing.view.document,o=e.ui.componentFactory;this._balloon=e.plugins.get(d.ContextualBalloon),this.formView=this._createFormView(e.locale),o.add("map",(e=>{const o=new d.ButtonView(e);return o.set({label:e.t("Map"),icon:'\x3c!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --\x3e',tooltip:!0,isToggleable:!0}),o.bind("isEnabled").to(t,"isEnabled"),o.bind("isOn").to(t,"existingMapSelected"),this.listenTo(o,"execute",(()=>{this._showUI(t.existingMapSelected)})),this.listenTo(i,"click",(()=>{t.existingMapSelected&&this._showUI(t.existingMapSelected)})),o}))}_createFormView(e){const t=this.editor,i=new w(e);return this.listenTo(i,"submit",(()=>{t.execute("insertMap",{value:i.valueInputView.fieldView.element.value,size:i.size}),this._hideUI()})),this.listenTo(i,"cancel",(()=>this._hideUI())),(0,d.clickOutsideHandler)({emitter:i,activator:()=>this._balloon.visibleView===i,contextElements:[this._balloon.view.element],callback:()=>this._hideUI()}),i.keystrokes.set("Esc",((e,t)=>{this._hideUI(),t()})),i}_showUI(e){if(this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),e){const t=e.getAttribute("mapLocation");t&&"campusMap"===e.name?this.formView.value=c(t):t&&"googleMap"===e.name&&(this.formView.value=r(t)),this.formView.size=e.getAttribute("mapSize"),this.editor.model.change((t=>t.setSelection(e,"on")))}this.formView.focus()}_hideUI(){this.formView.reset(),this._balloon.remove(this.formView),this.editor.editing.view.focus()}_getBalloonPositionData(){const e=this.editor.editing.view,t=e.document;return{target:()=>e.domConverter.viewRangeToDom(t.selection.getFirstRange())}}}class g extends e.Plugin{static get requires(){return[u,b]}}const f={Map:g}})(),o=o.default})())); \ No newline at end of file diff --git a/js/build/tooltip.js b/js/build/tooltip.js index aa47ebe..b2b1536 100644 --- a/js/build/tooltip.js +++ b/js/build/tooltip.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.tooltip=t())}(self,(()=>(()=>{var e={"ckeditor5/src/core.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/core.js")},"ckeditor5/src/ui.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/ui.js")},"ckeditor5/src/utils.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/utils.js")},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},t={};function i(o){var s=t[o];if(void 0!==s)return s.exports;var r=t[o]={exports:{}};return e[o](r,r.exports,i),r.exports}i.d=(e,t)=>{for(var o in t)i.o(t,o)&&!i.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var o={};return(()=>{"use strict";i.d(o,{default:()=>b});var e=i("ckeditor5/src/core.js");function t(e,t,i,o){return o.createRange(s(e,t,i,!0,o),s(e,t,i,!1,o))}function s(e,t,i,o,s){let r=e.textNode||(o?e.nodeBefore:e.nodeAfter),n=null;for(;r&&r.getAttribute(t)==i;)n=r,r=o?r.previousSibling:r.nextSibling;return n?s.createPositionAt(n,o?"before":"after"):e}function r(e){return Array.from(e.getItems()).reduce(((e,t)=>t.is("text")||t.is("textProxy")?e+t.data:e),"")}var n=i("ckeditor5/src/utils.js");class l extends e.Command{refresh(){const e=this.editor.model,i=e.document.selection,o=i.getFirstRange();if(o.isCollapsed)if(i.hasAttribute("tooltip")){const o=i.getAttribute("ucb-tooltip"),s=t(i.getFirstPosition(),"ucb-tooltip",o,e);this.value={abbr:r(s),title:o,range:s}}else this.value=null;else if(i.hasAttribute("ucb-tooltip")){const s=i.getAttribute("ucb-tooltip");t(i.getFirstPosition(),"ucb-tooltip",s,e).containsRange(o,!0)?this.value={abbr:r(o),title:s,range:o}:this.value=null}else this.value=null;this.isEnabled=e.schema.checkAttributeInSelection(i,"ucb-tooltip")}execute({abbr:e,title:t}){const i=this.editor.model,o=i.document.selection;i.change((s=>{if(o.isCollapsed){if(this.value){const{end:o}=i.insertContent(s.createText(e,{tooltip:t}),this.value.range);s.setSelection(o)}else if(""!==e){const r=o.getFirstPosition(),l=(0,n.toMap)(o.getAttributes());l.set("ucb-tooltip",t);const{end:c}=i.insertContent(s.createText(e,l),r);s.setSelection(c)}s.removeSelectionAttribute("ucb-tooltip")}else{const e=i.schema.getValidRanges(o.getRanges(),"ucb-tooltip");for(const i of e)s.setAttribute("ucb-tooltip",t,i)}}))}}class c extends e.Plugin{init(){this._defineSchema(),this._defineConverters(),this.editor.commands.add("addTooltip",new l(this.editor))}_defineSchema(){const e=this.editor.model.schema;e.register("ucb-tooltip",{isContent:!0}),e.extend("$text",{allowAttributes:["ucb-tooltip"]})}_defineConverters(){const e=this.editor.conversion;e.for("downcast").attributeToElement({model:"ucb-tooltip",view:(e,t)=>{const{writer:i}=t;return i.createAttributeElement("abbr",{title:e,class:"ucb-tooltip"})}}),e.for("upcast").elementToAttribute({view:{name:"abbr",attributes:["title"],classes:"ucb-tooltip"},model:{key:"ucb-tooltip",value:e=>e.getAttribute("title")}})}}var a=i("ckeditor5/src/ui.js");class u extends a.View{constructor(t){super(t),this.focusTracker=new n.FocusTracker,this.keystrokes=new n.KeystrokeHandler,this.abbrInputView=this._createInput("Add Tooltip"),this.titleInputView=this._createInput("Add Text"),this.saveButtonView=this._createButton("Save",e.icons.check,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton("Cancel",e.icons.cancel,"ck-button-cancel"),this.cancelButtonView.delegate("execute").to(this,"cancel"),this.childViews=this.createCollection([this.abbrInputView,this.titleInputView,this.saveButtonView,this.cancelButtonView]),this._focusCycler=new a.FocusCycler({focusables:this.childViews,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-tooltip-form"],tabindex:"-1"},children:this.childViews})}render(){super.render(),(0,a.submitHandler)({view:this}),this.childViews._items.forEach((e=>{this.focusTracker.add(e.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this.abbrInputView.isEnabled?this.abbrInputView.focus():this.titleInputView.focus()}_createInput(e){const t=new a.LabeledFieldView(this.locale,a.createLabeledInputText);return t.label=e,t}_createButton(e,t,i){const o=new a.ButtonView;return o.set({label:e,icon:t,tooltip:!0,class:i}),o}}class d extends e.Plugin{static get requires(){return[a.ContextualBalloon]}init(){const e=this.editor;this._balloon=this.editor.plugins.get(a.ContextualBalloon),this.formView=this._createFormView(),e.ui.componentFactory.add("tooltip",(()=>{const e=new a.ButtonView;return e.label="Tooltip",e.icon='\x3c!-- Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --\x3e',e.tooltip=!0,e.withText=!1,this.listenTo(e,"execute",(()=>{this._showUI()})),e}))}_createFormView(){const e=this.editor,t=new u(e.locale);return this.listenTo(t,"submit",(()=>{const i={abbr:t.abbrInputView.fieldView.element.value,title:t.titleInputView.fieldView.element.value};e.execute("addTooltip",i),this._hideUI()})),this.listenTo(t,"cancel",(()=>{this._hideUI()})),(0,a.clickOutsideHandler)({emitter:t,activator:()=>this._balloon.visibleView===t,contextElements:[this._balloon.view.element],callback:()=>this._hideUI()}),t}_showUI(){const e=this.editor.model.document.selection,t=this.editor.commands.get("addTooltip").value;if(this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),this.formView.abbrInputView.isEnabled=e.getFirstRange().isCollapsed,t)this.formView.abbrInputView.fieldView.value=t.abbr,this.formView.titleInputView.fieldView.value=t.title;else{const t=r(e.getFirstRange());this.formView.abbrInputView.fieldView.value=t,this.formView.titleInputView.fieldView.value=""}this.formView.focus()}_hideUI(){this.formView.abbrInputView.fieldView.value="",this.formView.titleInputView.fieldView.value="",this.formView.element.reset(),this._balloon.remove(this.formView),this.editor.editing.view.focus()}_getBalloonPositionData(){const e=this.editor.editing.view,t=e.document;let i=null;return i=()=>e.domConverter.viewRangeToDom(t.selection.getFirstRange()),{target:i}}}class h extends e.Plugin{static get requires(){return[c,d]}}const b={Tooltip:h}})(),o=o.default})())); \ No newline at end of file +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.CKEditor5=e():(t.CKEditor5=t.CKEditor5||{},t.CKEditor5.tooltip=e())}(self,(()=>(()=>{var t=[t=>{"use strict";t.exports=CKEditor5.dll},(t,e,i)=>{t.exports=i(0)("./src/core.js")},(t,e,i)=>{t.exports=i(0)("./src/utils.js")},(t,e,i)=>{t.exports=i(0)("./src/ui.js")}],e={};function i(o){var s=e[o];if(void 0!==s)return s.exports;var n=e[o]={exports:{}};return t[o](n,n.exports,i),n.exports}i.d=(t,e)=>{for(var o in e)i.o(e,o)&&!i.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);var o={};return(()=>{"use strict";i.d(o,{default:()=>b});var t=i(1);function e(t,e,i,o){return o.createRange(s(t,e,i,!0,o),s(t,e,i,!1,o))}function s(t,e,i,o,s){let n=t.textNode||(o?t.nodeBefore:t.nodeAfter),r=null;for(;n&&n.getAttribute(e)==i;)r=n,n=o?n.previousSibling:n.nextSibling;return r?s.createPositionAt(r,o?"before":"after"):t}function n(t){return Array.from(t.getItems()).reduce(((t,e)=>e.is("text")||e.is("textProxy")?t+e.data:t),"")}var r=i(2);class l extends t.Command{refresh(){const t=this.editor.model,i=t.document.selection,o=i.getFirstRange();if(o.isCollapsed)if(i.hasAttribute("tooltip")){const o=i.getAttribute("ucb-tooltip"),s=e(i.getFirstPosition(),"ucb-tooltip",o,t);this.value={abbr:n(s),title:o,range:s}}else this.value=null;else if(i.hasAttribute("ucb-tooltip")){const s=i.getAttribute("ucb-tooltip");e(i.getFirstPosition(),"ucb-tooltip",s,t).containsRange(o,!0)?this.value={abbr:n(o),title:s,range:o}:this.value=null}else this.value=null;this.isEnabled=t.schema.checkAttributeInSelection(i,"ucb-tooltip")}execute({abbr:t,title:e}){const i=this.editor.model,o=i.document.selection;i.change((s=>{if(o.isCollapsed){if(this.value){const{end:o}=i.insertContent(s.createText(t,{tooltip:e}),this.value.range);s.setSelection(o)}else if(""!==t){const n=o.getFirstPosition(),l=(0,r.toMap)(o.getAttributes());l.set("ucb-tooltip",e);const{end:c}=i.insertContent(s.createText(t,l),n);s.setSelection(c)}s.removeSelectionAttribute("ucb-tooltip")}else{const t=i.schema.getValidRanges(o.getRanges(),"ucb-tooltip");for(const i of t)s.setAttribute("ucb-tooltip",e,i)}}))}}class c extends t.Plugin{init(){this._defineSchema(),this._defineConverters(),this.editor.commands.add("addTooltip",new l(this.editor))}_defineSchema(){const t=this.editor.model.schema;t.register("ucb-tooltip",{isContent:!0}),t.extend("$text",{allowAttributes:["ucb-tooltip"]})}_defineConverters(){const t=this.editor.conversion;t.for("downcast").attributeToElement({model:"ucb-tooltip",view:(t,e)=>{const{writer:i}=e;return i.createAttributeElement("abbr",{title:t,class:"ucb-tooltip"})}}),t.for("upcast").elementToAttribute({view:{name:"abbr",attributes:["title"],classes:"ucb-tooltip"},model:{key:"ucb-tooltip",value:t=>t.getAttribute("title")}})}}var a=i(3);class u extends a.View{constructor(e){super(e),this.focusTracker=new r.FocusTracker,this.keystrokes=new r.KeystrokeHandler,this.abbrInputView=this._createInput("Add Tooltip"),this.titleInputView=this._createInput("Add Text"),this.saveButtonView=this._createButton("Save",t.icons.check,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton("Cancel",t.icons.cancel,"ck-button-cancel"),this.cancelButtonView.delegate("execute").to(this,"cancel"),this.childViews=this.createCollection([this.abbrInputView,this.titleInputView,this.saveButtonView,this.cancelButtonView]),this._focusCycler=new a.FocusCycler({focusables:this.childViews,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-tooltip-form"],tabindex:"-1"},children:this.childViews})}render(){super.render(),(0,a.submitHandler)({view:this}),this.childViews._items.forEach((t=>{this.focusTracker.add(t.element)})),this.keystrokes.listenTo(this.element)}destroy(){super.destroy(),this.focusTracker.destroy(),this.keystrokes.destroy()}focus(){this.abbrInputView.isEnabled?this.abbrInputView.focus():this.titleInputView.focus()}_createInput(t){const e=new a.LabeledFieldView(this.locale,a.createLabeledInputText);return e.label=t,e}_createButton(t,e,i){const o=new a.ButtonView;return o.set({label:t,icon:e,tooltip:!0,class:i}),o}}class d extends t.Plugin{static get requires(){return[a.ContextualBalloon]}init(){const t=this.editor;this._balloon=this.editor.plugins.get(a.ContextualBalloon),this.formView=this._createFormView(),t.ui.componentFactory.add("tooltip",(()=>{const t=new a.ButtonView;return t.label="Tooltip",t.icon='\x3c!-- Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --\x3e',t.tooltip=!0,t.withText=!1,this.listenTo(t,"execute",(()=>{this._showUI()})),t}))}_createFormView(){const t=this.editor,e=new u(t.locale);return this.listenTo(e,"submit",(()=>{const i={abbr:e.abbrInputView.fieldView.element.value,title:e.titleInputView.fieldView.element.value};t.execute("addTooltip",i),this._hideUI()})),this.listenTo(e,"cancel",(()=>{this._hideUI()})),(0,a.clickOutsideHandler)({emitter:e,activator:()=>this._balloon.visibleView===e,contextElements:[this._balloon.view.element],callback:()=>this._hideUI()}),e}_showUI(){const t=this.editor.model.document.selection,e=this.editor.commands.get("addTooltip").value;if(this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),this.formView.abbrInputView.isEnabled=t.getFirstRange().isCollapsed,e)this.formView.abbrInputView.fieldView.value=e.abbr,this.formView.titleInputView.fieldView.value=e.title;else{const e=n(t.getFirstRange());this.formView.abbrInputView.fieldView.value=e,this.formView.titleInputView.fieldView.value=""}this.formView.focus()}_hideUI(){this.formView.abbrInputView.fieldView.value="",this.formView.titleInputView.fieldView.value="",this.formView.element.reset(),this._balloon.remove(this.formView),this.editor.editing.view.focus()}_getBalloonPositionData(){const t=this.editor.editing.view,e=t.document;let i=null;return i=()=>t.domConverter.viewRangeToDom(e.selection.getFirstRange()),{target:i}}}class h extends t.Plugin{static get requires(){return[c,d]}}const b={Tooltip:h}})(),o=o.default})())); \ No newline at end of file diff --git a/package.json b/package.json index 8f394c8..904e6da 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "b": "run(){ webpack --env plugin=\"$1\"; }; run" }, "devDependencies": { + "@ckeditor/ckeditor5-clipboard": "^41.4.2", "@ckeditor/ckeditor5-core": "~41.4.2", "@ckeditor/ckeditor5-dev-utils": "^40.0.0", "@ckeditor/ckeditor5-engine": "~41.4.2", @@ -20,6 +21,7 @@ "@ckeditor/ckeditor5-utils": "~41.4.2", "@ckeditor/ckeditor5-widget": "~41.4.2", "ckeditor5": "~41.4.2", + "copy-webpack-plugin": "^11.0.0", "raw-loader": "^4.0.2", "terser-webpack-plugin": "^5.2.0", "ts-loader": "^9.5.1", diff --git a/src/Plugin/Filter/BootstrapAccordion.php b/src/Plugin/Filter/BootstrapAccordion.php new file mode 100644 index 0000000..dc557ab --- /dev/null +++ b/src/Plugin/Filter/BootstrapAccordion.php @@ -0,0 +1,135 @@ +query("//div[@data-accordion-id][contains(concat(' ', @class, ' '), ' accordion ')]") as $accordion) { + $accordionIdFromAttribute = $accordion->getAttribute('data-accordion-id'); + $accordionId = 'accordion-' . $accordionIdFromAttribute; + $accordion->setAttribute('id', $accordionId); + $accordionClasses = $this->getClassesFromElement($accordion); + $accordionClasses[] = 'accordion-flush'; + $accordion->setAttribute('class', implode(' ', $accordionClasses)); + $accordionItemCount = 1; + $accordionItemsStayOpen = in_array('accordion-items-stay-open', $accordionClasses); + foreach ($accordion->childNodes as $accordionItem) { + if (!($accordionItem instanceof \DOMElement)) { + continue; + } + $accordionItemClasses = $this->getClassesFromElement($accordionItem); + if (!in_array('accordion-item', $accordionItemClasses)) { + continue; + } + $accordionItemClasses[] = 'tab-content'; + $accordionItem->setAttribute('class', implode(' ', $accordionItemClasses)); + $accordionCollapseId = $accordionId . '-content' . ($accordionItemCount); + $isCollapsed = TRUE; + foreach ($accordionItem->childNodes as $childItem) { + if (!($childItem instanceof \DOMElement)) { + continue; + } + $childItemClasses = $this->getClassesFromElement($childItem); + if (in_array('accordion-header', $childItemClasses)) { + $headerId = $accordionId . '-title' . ($accordionItemCount); + $childItem->setAttribute('id', $headerId); + foreach ($childItem->childNodes as $accordionButton) { + if ($accordionButton instanceof \DOMElement && ($accordionButtonClasses = $this->getClassesFromElement($accordionButton)) && in_array('accordion-button', $accordionButtonClasses)) { + $accordionButton->setAttribute('role', 'button'); + $accordionButton->setAttribute('data-bs-toggle', 'collapse'); + $accordionButton->setAttribute('data-bs-target', '#' . $accordionCollapseId); + $isCollapsed = in_array('collapsed', $accordionButtonClasses); + $accordionButton->setAttribute('aria-expanded', $isCollapsed ? 'false' : 'true'); + $accordionButton->setAttribute('aria-controls', $accordionCollapseId); + $accordionButtonClasses[] = 'expandableHeaders'; + if ($isCollapsed) { + $accordionButtonClasses[] = 'collapsed'; + } + $accordionButton->setAttribute('class', implode(' ', $accordionButtonClasses)); + if ($accordionButton->hasAttribute('href')) { + $accordionButton->setAttribute('href', '#' . $accordionCollapseId); + } + // Add ID to button based on its text content + $buttonId = strtolower(preg_replace('/[^a-zA-Z0-9-]/', '-', trim($accordionButton->textContent))); + $accordionButton->setAttribute('id', $buttonId); + } + } + } + elseif (in_array('collapse', $childItemClasses)) { + $childItem->setAttribute('id', $accordionCollapseId); + $childItemClasses = array_diff($childItemClasses, ['collapse']); + $childItemClasses[] = 'accordion-collapse'; + $childItemClasses[] = 'collapse'; + if (!$isCollapsed) { + $childItemClasses[] = 'show'; + } + $childItem->setAttribute('class', implode(' ', $childItemClasses)); + $childItem->setAttribute('aria-labelledby', $accordionId . '-title' . ($accordionItemCount)); + $childItem->setAttribute('data-bs-parent', '#' . $accordionId); + + // Wrap accordion body content in a div + foreach ($childItem->childNodes as $accordionBody) { + if ($accordionBody instanceof \DOMElement && in_array('accordion-body', $this->getClassesFromElement($accordionBody))) { + $contentDiv = $dom->createElement('div'); + while ($accordionBody->hasChildNodes()) { + $contentDiv->appendChild($accordionBody->firstChild); + } + $accordionBody->appendChild($contentDiv); + } + } + } + } + $accordionItemCount++; + } + } + + $result->setProcessedText(Html::serialize($dom)); + + return $result; + } + + /** + * Gets the classes from a DOMElement as an array of strings. + * + * @param \DOMElement $element + * The element. + * + * @return string[] + * The element's CSS classes. + */ + protected function getClassesFromElement(\DOMElement $element) { + if (!$element->hasAttribute('class')) { + return []; + } + return preg_split('/\s+/', $element->getAttribute('class')); + } + +} \ No newline at end of file diff --git a/ucb_ckeditor_plugins.ckeditor5.yml b/ucb_ckeditor_plugins.ckeditor5.yml index c680614..6a677dc 100644 --- a/ucb_ckeditor_plugins.ckeditor5.yml +++ b/ucb_ckeditor_plugins.ckeditor5.yml @@ -407,3 +407,31 @@ ucb_ckeditor_plugins_jumpmenu: elements: - - + +ucb_ckeditor_plugins_bootstrapAccordion: + # Configuration that will be sent to CKEditor 5 JavaScript plugins. + ckeditor5: + plugins: + - bootstrapAccordion.BootstrapAccordion + - bootstrapAccordion.BootstrapAccordionClipboardPipeline + - bootstrapAccordion.BootstrapAccordionGeneralHtmlSupport + config: + bootstrapAccordion: + toolbarItems: + - bootstrapAccordionItem + - bootstrapAccordionOpenCollapse + # Configuration that will be used directly by Drupal. + drupal: + label: Bootstrap Accordion + library: ucb_ckeditor_plugins/bootstrapAccordion.editor + admin_library: ucb_ckeditor_plugins/bootstrapAccordion.admin + toolbar_items: + bootstrapAccordion: + label: Accordion + elements: + -

+ -