Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/editor/content-form.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ image::editor-rename-path.png[Rename content dialog, 548w]
== Form

Underneath the header is the toolbar with clickable navigation steps that correspond to different sections of the content form. The first one is always
the content type name followed by optional *X-data* steps (if any). Clicking on an item in the toolbar will scroll the content
the content type name followed by optional *Mixins* steps (if any). Clicking on an item in the toolbar will scroll the content
form down to the corresponding section.

Clicking the "<" icon in the menu toolbar will collapse the Content Form and automatically undock the Page Components tree.
Expand Down
6 changes: 3 additions & 3 deletions docs/release.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ Soft-hyphen character `\&shy;` added to Rich Text Editor's "Special chars" dialo

Before this release, email notifications for <<issues#,issues>> created in Content Studio used the current user's email address in the sender field. A new https://developer.enonic.com/docs/xp/stable/deployment/config#mail[config property^] is implemented in XP 7.14.1 which can be used to configure default email sender for emails sent by XP. If properly configured, the sender field in the email notifications sent for issues in Content Studio will be set to the configured email address.

==== eXtra Data
==== Mixins

Layout and behaviour of optional X-Data sections in the Content Form have been changed. `+` icon is now right-aligned and transforms to `x` icon whenever the X-Data is active.
Layout and behaviour of optional mixins sections in the Content Form have been changed. `+` icon is now right-aligned and transforms to `x` icon whenever the mixin is active.

image::cs52-x-data.png[x-data in the Content Editor form, 75%]
image::cs52-mixins.png[mixins in the Content Editor form, 75%]

== Content Studio 5 Update 1

