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
- __()
- api
- env (@sivujetti-commons-for-web-pages)
- events
- floatingDialog
- FormGroup
- FormGroupInline
- handleSubmit
- hasErrors
- hookForm
- http (@sivujetti-commons-for-web-pages)
- Icon
- Input
- InputError
- InputErrors
- MenuSection
- objectUtils
- reHookValues
- setFocusTo
- stringUtils
- Tabs
- Textarea
- timingUtils
- unhookForm
- urlUtils (@sivujetti-commons-for-web-pages)
- validationConstraints
__()
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
}
<MenuSection/>
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_-]*$'
}