Link Search Menu Expand Document

module @sivujetti-commons-for-edit-app

Moduuli, jota voidaan käyttää lisäosissa, ks. Luo lisäosa - osa 1 - todo. Tämäkin moduuli, kuten @sivujetti-commons-for-web-pages, on teknisesti globaali muuttuja jota [rollupin ansiosta] vain käytetään kuten tavallista javascript-moduulia.

Lähdekoodi

frontend/commons-for-edit-app/main.js .

Exports

__()

export function __(key: string, ...args?: any) => string;

Examples

import {__} from '@sivujetti-commons-for-edit-app';

const translated = __('Cancel');
console.log(translated); // "Kumoa"

const translated2 = __('New %s created', __('page'));
console.log(translated2); // "Uusi sivu luotiin"

api

export const api: SivujettiFrontendApi;

interface SivujettiFrontendApi {
    getPageTypes(): Array<PageType>;
    getBlockRenderers(): Array<BlockRenderer>;
    menuPanel: MenuPanel;
    blockTypes: BlockTypesRegister;
    saveButton: {
        todo: todo;
    };
    user: {
        can(doWhat: 'doAnything'|'editGlobalStylesVisually'|'editBlockCss'|'createPageTypes'|
                    'createPages'|'createReusableBranches'|'createGlobalBlockTrees'|'specializeGlobalBlocks'|
                    'editTheWebsitesBasicInfo'|'editTheWebsitesGlobalScripts'|'listUploads'): boolean;
        getRole(): number;
        ROLE_SUPER_ADMIN: number;
        ROLE_ADMIN: number;
        ROLE_ADMIN_EDITOR: number;
        ROLE_EDITOR: number;
        ROLE_AUTHOR: number;
        ROLE_CONTRIBUTOR: number;
        ROLE_FOLLOWER: number;
    };
    registerTranslationstrings(strings: {[key: string]: string}): void;
}

interface PageType {
    name: string;
    friendlyName: string;
    friendlyNamePlural: string;
    description: string;
    slug: string;
    defaultLayoutId: string;
    status: number;
    isListable: boolean;
    initialBlocks: Array<BlockBlueprint>;
    ownFields: Array<PageTypeField>;
    defaultFields: {
        [key: string]: {
            defaultValue: string;
        };
    };
}

interface PageTypeField {
    name: string;
    friendlyName: string;
    dataType: {
        type: 'text'|'json'|'int'|'uint';
        isNullable: boolean;
        length?: number;
        validationRules?: Array;
        canBeEditedBy?: number;
        rel?: string;
    };
    defaultValue: string|Array|Object|null;
}

interface BlockBlueprint {
    blockType: string;
    initialOwnData: {[key: string]: any;};
    initialDefaultsData: {
        title: string;
        renderer: string;
        styleClasses: string;
    };
    initialStyles: Array<StyleChunk>;
    initialChildren: Array<BlockBlueprint>;
}

interface StyleChunk {
    scss: string;
    scope: {
        kind: styleScopeKind;
        layer: stylesLayer;
        page?: string; // Example '-NGLsmQwm7aOSH-lS1-J:Pages'
    };
    data?: {
        title?: string;
        customizationSettings?: {
            varDefs: Array<VisualStylesFormVarDefinition>;
        };
        associatedBlockTypes?: Array<string>;
    };
}

type styleScopeKind = 'single-block'|'custom-class'|'base-vars'|'base-freeform';

type stylesLayer = 'user-styles'|'dev-styles'|'base-styles';

interface VisualStylesFormVarDefinition {
    varName: string;             // Example 'textAlign'
    cssProp: string;             // Example 'text-align'
    cssTemplate: string|null;    // Example 'border: 1px solid %s'
    cssSubSelector: string|null; // Example '>img'
    widgetSettings: VisualStylesFormVarDefinitionWidgetSettings & {[possibleExtras: string]: any;};
}

interface VisualStylesFormVarDefinitionWidgetSettings {
    valueType?: string;          // 'color'|'option' etc.
    renderer?: preact.Component; // ColorValueInput|OptionValueInput etc.
    label: string;               // Example 'Text align'
    defaultThemeValue?:          // Example {num: '6', unit: 'rem'}
        ColorValue |
        GridColumnsValue |
        ImageValue |
        LengthValue |
        OptionValue |
        string;
}

interface BlockRenderer {
    fileId: string;
    friendlyName: string|null;
    associatedWith: string|null;
}