Expand Down
437 changes: 273 additions & 164 deletions modules/app/pnpm-lock.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import com.enonic.xp.content.Content;
import com.enonic.xp.content.ContentId;
import com.enonic.xp.content.ContentService;
import com.enonic.xp.content.ExtraData;
import com.enonic.xp.content.Media;
import com.enonic.xp.content.Mixin;
import com.enonic.xp.context.ContextAccessor;
import com.enonic.xp.context.ContextBuilder;
import com.enonic.xp.exception.ThrottlingException;
Expand All @@ -39,7 +39,7 @@
import com.enonic.xp.schema.content.ContentTypeNames;
import com.enonic.xp.schema.content.ContentTypeService;
import com.enonic.xp.schema.content.GetContentTypeParams;
import com.enonic.xp.schema.xdata.XDataName;
import com.enonic.xp.schema.mixin.MixinName;
import com.enonic.xp.script.bean.BeanContext;
import com.enonic.xp.script.bean.ScriptBean;
import com.enonic.xp.security.PrincipalKey;
Expand Down Expand Up @@ -276,7 +276,7 @@ private ScaleParams parseScaleParam( final Media media, final String scale, fina

private int getOriginalWidth( final Media media )
{
ExtraData imageData = media.getAllExtraData().getMetadata( XDataName.from( "media:imageInfo" ) );
Mixin imageData = media.getMixins().getByName( MixinName.from( "media:imageInfo" ) );
if ( imageData != null )
{
return imageData.getData().getProperty( "imageWidth" ).getValue().asLong().intValue();
Expand Down
405 changes: 211 additions & 194 deletions modules/lib/pnpm-lock.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {XDataWizardStepForm} from '../wizard/XDataWizardStepForm';
import {MixinWizardStepForm} from '../wizard/MixinWizardStepForm';
import {PropertyPath} from '@enonic/lib-admin-ui/data/PropertyPath';
import {Property} from '@enonic/lib-admin-ui/data/Property';
import {Value} from '@enonic/lib-admin-ui/data/Value';
Expand All @@ -17,7 +17,7 @@ export class AiContentDataHelper {

public static DATA_PREFIX = '__data__';

public static XDATA_PREFIX = '__xdata__';
public static MIXIN_PREFIX = '__mixin__';

public static PAGE_PREFIX = '__page__';

Expand Down Expand Up @@ -49,8 +49,8 @@ export class AiContentDataHelper {
this.contentHeader?.setName('', true); // resetting name to trigger name generation after updating displayName
}
this.contentHeader?.setDisplayName(text);
} else if (this.isXDataPath(path)) {
this.handleXDataEvent(path, text);
} else if (this.isMixinPath(path)) {
this.handleMixinEvent(path, text);
} else if (this.isPagePath(path)) {
this.handlePageEvent(path, text);
} else if (this.isDataPath(path)) {
Expand All @@ -64,15 +64,15 @@ export class AiContentDataHelper {
}

transformPathOnDemand(path: string): string {
if (this.isXDataPath(path)) {
return this.transformXDataPath(path);
if (this.isMixinPath(path)) {
return this.transformMixinPath(path);
}

return path;
}

private isXDataPath(path: string): boolean {
return path.startsWith(AiContentDataHelper.XDATA_PREFIX);
private isMixinPath(path: string): boolean {
return path.startsWith(AiContentDataHelper.MIXIN_PREFIX);
}

private isPagePath(path: string): boolean {
Expand All @@ -91,19 +91,19 @@ export class AiContentDataHelper {
return path.indexOf(AiContentDataHelper.TOPIC) > -1;
}

private getXData(path: string): { xDataStepForm: XDataWizardStepForm, xDataPath: PropertyPath } | undefined {
private getMixin(path: string): { mixinStepForm: MixinWizardStepForm, mixinPath: PropertyPath } | undefined {
const pathParts = path.split('/');
const appName = pathParts[1];
const xDataName = pathParts[2];
const key = `${appName.replace(/[/-]/g, '.')}:${xDataName}`;
const xDataStepForm = XDataWizardStepForm.getXDataWizardStepForm(key);
const mixinName = pathParts[2];
const key = `${appName.replace(/[/-]/g, '.')}:${mixinName}`;
const mixinStepForm = MixinWizardStepForm.getMixinsWizardStepForm(key);

return xDataStepForm ? {xDataStepForm, xDataPath: PropertyPath.fromString(`.${pathParts.slice(3).join('.')}`)} : undefined;
return mixinStepForm ? {mixinStepForm: mixinStepForm, mixinPath: PropertyPath.fromString(`.${pathParts.slice(3).join('.')}`)} : undefined;
}

private handleXDataEvent(path: string, text: string): void {
const xData = this.getXData(path);
const prop = xData?.xDataStepForm.getData().getRoot().getPropertyByPath(xData.xDataPath);
private handleMixinEvent(path: string, text: string): void {
const mixin = this.getMixin(path);
const prop = mixin?.mixinStepForm.getData().getRoot().getPropertyByPath(mixin.mixinPath);
this.updateProperty(prop, text);
}

Expand Down Expand Up @@ -159,11 +159,11 @@ export class AiContentDataHelper {
}
}

private transformXDataPath(path: string): string { // take path parts and make a right xdata group name
private transformMixinPath(path: string): string { // take path parts and make a right mixins group name
const pathParts = path.split('/');
const appName = pathParts[1];
const xDataName = pathParts[2];
const key = `${appName.replace(/[/-]/g, '.')}:${xDataName}`;
const mixinName = pathParts[2];
const key = `${appName.replace(/[/-]/g, '.')}:${mixinName}`;

return `__${key}__/${pathParts.slice(3).join('/')}`;
}
Expand Down
32 changes: 16 additions & 16 deletions modules/lib/src/main/resources/assets/js/app/content/Content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import {Property} from '@enonic/lib-admin-ui/data/Property';
import {PropertyTree} from '@enonic/lib-admin-ui/data/PropertyTree';
import {Attachments, AttachmentsBuilder} from '../attachment/Attachments';
import {ContentJson} from './ContentJson';
import {ExtraData} from './ExtraData';
import {ExtraDataJson} from '../resource/json/ExtraDataJson';
import {XDataName} from './XDataName';
import {Mixin} from './Mixin';
import {MixinJson} from '../resource/json/MixinJson';
import {MixinName} from './MixinName';
import {Page, PageBuilder} from '../page/Page';
import {AccessControlList} from '../access/AccessControlList';
import {Equitable} from '@enonic/lib-admin-ui/Equitable';
Expand All @@ -25,7 +25,7 @@ export class Content

private readonly attachments: Attachments;

private readonly extraData: ExtraData[] = [];
private readonly mixins: Mixin[] = [];

private readonly pageObj: Page;

Expand All @@ -39,7 +39,7 @@ export class Content
assertNotNull(builder.data, 'data is required for Content');
this.data = builder.data;
this.attachments = builder.attachments;
this.extraData = builder.extraData || [];
this.mixins = builder.mixins || [];
this.pageObj = builder.pageObj;
this.permissions = builder.permissions || new AccessControlList();
this.validationErrors = builder.validationErrors || [];
Expand All @@ -53,12 +53,12 @@ export class Content
return this.attachments;
}

getExtraDataByName(name: XDataName): ExtraData {
return this.extraData.filter((item: ExtraData) => item.getName().equals(name))[0];
getMixinByName(name: MixinName): Mixin {
return this.mixins.filter((item: Mixin) => item.getName().equals(name))[0];
}

getAllExtraData(): ExtraData[] {
return this.extraData;
getMixins(): Mixin[] {
return this.mixins;
}

getProperty(propertyName: string): Property {
Expand Down Expand Up @@ -106,7 +106,7 @@ export class ContentBuilder

attachments: Attachments;

extraData: ExtraData[];
mixins: Mixin[];

pageObj: Page;

Expand All @@ -120,7 +120,7 @@ export class ContentBuilder
if (source) {
if (cloneProperties) {
this.data = source.getContentData() ? source.getContentData().copy() : null;
this.extraData = source.getAllExtraData() ? source.getAllExtraData().map((extraData: ExtraData) => extraData.clone()) : [];
this.mixins = source.getMixins() ? source.getMixins().map((mixin: Mixin) => mixin.clone()) : [];
this.pageObj = source.getPage() ? source.getPage().clone() : null;
}
this.attachments = source.getAttachments();
Expand All @@ -135,9 +135,9 @@ export class ContentBuilder

this.data = PropertyTree.fromJson(json.data);
this.attachments = new AttachmentsBuilder().fromJson(json.attachments).build();
this.extraData = [];
json.meta.forEach((extraDataJson: ExtraDataJson) => {
this.extraData.push(ExtraData.fromJson(extraDataJson));
this.mixins = [];
json.meta.forEach((mixinJson: MixinJson) => {
this.mixins.push(Mixin.fromJson(mixinJson));
});

if (this.page) {
Expand Down Expand Up @@ -172,8 +172,8 @@ export class ContentBuilder
return this;
}

setExtraData(extraData: ExtraData[]): ContentBuilder {
this.extraData = extraData;
setMixins(mixins: Mixin[]): ContentBuilder {
this.mixins = mixins;
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {ContentSummaryDiff} from './ContentSummaryDiff';

export interface ContentDiff extends ContentSummaryDiff {
data?: boolean;
extraData?: boolean;
mixins?: boolean;
pageObj?: boolean;
permissions?: boolean;
attachments?: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {AttachmentJson} from '../attachment/AttachmentJson';
import {ExtraDataJson} from '../resource/json/ExtraDataJson';
import {MixinJson} from '../resource/json/MixinJson';
import {PageJson} from '../page/PageJson';
import {AccessControlEntryJson} from '../access/AccessControlEntryJson';
import {PropertyArrayJson} from '@enonic/lib-admin-ui/data/PropertyArrayJson';
Expand All @@ -13,7 +13,7 @@ export interface ContentJson

attachments: AttachmentJson[];

meta: ExtraDataJson[];
meta: MixinJson[];

page: PageJson;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,39 @@ import {ObjectHelper} from '@enonic/lib-admin-ui/ObjectHelper';
import {Cloneable} from '@enonic/lib-admin-ui/Cloneable';
import {Equitable} from '@enonic/lib-admin-ui/Equitable';
import {PropertyTree} from '@enonic/lib-admin-ui/data/PropertyTree';
import {XDataName} from './XDataName';
import {ExtraDataJson} from '../resource/json/ExtraDataJson';
import {MixinName} from './MixinName';
import {MixinJson} from '../resource/json/MixinJson';

export class ExtraData
export class Mixin
implements Cloneable, Equitable {

private name: XDataName;
private name: MixinName;

private data: PropertyTree;

constructor(name: XDataName, data: PropertyTree) {
constructor(name: MixinName, data: PropertyTree) {
this.name = name;
this.data = data;
}

static fromJson(metadataJson: ExtraDataJson): ExtraData {
return new ExtraData(new XDataName(metadataJson.name), PropertyTree.fromJson(metadataJson.data));
static fromJson(metadataJson: MixinJson): Mixin {
return new Mixin(new MixinName(metadataJson.name), PropertyTree.fromJson(metadataJson.data));
}

getData(): PropertyTree {
return this.data;
}

clone(): ExtraData {
return new ExtraData(this.name, this.data.copy());
clone(): Mixin {
return new Mixin(this.name, this.data.copy());
}

equals(o: Equitable): boolean {
if (!ObjectHelper.iFrameSafeInstanceOf(o, ExtraData)) {
if (!ObjectHelper.iFrameSafeInstanceOf(o, Mixin)) {
return false;
}

let other = o as ExtraData;
let other = o as Mixin;

if (!ObjectHelper.equals(this.name, other.name)) {
return false;
Expand All @@ -47,14 +47,14 @@ export class ExtraData
return true;
}

toJson(): ExtraDataJson {
toJson(): MixinJson {
return {
name: this.name.toString(),
data: this.data.toJson()
};
}

getName(): XDataName {
getName(): MixinName {
return this.name;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {ExtraData} from './ExtraData';
import {Mixin} from './Mixin';
import {Comparator} from '@enonic/lib-admin-ui/Comparator';

export class ExtraDataByMixinNameComparator
implements Comparator<ExtraData> {
export class MixinByMixinNameComparator
implements Comparator<Mixin> {

compare(a: ExtraData, b: ExtraData): number {
compare(a: Mixin, b: Mixin): number {
let firstName: string;
let secondName: string;

Expand Down
Loading
Loading