@silexlabs/grapesjs-data-source
Version:
Grapesjs Data Source
256 lines • 10.2 kB
JavaScript
;
/*
* Silex website builder, free/libre no-code tool for makers.
* Copyright (c) 2023 lexoyo and Silex Labs foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PropertiesEditor = void 0;
const lit_1 = require("lit");
const ref_js_1 = require("lit/directives/ref.js");
const decorators_js_1 = require("lit/decorators.js");
require("./state-editor");
const defaultStyles_1 = require("./defaultStyles");
const token_1 = require("../model/token");
const types_1 = require("../types");
const state_1 = require("../model/state");
const utils_1 = require("../utils");
/**
* Editor for selected element's properties
*
* Usage:
*
* ```
* <properties-editor disabled>
* <style> / * Custom styles * / </style>
* </properties-editor>
* ```
*
*/
class PropertiesEditor extends lit_1.LitElement {
constructor() {
super(...arguments);
this.disabled = false;
this.defaultFixed = false;
this.inputs = {
innerHTML: undefined,
condition: undefined,
condition2: undefined,
__data: undefined,
};
this.editor = null;
this.redrawing = false;
}
setEditor(editor) {
if (this.editor) {
console.warn('property-editor setEditor already set');
return;
}
this.editor = editor;
// Update the UI when a page is added/renamed/removed
this.editor.on('page', () => this.requestUpdate());
// Update the UI on component selection change
this.editor.on('component:selected', () => this.requestUpdate());
// Update the UI on component change
this.editor.on('component:update', () => this.requestUpdate());
}
render() {
var _a;
super.render();
this.redrawing = true;
const selected = (_a = this.editor) === null || _a === void 0 ? void 0 : _a.getSelected();
const head = (0, lit_1.html) `
<style>
${defaultStyles_1.PROPERTY_STYLES}
</style>
<slot></slot>
`;
const empty = (0, lit_1.html) `
${head}
<p class="ds-empty">Select an element to edit its properties</p>
`;
if (!this.editor || this.disabled) {
this.resetInputs();
this.redrawing = false;
return (0, lit_1.html) ``;
}
if (!selected || selected.get('tagName') === 'body') {
this.resetInputs();
this.redrawing = false;
return empty;
}
const result = (0, lit_1.html) `
${head}
<section class="ds-section">
<div>
<div class="gjs-traits-label">
Properties
<details class="ds-states__help">
<summary>Help</summary>
<div class="ds-states__help--tooltip">
Elements properties are expressions that can replace the HTML attributes of the element or it's whole content (innerHTML).
<a target="_blank" href="https://docs.silex.me/en/user/cms-concepts#properties">Learn more about element properties</a>
</div>
</details>
</div>
</div>
<main>
${[
{ label: 'HTML content', name: types_1.Properties.innerHTML, publicState: false },
].map(({ label, name, publicState }) => this.renderStateEditor(selected, label, name, publicState))}
</main>
</section>
<section class="ds-section">
<main>
${this.renderStateEditor(selected, 'Visibility Condition', types_1.Properties.condition, false)}
<div>
<span>... is</span>
<select
class="ds-visibility__condition-operator"
@change=${(e) => {
const select = e.target;
const value = select.value;
if (!value)
throw new Error('Selection required for operator select element');
selected.set('conditionOperator', value);
this.requestUpdate();
}}
>
</div>
${Object.values(types_1.UnariOperator)
.concat(Object.values(types_1.BinaryOperator))
.map(operator => (0, lit_1.html) `
<option value="${operator}" .selected=${selected.get('conditionOperator') === operator} >${operator}</option>
`)}
</select>
${this.renderStateEditor(selected, '', types_1.Properties.condition2, false, false, selected.has('conditionOperator') && Object.values(types_1.BinaryOperator).includes(selected.get('conditionOperator')))}
</main>
</section>
<section class="ds-section">
<main>
${this.renderStateEditor(selected, 'Loop Data', types_1.Properties.__data, false, true)}
</main>
</section>
`;
this.redrawing = false;
return result;
}
resetInputs() {
this.inputs = {
innerHTML: undefined,
condition: undefined,
condition2: undefined,
__data: undefined,
};
}
renderStateEditor(selected, label, name, publicState, hideLoopData = false, visible = true) {
return (0, lit_1.html) `
<state-editor
.style=${visible ? '' : 'display: none;'}
.selected=${selected}
.editor=${this.editor}
id="${name}"
name=${name}
default-fixed=${this.defaultFixed}
?hide-loop-data=${hideLoopData}
${(0, ref_js_1.ref)(el => {
// Get the stateEditor ref
if (el) {
// Set the editor - we could do this only once
const stateEditor = el;
// Store the stateEditor ref and the component it is representing
if (!this.inputs[name]) {
this.inputs[name] = {
stateEditor,
selected: undefined, // clear the selected component so that we update the data
};
}
}
// Finally update the data
if (this.inputs[name]) {
const stateEditorFinally = this.inputs[name].stateEditor;
this.redrawing = true;
try {
stateEditorFinally.data = this.getTokens(selected, name, publicState);
}
catch (e) {
console.error('Error setting data', e);
stateEditorFinally.data = [(0, utils_1.getFixedToken)(`Error setting data: ${e}`)];
}
this.redrawing = false;
// Store the selected component
this.inputs[name].selected = selected;
}
})}
@change=${() => this.onChange(selected, name, publicState)}
?disabled=${this.disabled}
>
<label slot="label">${label}</label>
</state-editor>
`;
}
onChange(component, name, publicState) {
const { stateEditor } = this.inputs[name];
if (this.redrawing)
return;
if (name === types_1.Properties.__data) {
// Handle the case when data is empty (after clearing)
if (stateEditor.data.length === 0) {
(0, state_1.setState)(component, name, {
expression: [],
}, publicState);
}
else {
(0, state_1.setState)(component, name, {
expression: stateEditor.data.slice(0, -1).concat(Object.assign(Object.assign({}, stateEditor.data[stateEditor.data.length - 1]), { previewIndex: 0 })),
}, publicState);
}
}
else {
(0, state_1.setState)(component, name, {
expression: stateEditor.data,
}, publicState);
}
}
getTokens(component, name, publicState) {
const state = (0, state_1.getState)(component, name, publicState);
if (!state || !state.expression)
return [];
return state.expression
.filter(token => token && typeof token === 'object' && token.type) // Filter out invalid tokens
.map(token => (0, token_1.fromStored)(token, component.getId()));
}
}
exports.PropertiesEditor = PropertiesEditor;
__decorate([
(0, decorators_js_1.property)({ type: Boolean }),
__metadata("design:type", Object)
], PropertiesEditor.prototype, "disabled", void 0);
__decorate([
(0, decorators_js_1.property)({ type: Boolean, attribute: 'default-fixed' }),
__metadata("design:type", Object)
], PropertiesEditor.prototype, "defaultFixed", void 0);
if (!window.customElements.get('properties-editor')) {
window.customElements.define('properties-editor', PropertiesEditor);
}
//# sourceMappingURL=properties-editor.js.map