scrivito
Version:
Scrivito is a professional, yet easy to use SaaS Enterprise Content Management Service, built for digital agencies and medium to large businesses. It is completely maintenance-free, cost-effective, and has unprecedented performance and security.
166 lines (130 loc) • 4.58 kB
text/typescript
import { ArgumentError, InternalError } from 'scrivito_sdk/common';
import { BasicWidget } from 'scrivito_sdk/models';
import { assertValidAttributeName } from 'scrivito_sdk/realm/assert_valid_attribute_name';
import { AttrDict } from 'scrivito_sdk/realm/attribute_types';
import { initialAttributesFor } from 'scrivito_sdk/realm/initial_attributes_for';
import { Obj } from 'scrivito_sdk/realm/obj';
import { objClassNameFor } from 'scrivito_sdk/realm/registry';
import {
AttributeDefinitions,
NormalizedAttributeDefinitions,
Schema,
} from 'scrivito_sdk/realm/schema';
import { subWidgets } from 'scrivito_sdk/realm/sub_widgets';
import {
AttributeValueOf,
unwrapAppAttributes,
wrapInAppClass,
} from 'scrivito_sdk/realm/wrap_in_app_class';
import { readAppAttribute, updateAppAttributes } from './app_model_accessor';
/** @public */
export interface WidgetClass<
AttrDefs extends AttributeDefinitions = AttributeDefinitions
> {
/** @internal */
readonly _scrivitoPrivateSchema?: Schema;
new (attributes?: AttrDict<AttrDefs>): Widget<AttrDefs>;
attributeDefinitions(): NormalizedAttributeDefinitions;
}
/** @public */
export class Widget<
AttrDefs extends AttributeDefinitions = AttributeDefinitions
> {
/** @internal */
readonly _scrivitoPrivateContent: BasicWidget;
/** @internal */
static readonly _scrivitoPrivateSchema?: Schema;
constructor(attributes: AttrDict<AttrDefs> = {}) {
const appClassName = objClassNameFor(this.constructor as WidgetClass);
if (!appClassName) {
throw new ArgumentError(
'Use a specific class (like TextWidget or ImageWidget) to create a Widget.'
);
}
assertValidAttributes(attributes);
const schema = Schema.forInstance(this);
// schema should exist, if objClassNameFor can find something
if (!schema) throw new InternalError();
const basicAttributes = unwrapAppAttributes(
{ ...attributes, _objClass: appClassName },
schema,
appClassName
);
const basicWidget = BasicWidget.createWithUnknownValues(basicAttributes);
basicWidget.onDidPersist((copiedWidget) => {
const appWidget = wrapInAppClass(copiedWidget);
const initialAttributes = initialAttributesFor(
basicAttributes,
schema,
appClassName
);
updateAppAttributes(appWidget, initialAttributes);
});
this._scrivitoPrivateContent = basicWidget;
}
static attributeDefinitions(): NormalizedAttributeDefinitions {
const schema = Schema.forClass(this);
if (!schema) return {};
return schema.normalizedAttributes();
}
id(): string {
return this._scrivitoPrivateContent.id();
}
objClass(): string {
return this._scrivitoPrivateContent.objClass();
}
get<AttributeName extends keyof AttrDefs & string>(
attributeName: AttributeName
): AttributeValueOf<AttrDefs, AttributeName> {
assertValidAttributeName(attributeName);
// Bang: TypeScript will display an error if the attribute in question does not have a
// corresponding attribute definition.
return readAppAttribute(this, attributeName)!;
}
update(attributes: AttrDict<AttrDefs>): void {
updateAppAttributes(this, attributes);
}
obj(): Obj {
const basicObj = this._scrivitoPrivateContent.obj();
return wrapInAppClass(basicObj);
}
widgets(): Widget[] {
return wrapInAppClass(subWidgets(this._scrivitoPrivateContent));
}
copy(): Widget<AttrDefs> {
const basicWidget = this._scrivitoPrivateContent.copy();
return wrapInAppClass<AttrDefs>(basicWidget);
}
/** @deprecated Use `Widget#delete` instead */
destroy(): void {
this.delete();
}
delete(): void {
this._scrivitoPrivateContent.delete();
}
container(): Obj | Widget {
const container = this._scrivitoPrivateContent.container();
return wrapInAppClass(container);
}
attributeDefinitions(): NormalizedAttributeDefinitions {
const schema = Schema.forInstance(this);
if (!schema) return {};
return schema.normalizedAttributes();
}
}
function assertValidAttributes(attributes: { [name: string]: unknown }) {
if (attributes.constructor !== Object) {
throw new ArgumentError(
'The provided attributes are invalid. They have ' +
'to be an Object with valid Scrivito attribute values.'
);
}
if (attributes._objClass) {
throw new ArgumentError(
'Invalid attribute "_objClass". ' +
`"new ${String(
attributes._objClass
)}" will automatically set the CMS object class correctly.`
);
}
}