interface MenuPanel {
    scrollTo(blockId: string, behavior: 'smooth'|'auto' = 'smooth');
    scrollToSection(name: mainPanelSectionName, behavior: 'smooth'|'auto' = 'smooth');
    getOuterEl(): HTMLElement;
    setSectionCmp(name: mainPanelSectionName, cmp: preact.Component);
    getSectionCmp(name: mainPanelSectionName): preact.Component|null;
    getSectionEl(name: mainPanelSectionName): HTMLElement;
    registerSection(name: string, Cls: preact.AnyComponent): void;
    getSection(name: string, doThrowIfNotFound: boolean = false): preact.AnyComponent;
    getSections(): Map<preact.AnyComponent>;
}

type mainPanelSectionName = 'onThisPage'|'baseStyles';

interface BlockTypesRegister {
    setup(defaultBlockTypes: Array<[string, BlockTypeDefinition]>): void;
    register(name: string, blockTypeFactory: () => BlockTypeDefinition): void;
    get(name: string): BlockTypeDefinition;
    getIconId(blockType: BlockTypeDefinition|string, fallback: string = 'box'): string;
    entries(): IterableIterator<string, BlockTypeDefinition>;
}

interface BlockTypeDefinition {
    name: string;         // Examples 'Text'
    friendlyName: string; // Examples 'Text'
    editForm: preact.Component|null;
    stylesEditForm: 'default'|preact.Component|null;
    createOwnProps(defProps: {[key: string]: any;}): {[propName: string]: any};
    icon?: string;        // Examples 'blockquote'
}

events

export const events: Events;

interface Events {
    on(when: string, thenDo: (...any) => void): Function;
    emit(eventName: string, ...args: any): void;
}

Examples

import {events} from '@sivujetti-commons-for-edit-app';

const unregister = events.on('route-changed', (e, isMainColumnView) => {
    console.log('route changed', e)
});
unregister();

events.trigger('my-plugin-did-something', 'thing');

floatingDialog

export const floatingDialog: FloatingDialog;

interface FloatingDialog {
    open(
        Renderer: preact.ComponentType|string,
        settings: FloatingDialogSettingsInput & {[key: string]: any;},
        rendererProps: Object
    ): void;
    close(): void;
    setTitle(title: string): void;
    setOnBeforeClose(fn: () => void): void;
    setHeight(height: number, instructions: 'animate'|'' = ''): void;
}

interface FloatingDialogSettingsInput {
    title: string;
    width?: number;
    height?: number;
}

Examples

import {floatingDialog} from '@sivujetti-commons-for-edit-app';

class MyPopup extends preact.Component {
    render({prop}) {
        return [
            <div>{ prop }</div>,
            <button
                onClick={ () => floatingDialog.close() }
                class="btn btn-link"
                type="button">Ok</button>
        ];
    }
}

floatingDialog.open(MyPopup, {
    title: 'My popup',
}, {
    prop: 'foo',
});

<FormGroup/>

export class FormGroup extends preact.Component<{className?: string;}, any> {
    // No public methods
}

Examples

import {FormGroup, hookForm, Input, InputErrors} from '@sivujetti-commons-for-edit-app';

class MyForm extends preact.Component {
    componentWillMount() {
        this.setState(hookForm(this, [
            {name: 'something', value: '..', validations: [['minLength', 1]], label: 'Something'},
        ]));
    }
    render(_, {values, errors}) {
        return <div>
            <FormGroup className="foo">
                <label htmlFor="myform_something" class="form-label">Something</label>
                <Input vm={ this } prop="something" id="myform_something"/>
                <InputErrors vm={ this } prop="something"/>
            </FormGroup>
            <div>
                You typed: { values.something.value }
            </div>
            <div>
                Errors: { JSON.stringify(errors.something) }
            </div>
        </div>;
    }
}

<FormGroupInline/>

export class FormGroupInline extends preact.Component<{
    className?: string;
    labelFlow?: 'ellipsis'|'break';
}, any> {
    // No public methods
}

handleSubmit()

export function handleSubmit(
    cmp: preact.Component,
    fn: Promise<any>,
    e: Event = null
): boolean|null;

hasErrors()

export function hasErrors(cmp: preact.Component): boolean;

hookForm()

export function hookForm(
    cmp: preact.Component,
    inputs: Array<InputDefinition>,
    initialState: {[key: string]: any;} = {}
): {[key: string]: any;};

