handle rich text rules on the client
This commit is contained in:
@@ -52,25 +52,7 @@ export class UmbStylesheetRuleInputElement extends FormControlMixin(UmbLitElemen
|
||||
return true;
|
||||
}
|
||||
|
||||
setRules(rules: UmbSortableStylesheetRule[]) {
|
||||
/*
|
||||
const newRules = rules.map((r, i) => ({ ...r, sortOrder: i }));
|
||||
this.#rules.next(newRules);
|
||||
this.sendRulesGetContent();
|
||||
*/
|
||||
}
|
||||
|
||||
#onChange(event: UUIComboboxEvent) {
|
||||
event.stopPropagation();
|
||||
const target = event.target as UUIComboboxElement;
|
||||
|
||||
if (typeof target?.value === 'string') {
|
||||
this.value = target.value;
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
}
|
||||
}
|
||||
|
||||
addRule = (rule: UmbSortableStylesheetRule | null = null) => {
|
||||
#openRuleSettings = (rule: UmbSortableStylesheetRule | null = null) => {
|
||||
if (!this.#modalManager) throw new Error('Modal context not found');
|
||||
const modalContext = this.#modalManager.open(UMB_STYLESHEET_RULE_SETTINGS_MODAL, {
|
||||
value: {
|
||||
@@ -79,18 +61,15 @@ export class UmbStylesheetRuleInputElement extends FormControlMixin(UmbLitElemen
|
||||
});
|
||||
|
||||
modalContext?.onSubmit().then((value) => {
|
||||
console.log(value);
|
||||
/*
|
||||
if (result.rule) {
|
||||
console.log(result.rule);
|
||||
//this.#context?.setRules([...this._rules, { ...result.rule, sortOrder: this._rules.length }]);
|
||||
}
|
||||
*/
|
||||
const newRule: UmbSortableStylesheetRule = { ...value.rule, sortOrder: this.rules.length };
|
||||
this.rules = [...this.rules, newRule];
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
});
|
||||
};
|
||||
|
||||
removeRule = (rule: UmbSortableStylesheetRule) => {
|
||||
//const rules = this._rules?.filter((r) => r.name !== rule.name);
|
||||
#removeRule = (rule: UmbSortableStylesheetRule) => {
|
||||
this.rules = this.rules.filter((r) => r.name !== rule.name);
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -103,11 +82,15 @@ export class UmbStylesheetRuleInputElement extends FormControlMixin(UmbLitElemen
|
||||
<umb-stylesheet-rule-ref
|
||||
name=${rule.name}
|
||||
detail=${rule.selector}
|
||||
data-umb-rule-name="${ifDefined(rule?.name)}"></umb-stylesheet-rule-ref>
|
||||
data-umb-rule-name="${ifDefined(rule?.name)}">
|
||||
<uui-action-bar slot="actions">
|
||||
<uui-button @click=${() => this.#removeRule(rule)} label="Remove ${rule.name}">Remove</uui-button>
|
||||
</uui-action-bar>
|
||||
</umb-stylesheet-rule-ref>
|
||||
`,
|
||||
)}
|
||||
</uui-ref-list>
|
||||
<uui-button label="Add rule" look="placeholder" @click=${() => this.addRule(null)}>Add</uui-button>
|
||||
<uui-button label="Add rule" look="placeholder" @click=${() => this.#openRuleSettings(null)}>Add</uui-button>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from './rich-text-rule/index.js';
|
||||
export * from './item/index.js';
|
||||
|
||||
export * from './stylesheet-detail.repository.js';
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { UmbStylesheetRichTextRuleRepository } from './stylesheet-rich-text-rule.repository.js';
|
||||
@@ -1,43 +0,0 @@
|
||||
import { UmbStylesheetRichTextRuleServerDataSource } from './stylesheet-rich-text-rule.server.data-source.js';
|
||||
import { type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository';
|
||||
import {
|
||||
ExtractRichTextStylesheetRulesRequestModel,
|
||||
InterpolateRichTextStylesheetRequestModel,
|
||||
} from '@umbraco-cms/backoffice/backend-api';
|
||||
|
||||
export class UmbStylesheetRichTextRuleRepository extends UmbRepositoryBase {
|
||||
#dataSource;
|
||||
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host);
|
||||
|
||||
this.#dataSource = new UmbStylesheetRichTextRuleServerDataSource(host);
|
||||
}
|
||||
|
||||
requestStylesheetRules(unique: string) {
|
||||
return this.#dataSource.getStylesheetRichTextRules(unique);
|
||||
}
|
||||
|
||||
/**
|
||||
* Existing content + array of rules => new content string
|
||||
*
|
||||
* @param {InterpolateRichTextStylesheetRequestModel} data
|
||||
* @return {*} {Promise<DataSourceResponse<InterpolateRichTextStylesheetResponseModel>>}
|
||||
* @memberof UmbStylesheetRepository
|
||||
*/
|
||||
interpolateStylesheetRules(data: InterpolateRichTextStylesheetRequestModel) {
|
||||
return this.#dataSource.interpolateStylesheetRules(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* content string => array of rules
|
||||
*
|
||||
* @param {ExtractRichTextStylesheetRulesRequestModel} data
|
||||
* @return {*}
|
||||
* @memberof UmbStylesheetRepository
|
||||
*/
|
||||
extractStylesheetRules(data: ExtractRichTextStylesheetRulesRequestModel) {
|
||||
return this.#dataSource.extractStylesheetRules(data);
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import { UmbServerPathUniqueSerializer } from '../../../utils/index.js';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import {
|
||||
ExtractRichTextStylesheetRulesRequestModel,
|
||||
InterpolateRichTextStylesheetRequestModel,
|
||||
StylesheetResource,
|
||||
} from '@umbraco-cms/backoffice/backend-api';
|
||||
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
|
||||
|
||||
/**
|
||||
* A data source for the Stylesheet rich text rules that fetches data from the server
|
||||
* @export
|
||||
* @class UmbStylesheetRichTextRuleServerDataSource
|
||||
*/
|
||||
export class UmbStylesheetRichTextRuleServerDataSource {
|
||||
#host: UmbControllerHost;
|
||||
#serverPathUniqueSerializer = new UmbServerPathUniqueSerializer();
|
||||
|
||||
/**
|
||||
* Creates an instance of UmbStylesheetRichTextRuleServerDataSource.
|
||||
* @param {UmbControllerHost} host
|
||||
* @memberof UmbStylesheetRichTextRuleServerDataSource
|
||||
*/
|
||||
constructor(host: UmbControllerHost) {
|
||||
this.#host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get's the rich text rules for a stylesheet
|
||||
*
|
||||
* @param {string} unique
|
||||
* @return {*}
|
||||
* @memberof UmbStylesheetRichTextRuleServerDataSource
|
||||
*/
|
||||
getStylesheetRichTextRules(unique: string) {
|
||||
const path = this.#serverPathUniqueSerializer.toServerPath(unique);
|
||||
return tryExecuteAndNotify(this.#host, StylesheetResource.getStylesheetRichTextRules({ path }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the rich text rules from a stylesheet string. In simple words: takes a stylesheet string and returns a array of rules.
|
||||
*
|
||||
* @param {ExtractRichTextStylesheetRulesRequestModel} data
|
||||
* @return {*}
|
||||
* @memberof UmbStylesheetRichTextRuleServerDataSource
|
||||
*/
|
||||
extractStylesheetRules(data: ExtractRichTextStylesheetRulesRequestModel) {
|
||||
return tryExecuteAndNotify(
|
||||
this.#host,
|
||||
StylesheetResource.postStylesheetRichTextExtractRules({ requestBody: data }),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates the rich text rules from a stylesheet string. In simple words: takes a array of rules and existing content. Returns new content with the rules applied.
|
||||
*
|
||||
* @param {InterpolateRichTextStylesheetRequestModel} data
|
||||
* @return {*}
|
||||
* @memberof UmbStylesheetRichTextRuleServerDataSource
|
||||
*/
|
||||
interpolateStylesheetRules(data: InterpolateRichTextStylesheetRequestModel) {
|
||||
return tryExecuteAndNotify(
|
||||
this.#host,
|
||||
StylesheetResource.postStylesheetRichTextInterpolateRules({ requestBody: data }),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { UmbStylesheetRuleManager } from './stylesheet-rule-manager.js';
|
||||
@@ -0,0 +1,47 @@
|
||||
import { RichTextRuleModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
|
||||
export class UmbStylesheetRuleManager {
|
||||
#umbRuleRegex = /\/\*\*\s*umb_name:\s*(?<name>[^*\r\n]*?)\s*\*\/\s*(?<selector>[^,{]*?)\s*{\s*(?<styles>.*?)\s*}/gis;
|
||||
|
||||
/**
|
||||
* Extracts umbraco rules from a stylesheet content
|
||||
* @param {string} stylesheetContent
|
||||
* @return {*}
|
||||
* @memberof UmbStylesheetRuleManager
|
||||
*/
|
||||
extractRules(stylesheetContent: string) {
|
||||
const regex = this.#umbRuleRegex;
|
||||
if (!stylesheetContent) throw Error('No Stylesheet content');
|
||||
return [...stylesheetContent.matchAll(regex)].map((match) => match.groups);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts umbraco rules into stylesheet content
|
||||
* @param {string} stylesheetContent
|
||||
* @param {UmbStylesheetRule[]} rules
|
||||
* @return {*}
|
||||
* @memberof UmbStylesheetRuleManager
|
||||
*/
|
||||
insertRules(stylesheetContent: string, rules: Array<RichTextRuleModel>) {
|
||||
const regex = this.#umbRuleRegex;
|
||||
if (!stylesheetContent) throw Error('No Stylesheet content');
|
||||
if (!stylesheetContent && !rules) return { content: '' };
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore
|
||||
const cleanedContent = stylesheetContent?.replaceAll(regex, '');
|
||||
const newContent = `
|
||||
${cleanedContent.replace(/[\r\n]+$/, '')}
|
||||
${rules
|
||||
?.map(
|
||||
(rule) => `
|
||||
/**umb_name:${rule.name}*/
|
||||
${rule.selector} {
|
||||
${rule.styles}
|
||||
}
|
||||
`,
|
||||
)
|
||||
.join('')}`;
|
||||
return newContent;
|
||||
}
|
||||
}
|
||||
@@ -99,34 +99,6 @@ export class UmbStylesheetWorkspaceContext
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
async sendRulesGetContent() {
|
||||
const requestBody = {
|
||||
content: this.getData()?.content,
|
||||
rules: this.getRules(),
|
||||
};
|
||||
const { data } = await this.repository.interpolateStylesheetRules(requestBody);
|
||||
this.setContent(data?.content ?? '');
|
||||
}
|
||||
|
||||
async sendContentGetRules() {
|
||||
const content = this.getData()?.content;
|
||||
if (!content) throw Error('No content');
|
||||
|
||||
const { data } = await this.repository.extractStylesheetRules({ content });
|
||||
this.setRules(data?.rules ?? []);
|
||||
}
|
||||
|
||||
getRules() {
|
||||
return this.#rules.getValue();
|
||||
}
|
||||
|
||||
updateRule(unique: string, rule: RichTextRuleModelSortable) {
|
||||
this.#rules.updateOne(unique, rule);
|
||||
this.sendRulesGetContent();
|
||||
}
|
||||
*/
|
||||
|
||||
public destroy(): void {
|
||||
this.#data.destroy();
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { UmbStylesheetWorkspaceContext } from '../../stylesheet-workspace.context.js';
|
||||
import { UmbStylesheetRichTextRuleRepository } from '../../../repository/index.js';
|
||||
import { UmbSortableStylesheetRule } from '../../../types.js';
|
||||
import { UmbStylesheetRuleInputElement } from '../../../components/index.js';
|
||||
import { UmbStylesheetRuleManager } from '../../../utils/index.js';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
|
||||
@customElement('umb-stylesheet-rich-text-rule-workspace-view')
|
||||
export class UmbStylesheetRichTextRuleWorkspaceViewElement extends UmbLitElement {
|
||||
@@ -12,24 +14,36 @@ export class UmbStylesheetRichTextRuleWorkspaceViewElement extends UmbLitElement
|
||||
_rules: UmbSortableStylesheetRule[] = [];
|
||||
|
||||
#context?: UmbStylesheetWorkspaceContext;
|
||||
|
||||
#stylesheetRichTextRuleRepository = new UmbStylesheetRichTextRuleRepository(this);
|
||||
#stylesheetRuleManager = new UmbStylesheetRuleManager();
|
||||
#stylesheetContent = '';
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_WORKSPACE_CONTEXT, (workspaceContext) => {
|
||||
this.#context = workspaceContext as UmbStylesheetWorkspaceContext;
|
||||
const unique = this.#context?.getEntityId();
|
||||
this.#setRules(unique);
|
||||
this.#observeContent();
|
||||
});
|
||||
}
|
||||
|
||||
async #setRules(unique: string) {
|
||||
const { data } = await this.#stylesheetRichTextRuleRepository.requestStylesheetRules(unique);
|
||||
#observeContent() {
|
||||
if (!this.#context?.content) return;
|
||||
this.observe(
|
||||
this.#context.content,
|
||||
(content) => {
|
||||
this.#stylesheetContent = content;
|
||||
this.#extractRules(content);
|
||||
},
|
||||
'umbStylesheetContentObserver',
|
||||
);
|
||||
}
|
||||
|
||||
if (data) {
|
||||
this._rules = data.rules ?? [];
|
||||
#extractRules(content: string | undefined) {
|
||||
if (content) {
|
||||
const rules = this.#stylesheetRuleManager.extractRules(content);
|
||||
this._rules = [...rules];
|
||||
} else {
|
||||
this._rules = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +51,8 @@ export class UmbStylesheetRichTextRuleWorkspaceViewElement extends UmbLitElement
|
||||
event.stopPropagation();
|
||||
const target = event.target as UmbStylesheetRuleInputElement;
|
||||
const rules = target.rules;
|
||||
console.log(rules);
|
||||
console.log(event);
|
||||
debugger;
|
||||
const newContent = this.#stylesheetRuleManager.insertRules(this.#stylesheetContent, rules);
|
||||
this.#context?.setContent(newContent);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
import { UMB_STYLESHEET_WORKSPACE_CONTEXT, UmbStylesheetWorkspaceContext } from '../../stylesheet-workspace.context.js';
|
||||
import { UMB_MODAL_TEMPLATING_STYLESHEET_RTF_STYLE_SIDEBAR_MODAL } from './stylesheet-rich-text-rule-workspace-view.element.js';
|
||||
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { RichTextRuleModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UMB_MODAL_MANAGER_CONTEXT_TOKEN, UmbModalManagerContext } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
|
||||
@customElement('umb-stylesheet-rich-text-editor-rule')
|
||||
export default class UmbStylesheetRichTextEditorRuleElement extends UmbLitElement {
|
||||
@property({ attribute: false })
|
||||
private rule: RichTextRuleModel | null = null;
|
||||
|
||||
#context?: UmbStylesheetWorkspaceContext;
|
||||
private _modalContext?: UmbModalManagerContext;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_STYLESHEET_WORKSPACE_CONTEXT, (workspaceContext) => {
|
||||
this.#context = workspaceContext;
|
||||
});
|
||||
|
||||
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => {
|
||||
this._modalContext = instance;
|
||||
});
|
||||
}
|
||||
|
||||
#openModal() {
|
||||
if (!this._modalContext) throw new Error('Modal context not found');
|
||||
const modal = this._modalContext.open(UMB_MODAL_TEMPLATING_STYLESHEET_RTF_STYLE_SIDEBAR_MODAL, {
|
||||
value: {
|
||||
rule: this.rule,
|
||||
},
|
||||
});
|
||||
modal?.onSubmit().then((value) => {
|
||||
if (value.rule && this.rule?.name) {
|
||||
this.#context?.updateRule(this.rule?.name, value.rule);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#removeRule() {
|
||||
//TODO: SPORTER BREAKS THAT - rules are removed from the data but not from the DOM
|
||||
if (!this.#context) throw new Error('Context not found');
|
||||
this.#context.setRules(this.#context.getRules().filter((r) => r.name !== this.rule?.name));
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="rule-name"><uui-icon name="icon-navigation"></uui-icon>${this.rule?.name}</div>
|
||||
<div class="rule-actions">
|
||||
<uui-button label="Edit" look="secondary" @click=${this.#openModal}>Edit</uui-button
|
||||
><uui-button label="Remove" look="secondary" color="danger" @click=${this.#removeRule}>Remove</uui-button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
UmbTextStyles,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
padding: var(--uui-size-2);
|
||||
align-items: center;
|
||||
border-radius: var(--uui-border-radius);
|
||||
background-color: var(--uui-color-surface-alt);
|
||||
margin-bottom: var(--uui-size-space-4);
|
||||
}
|
||||
|
||||
.rule-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--uui-size-2);
|
||||
padding-left: var(--uui-size-2);
|
||||
font-weight: bold;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-stylesheet-rich-text-editor-rule': UmbStylesheetRichTextEditorRuleElement;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user