interface InputDefinition {
    name: string;                         // e.g. 'numColumns'
    value: string|number;                 // e.g. 1, 'foo'
    validations: Array<[string, ...any]>; // e.g. [['min', 0], ['max', 12]]
    id?: string;                          // e.g. 'numColumns'
    label?: string;                       // e.g. 'Num columns'
    valueType?: string;                   // e.g. 'int'
    type?: string;                        // e.g. 'number'
    // maybe other props
}

<Icon/>

export class Icon extends preact.Component<{
    // see github.com/sivujetti/sivujetti/blob/master/public/sivujetti/assets/tabler-sprite-custom.svg
    iconId: stockId|string;
    className?: string;
}, any> {
    // No public methods
}

type stockId = 'alert-triangle' |
    'arrow-back-up' |
    'at' |
    'ban' |
    'blockquote' |
    'box' |
    'check' |
    'checkbox' |
    'chevron-down' |
    'chevron-right' |
    'circle-plus' |
    'circle-x' |
    'circle' |
    'code' |
    'columns-3' |
    'database' |
    'device-floppy' |
    'dots' |
    'external-link' |
    'eye' |
    'eye-off' |
    'file-info' |
    'file-plus' |
    'file-text' |
    'file' |
    'files' |
    'grid-dots' |
    'hand-finger' |
    'heading' |
    'info-circle' |
    'layout-columns' |
    'layout-grid' |
    'layout-list' |
    'layout-rows' |
    'letter-p' |
    'letter-t' |
    'lifebuoy' |
    'list' |
    'list-details' |
    'macro' |
    'map-pin' |
    'menu-2' |
    'message-2' |
    'new-section' |
    'number-1' |
    'palette' |
    'pencil' |
    'photo' |
    'plus' |
    'question-mark' |
    'rectangle' |
    'refresh' |
    'rotate' |
    'search' |
    'selector' |
    'settings' |
    'send' |
    'slideshow' |
    'star' |
    'writing' |
    'x';

<Input/>

export class Input extends preact.Component<{
    vm: preact.Component;
    prop: string;
}, any> {
    // No public methods
}

<InputError/>

export class InputError extends preact.Component<{
    errorMessage?: string;
}, any> {
    // No public methods
}

<InputErrors/>

export class InputErrors extends preact.Component<{
    vm?: preact.Component;
    prop?: string;
    errors?: Array<{message: string;}>;
}, any> {
    // No public methods
}
export class MenuSection extends preact.Component<{
    title: string;
    subtitle: string;
    iconId: string;
    colorClass: string;
    outerClass?: string;
    buttonClass?: string;
    onIsCollapsedChanged?: (to: boolean) => void;
    initiallyIsCollapsed?: boolean;
}, any> {
    collapseOrUncollapse(): void;
    getEl(): HTMLElement;
}

objectUtils

export const objectUtils: {
    clonePartially(keys: Array<string>, obj: Object): Object;
    cloneDeep(obj: Object): Object,
    cloneDeepWithChanges(obj: Object, doTheChanges: (newCopyFreeToMutate: Object) => any): Object;
}

reHookValues()

export function reHookValues(cmp: preact.Component, inputs: Array<InputDefinition>): void;

setFocusTo()

export function setFocusTo(ref: preact.Ref): void;

stringUtils

export const stringUtils: StringUtils;

interface StringUtils {
    slugify(text: string): string;
    capitalize(str: string): string;
}

<Tabs/>

export class Tabs extends preact.Component<{
    links: Array<preact.ComponentChild>;
    onTabChanged: (idx: number) => any;
    initialIndex?: number;
    className?: string;
    getTabName?: (linkText: string, tabIdx: number) => string|null;
}, any> {
    changeTab(toIdx: number): void;
}

<Textarea/>

export class Textarea extends preact.Component<{
    vm: preact.Component;
    prop: string;
}, any> {
    // No public methods
}

timingUtils

export const timingUtils: TimingUtils;

interface TimingUtils {
    debounce(func: Function, wait: number, immediate?: boolean): Function;
}

unhookForm()

export function unhookForm(cmp: preact.Component): void;

validationConstraints

export const validationConstraints: ValidationConstraints;

interface ValidationConstraints {
    HARD_SHORT_TEXT_MAX_LEN: number; // Default 1024
    HARD_LONG_TEXT_MAX_LEN: number;  // Default 128000
    MAX_PROSE_HTML_LENGTH: number;   // Default 128000
    INDEX_STR_MAX_LENGTH: number;    // Default 92
    SLUG_REGEXP: string;             // Default '^/[a-zA-Z0-9_-]*$'
}

© Copyright 2021-present ut4 (CC BY-SA).