diff --git a/docs/docs/cmd/spo/page/page-section-add.mdx b/docs/docs/cmd/spo/page/page-section-add.mdx index d949a5b102f..2dd5d98fbb8 100644 --- a/docs/docs/cmd/spo/page/page-section-add.mdx +++ b/docs/docs/cmd/spo/page/page-section-add.mdx @@ -20,10 +20,16 @@ m365 spo page section add [options] : URL of the site where the page to retrieve is located. `-t, --sectionTemplate ` -: Type of section to add. Allowed values `OneColumn`, `OneColumnFullWidth`, `TwoColumn`, `ThreeColumn`, `TwoColumnLeft`, `TwoColumnRight`. +: Type of section to add. Allowed values `OneColumn`, `OneColumnFullWidth`, `TwoColumn`, `ThreeColumn`, `TwoColumnLeft`, `TwoColumnRight`, `Vertical`. `--order [order]` : Order of the section to add. + +`--zoneEmphasis [zoneEmphasis]` +: Section background shading. Allowed values `None`, `Neutral`, `Soft`, `Strong` + +`--isLayoutReflowOnTop` +: The position of the Vertical section for smaller screens. Applied only for Vertical section. ``` @@ -40,6 +46,24 @@ Add section to the modern page m365 spo page section add --pageName home.aspx --webUrl https://contoso.sharepoint.com/sites/newsletter --sectionTemplate OneColumn --order 1 ``` +Add section with background shading to the modern page + +```sh +m365 spo page section add --pageName home.aspx --webUrl https://contoso.sharepoint.com/sites/newsletter --sectionTemplate OneColumn --zoneEmphasis Strong +``` + +Add a vertical section to the modern page. There can only be one vertical section per page. If a vertical section already exists on the page, the command will not have any effect. + +```sh +m365 spo page section add --pageName home.aspx --webUrl https://contoso.sharepoint.com/sites/newsletter --sectionTemplate Vertical +``` + +Add Vertical section with background shading to the modern page with adjusting the position of this section for smaller screens to the top + +```sh +m365 spo page section add --pageName home.aspx --webUrl https://contoso.sharepoint.com/sites/newsletter --sectionTemplate Vertical --zoneEmphasis Neutral --isLayoutReflowOnTop +``` + ## Response The command won't return a response on success. diff --git a/src/m365/spo/commands/page/canvasContent.ts b/src/m365/spo/commands/page/canvasContent.ts index 2f536463acb..1d43bf0569b 100644 --- a/src/m365/spo/commands/page/canvasContent.ts +++ b/src/m365/spo/commands/page/canvasContent.ts @@ -16,4 +16,5 @@ interface ControlPosition { sectionFactor: number; sectionIndex: number; zoneIndex: number; + isLayoutReflowOnTop?: boolean; } \ No newline at end of file diff --git a/src/m365/spo/commands/page/clientsidepages.ts b/src/m365/spo/commands/page/clientsidepages.ts index 5a5c3535d49..032a448b905 100644 --- a/src/m365/spo/commands/page/clientsidepages.ts +++ b/src/m365/spo/commands/page/clientsidepages.ts @@ -32,7 +32,25 @@ export enum CanvasSectionTemplate { /// /// Two columns, left one is 1/3, right one 2/3 /// - TwoColumnRight + TwoColumnRight, + /// + /// Vertical + /// + Vertical +} + +/** + * Section background shading + * 0 - None + * 1 - Neutral + * 2 - Soft + * 3 - Strong + */ +export enum ZoneEmphasis { + None = 0, + Neutral = 1, + Soft = 2, + Strong = 3 } /** diff --git a/src/m365/spo/commands/page/page-section-add.spec.ts b/src/m365/spo/commands/page/page-section-add.spec.ts index 5db43b02e5c..2cc8ed23e5a 100644 --- a/src/m365/spo/commands/page/page-section-add.spec.ts +++ b/src/m365/spo/commands/page/page-section-add.spec.ts @@ -137,7 +137,7 @@ describe(commands.PAGE_SECTION_ADD, () => { if ((opts.url as string).indexOf(`/_api/sitepages/pages/GetByUrl('sitepages/home.aspx')?$select=CanvasContent1,IsPageCheckedOutToCurrentUser`) > -1) { return { "IsPageCheckedOutToCurrentUser": true, - "CanvasContent1": null + "CanvasContent1": "[{\"controlType\":0,\"pageSettingsSlice\":{\"isDefaultDescription\":true,\"isDefaultThumbnail\":true}}]" }; } @@ -170,7 +170,7 @@ describe(commands.PAGE_SECTION_ADD, () => { if ((opts.url as string).indexOf(`/_api/sitepages/pages/GetByUrl('sitepages/home.aspx')?$select=CanvasContent1,IsPageCheckedOutToCurrentUser`) > -1) { return { "IsPageCheckedOutToCurrentUser": true, - "CanvasContent1": null + "CanvasContent1": "[{\"controlType\":0,\"pageSettingsSlice\":{\"isDefaultDescription\":true,\"isDefaultThumbnail\":true}}]" }; } @@ -199,6 +199,39 @@ describe(commands.PAGE_SECTION_ADD, () => { assert.strictEqual(data, JSON.stringify({ "CanvasContent1": "[{\"displayMode\":2,\"position\":{\"zoneIndex\":1,\"sectionIndex\":1,\"sectionFactor\":12,\"layoutIndex\":1},\"emphasis\":{}},{\"controlType\":0,\"pageSettingsSlice\":{\"isDefaultDescription\":true,\"isDefaultThumbnail\":true}}]" })); }); + it('adds a first section to an uncustomized page correctly even when CanvasContent1 of returned page is null', async () => { + sinon.stub(request, 'get').callsFake((opts) => { + if ((opts.url as string).indexOf(`/_api/sitepages/pages/GetByUrl('sitepages/home.aspx')?$select=CanvasContent1,IsPageCheckedOutToCurrentUser`) > -1) { + return Promise.resolve({ + "IsPageCheckedOutToCurrentUser": true, + "CanvasContent1": null + }); + } + + return Promise.reject('Invalid request'); + }); + + let data: string = ''; + sinon.stub(request, 'post').callsFake((opts) => { + if ((opts.url as string).indexOf(`/_api/sitepages/pages/GetByUrl('sitepages/home.aspx')/savepage`) > -1) { + data = JSON.stringify(opts.data); + return Promise.resolve({}); + } + + return Promise.reject('Invalid request'); + }); + + await command.action(logger, { + options: + { + pageName: 'home.aspx', + webUrl: 'https://contoso.sharepoint.com/sites/newsletter', + sectionTemplate: 'OneColumn' + } + }); + assert.strictEqual(data, JSON.stringify({ "CanvasContent1": "[{\"displayMode\":2,\"position\":{\"zoneIndex\":1,\"sectionIndex\":1,\"sectionFactor\":12,\"layoutIndex\":1},\"emphasis\":{}},{\"controlType\":0,\"pageSettingsSlice\":{\"isDefaultDescription\":true,\"isDefaultThumbnail\":true}}]" })); + }); + it('adds a first section to the page if no order specified', async () => { sinon.stub(request, 'get').callsFake(async (opts) => { if ((opts.url as string).indexOf(`/_api/sitepages/pages/GetByUrl('sitepages/home.aspx')?$select=CanvasContent1,IsPageCheckedOutToCurrentUser`) > -1) { @@ -469,6 +502,109 @@ describe(commands.PAGE_SECTION_ADD, () => { assert.strictEqual(data, JSON.stringify({ "CanvasContent1": "[{\"displayMode\":2,\"position\":{\"zoneIndex\":0.5,\"sectionIndex\":1,\"sectionFactor\":6,\"layoutIndex\":1},\"emphasis\":{}},{\"displayMode\":2,\"position\":{\"zoneIndex\":0.5,\"sectionIndex\":2,\"sectionFactor\":6,\"layoutIndex\":1},\"emphasis\":{}},{\"displayMode\":2,\"position\":{\"zoneIndex\":0.75,\"sectionIndex\":1,\"sectionFactor\":6,\"layoutIndex\":1},\"emphasis\":{}},{\"displayMode\":2,\"position\":{\"zoneIndex\":0.75,\"sectionIndex\":2,\"sectionFactor\":6,\"layoutIndex\":1},\"emphasis\":{}},{\"displayMode\":2,\"position\":{\"zoneIndex\":1,\"sectionIndex\":1,\"sectionFactor\":12,\"layoutIndex\":1},\"emphasis\":{}},{\"displayMode\":2,\"position\":{\"zoneIndex\":1.5,\"sectionIndex\":1,\"sectionFactor\":4,\"layoutIndex\":1},\"emphasis\":{}},{\"displayMode\":2,\"position\":{\"zoneIndex\":1.5,\"sectionIndex\":2,\"sectionFactor\":4,\"layoutIndex\":1},\"emphasis\":{}},{\"displayMode\":2,\"position\":{\"zoneIndex\":1.5,\"sectionIndex\":3,\"sectionFactor\":4,\"layoutIndex\":1},\"emphasis\":{}},{\"displayMode\":2,\"position\":{\"zoneIndex\":2,\"sectionIndex\":1,\"sectionFactor\":4,\"layoutIndex\":1},\"emphasis\":{}},{\"displayMode\":2,\"position\":{\"zoneIndex\":2,\"sectionIndex\":2,\"sectionFactor\":8,\"layoutIndex\":1},\"emphasis\":{}},{\"controlType\":0,\"pageSettingsSlice\":{\"isDefaultDescription\":true,\"isDefaultThumbnail\":true}}]" })); }); + it('adds a Vertical section at the end to an uncustomized page', async () => { + sinon.stub(request, 'get').callsFake((opts) => { + if ((opts.url as string).indexOf(`/_api/sitepages/pages/GetByUrl('sitepages/home.aspx')?$select=CanvasContent1,IsPageCheckedOutToCurrentUser`) > -1) { + return Promise.resolve({ + "IsPageCheckedOutToCurrentUser": true, + "CanvasContent1": "[{\"controlType\":0,\"pageSettingsSlice\":{\"isDefaultDescription\":true,\"isDefaultThumbnail\":true}}]" + }); + } + + return Promise.reject('Invalid request'); + }); + + let data: string = ''; + sinon.stub(request, 'post').callsFake((opts) => { + if ((opts.url as string).indexOf(`/_api/sitepages/pages/GetByUrl('sitepages/home.aspx')/savepage`) > -1) { + data = JSON.stringify(opts.data); + return Promise.resolve({}); + } + + return Promise.reject('Invalid request'); + }); + + await command.action(logger, { + options: + { + pageName: 'home.aspx', + webUrl: 'https://contoso.sharepoint.com/sites/newsletter', + sectionTemplate: 'Vertical' + } + }); + assert.strictEqual(data, JSON.stringify({ "CanvasContent1": "[{\"displayMode\":2,\"position\":{\"zoneIndex\":1,\"sectionIndex\":1,\"sectionFactor\":12,\"layoutIndex\":2,\"isLayoutReflowOnTop\":false,\"controlIndex\":1},\"emphasis\":{}},{\"controlType\":0,\"pageSettingsSlice\":{\"isDefaultDescription\":true,\"isDefaultThumbnail\":true}}]" })); + }); + + + it('adds a Vertical section at the end with correct zoneEmphasisValue to an uncustomized page', async () => { + sinon.stub(request, 'get').callsFake((opts) => { + if ((opts.url as string).indexOf(`/_api/sitepages/pages/GetByUrl('sitepages/home.aspx')?$select=CanvasContent1,IsPageCheckedOutToCurrentUser`) > -1) { + return Promise.resolve({ + "IsPageCheckedOutToCurrentUser": true, + "CanvasContent1": "[{\"controlType\":0,\"pageSettingsSlice\":{\"isDefaultDescription\":true,\"isDefaultThumbnail\":true}}]" + }); + } + + return Promise.reject('Invalid request'); + }); + + let data: string = ''; + sinon.stub(request, 'post').callsFake((opts) => { + if ((opts.url as string).indexOf(`/_api/sitepages/pages/GetByUrl('sitepages/home.aspx')/savepage`) > -1) { + data = JSON.stringify(opts.data); + return Promise.resolve({}); + } + + return Promise.reject('Invalid request'); + }); + + await command.action(logger, { + options: + { + pageName: 'home.aspx', + webUrl: 'https://contoso.sharepoint.com/sites/newsletter', + sectionTemplate: 'Vertical', + zoneEmphasis: 'Neutral' + } + }); + assert.strictEqual(data, JSON.stringify({ "CanvasContent1": "[{\"displayMode\":2,\"position\":{\"zoneIndex\":1,\"sectionIndex\":1,\"sectionFactor\":12,\"layoutIndex\":2,\"isLayoutReflowOnTop\":false,\"controlIndex\":1},\"emphasis\":{\"zoneEmphasis\":1}},{\"controlType\":0,\"pageSettingsSlice\":{\"isDefaultDescription\":true,\"isDefaultThumbnail\":true}}]" })); + }); + + it('adds a Vertical section at the end with correct zoneEmphasisValue and isLayoutReflowOnTop values to an uncustomized page', async () => { + sinon.stub(request, 'get').callsFake((opts) => { + if ((opts.url as string).indexOf(`/_api/sitepages/pages/GetByUrl('sitepages/home.aspx')?$select=CanvasContent1,IsPageCheckedOutToCurrentUser`) > -1) { + return Promise.resolve({ + "IsPageCheckedOutToCurrentUser": true, + "CanvasContent1": "[{\"controlType\":0,\"pageSettingsSlice\":{\"isDefaultDescription\":true,\"isDefaultThumbnail\":true}}]" + }); + } + + return Promise.reject('Invalid request'); + }); + + let data: string = ''; + sinon.stub(request, 'post').callsFake((opts) => { + if ((opts.url as string).indexOf(`/_api/sitepages/pages/GetByUrl('sitepages/home.aspx')/savepage`) > -1) { + data = JSON.stringify(opts.data); + return Promise.resolve({}); + } + + return Promise.reject('Invalid request'); + }); + + await command.action(logger, { + options: + { + pageName: 'home.aspx', + webUrl: 'https://contoso.sharepoint.com/sites/newsletter', + sectionTemplate: 'Vertical', + zoneEmphasis: 'Neutral', + isLayoutReflowOnTop: true + } + }); + assert.strictEqual(data, JSON.stringify({ "CanvasContent1": "[{\"displayMode\":2,\"position\":{\"zoneIndex\":1,\"sectionIndex\":1,\"sectionFactor\":12,\"layoutIndex\":2,\"isLayoutReflowOnTop\":true,\"controlIndex\":1},\"emphasis\":{\"zoneEmphasis\":1}},{\"controlType\":0,\"pageSettingsSlice\":{\"isDefaultDescription\":true,\"isDefaultThumbnail\":true}}]" })); + }); + it('correctly handles random API error', async () => { sinon.stub(request, 'get').callsFake(() => { throw 'An error has occurred'; @@ -533,19 +669,59 @@ describe(commands.PAGE_SECTION_ADD, () => { assert.notStrictEqual(actual, true); }); - it('passes validation if all the parameters are specified', async () => { + it('fails validation if zoneEmphasis is not valid', async () => { + const actual = await command.validate({ + options: { + pageName: 'page.aspx', + webUrl: 'https://contoso.sharepoint.com', + sectionTemplate: 'OneColumn', + zoneEmphasis: 'Invalid' + } + }, commandInfo); + assert.notStrictEqual(actual, true); + }); + + + it('fails validation if isLayoutReflowOnTop is valid but sectionTemplate is not Vertical', async () => { + const actual = await command.validate({ + options: { + pageName: 'page.aspx', + webUrl: 'https://contoso.sharepoint.com', + sectionTemplate: 'OneColumn', + isLayoutReflowOnTop: true + } + }, commandInfo); + assert.notStrictEqual(actual, true); + }); + + it('passes validation if all the parameters are specified for a regular Section', async () => { const actual = await command.validate({ options: { order: 1, sectionTemplate: 'OneColumn', webUrl: 'https://contoso.sharepoint.com', - pageName: 'Home.aspx' + pageName: 'Home.aspx', + zoneEmphasis: 'None' } }, commandInfo); assert.strictEqual(actual, true); }); - it('passes validation if order is not specified', async () => { + it('passes validation if all the parameters are specified for Vertical Section', async () => { + const actual = await command.validate({ + options: { + order: 1, + sectionTemplate: 'Vertical', + webUrl: 'https://contoso.sharepoint.com', + pageName: 'Home.aspx', + zoneEmphasis: 'None', + isLayoutReflowOnTop: false + } + }, commandInfo); + assert.strictEqual(actual, true); + }); + + it('passes validation if order, zoneEmphasis and isLayoutReflowOnTop are not specified', async () => { const actual = await command.validate({ options: { sectionTemplate: 'OneColumn', @@ -556,6 +732,58 @@ describe(commands.PAGE_SECTION_ADD, () => { assert.strictEqual(actual, true); }); + it('passes validation if order and isLayoutReflowOnTop are not specified', async () => { + const actual = await command.validate({ + options: { + sectionTemplate: 'OneColumn', + webUrl: 'https://contoso.sharepoint.com', + pageName: 'Home.aspx', + zoneEmphasis: 'None' + } + }, commandInfo); + assert.strictEqual(actual, true); + }); + + it('passes validation if isLayoutReflowOnTop is specified along with Vertical sectionTemplate', async () => { + const actual = await command.validate({ + options: { + sectionTemplate: 'Vertical', + webUrl: 'https://contoso.sharepoint.com', + pageName: 'Home.aspx', + zoneEmphasis: 'None', + order: 1, + isLayoutReflowOnTop: false + } + }, commandInfo); + assert.strictEqual(actual, true); + }); + + it('passes validation if order is not specified', async () => { + const actual = await command.validate({ + options: { + sectionTemplate: 'Vertical', + webUrl: 'https://contoso.sharepoint.com', + pageName: 'Home.aspx', + isLayoutReflowOnTop: false + } + }, commandInfo); + assert.strictEqual(actual, true); + }); + + it('passes validation if zoneEmphasis is not specified', async () => { + const actual = await command.validate({ + options: { + sectionTemplate: 'Vertical', + webUrl: 'https://contoso.sharepoint.com', + pageName: 'Home.aspx', + order: 1, + isLayoutReflowOnTop: false + } + }, commandInfo); + assert.strictEqual(actual, true); + }); + + it('supports specifying page name', () => { const options = command.options; let containsOption = false; @@ -599,4 +827,26 @@ describe(commands.PAGE_SECTION_ADD, () => { }); assert(containsOption); }); + + it('supports specifying zoneEmphasis', () => { + const options = command.options; + let containsOption = false; + options.forEach((o) => { + if (o.option.indexOf('--zoneEmphasis') > -1) { + containsOption = true; + } + }); + assert(containsOption); + }); + + it('supports specifying isLayoutReflowOnTop', () => { + const options = command.options; + let containsOption = false; + options.forEach((o) => { + if (o.option.indexOf('--isLayoutReflowOnTop') > -1) { + containsOption = true; + } + }); + assert(containsOption); + }); }); diff --git a/src/m365/spo/commands/page/page-section-add.ts b/src/m365/spo/commands/page/page-section-add.ts index 62c12edb972..dd040acb12d 100644 --- a/src/m365/spo/commands/page/page-section-add.ts +++ b/src/m365/spo/commands/page/page-section-add.ts @@ -6,7 +6,7 @@ import { validation } from '../../../../utils/validation.js'; import SpoCommand from '../../../base/SpoCommand.js'; import commands from '../../commands.js'; import { Control } from './canvasContent.js'; -import { CanvasSectionTemplate } from './clientsidepages.js'; +import { CanvasSectionTemplate, ZoneEmphasis } from './clientsidepages.js'; interface CommandArgs { options: Options; @@ -17,9 +17,14 @@ interface Options extends GlobalOptions { webUrl: string; sectionTemplate: string; order?: number; + zoneEmphasis?: string; + isLayoutReflowOnTop?: boolean; } class SpoPageSectionAddCommand extends SpoCommand { + public static readonly SectionTemplate: string[] = ['OneColumn', 'OneColumnFullWidth', 'TwoColumn', 'ThreeColumn', 'TwoColumnLeft', 'TwoColumnRight', 'Vertical']; + public static readonly ZoneEmphasis: string[] = ['None', 'Neutral', 'Soft', 'Strong']; + public get name(): string { return commands.PAGE_SECTION_ADD; } @@ -39,7 +44,9 @@ class SpoPageSectionAddCommand extends SpoCommand { #initTelemetry(): void { this.telemetry.push((args: CommandArgs) => { Object.assign(this.telemetryProperties, { - order: typeof args.options.order !== 'undefined' + order: typeof args.options.order !== 'undefined', + zoneEmphasis: typeof args.options.zoneEmphasis !== 'undefined', + isLayoutReflowOnTop: !!args.options.isLayoutReflowOnTop }); }); } @@ -53,10 +60,18 @@ class SpoPageSectionAddCommand extends SpoCommand { option: '-u, --webUrl ' }, { - option: '-t, --sectionTemplate ' + option: '-t, --sectionTemplate ', + autocomplete: SpoPageSectionAddCommand.SectionTemplate }, { option: '--order [order]' + }, + { + option: '--zoneEmphasis [zoneEmphasis]', + autocomplete: SpoPageSectionAddCommand.ZoneEmphasis + }, + { + option: '--isLayoutReflowOnTop' } ); } @@ -65,7 +80,7 @@ class SpoPageSectionAddCommand extends SpoCommand { this.validators.push( async (args: CommandArgs) => { if (!(args.options.sectionTemplate in CanvasSectionTemplate)) { - return `${args.options.sectionTemplate} is not a valid section template. Allowed values are OneColumn|OneColumnFullWidth|TwoColumn|ThreeColumn|TwoColumnLeft|TwoColumnRight`; + return `${args.options.sectionTemplate} is not a valid section template. Allowed values are OneColumn|OneColumnFullWidth|TwoColumn|ThreeColumn|TwoColumnLeft|TwoColumnRight|Vertical`; } if (typeof args.options.order !== 'undefined') { @@ -74,6 +89,18 @@ class SpoPageSectionAddCommand extends SpoCommand { } } + if (typeof args.options.zoneEmphasis !== 'undefined') { + if (!(args.options.zoneEmphasis in ZoneEmphasis)) { + return 'The value of parameter zoneEmphasis must be None|Neutral|Soft|Strong'; + } + } + + if (typeof args.options.isLayoutReflowOnTop !== 'undefined') { + if (args.options.sectionTemplate !== 'Vertical') { + return 'Specify isLayoutReflowOnTop when the sectionTemplate is set to Vertical.'; + } + } + return validation.isValidSharePointUrl(args.options.webUrl); } ); @@ -128,7 +155,7 @@ class SpoPageSectionAddCommand extends SpoCommand { // zoneIndex for the new section to add const zoneIndex: number = this.getSectionIndex(zoneIndices, args.options.order); // get the list of columns to insert based on the selected template - const columnsToAdd: Control[] = this.getColumns(zoneIndex, args.options.sectionTemplate); + const columnsToAdd: Control[] = this.getColumns(zoneIndex, args.options.sectionTemplate, args.options.zoneEmphasis, args.options.isLayoutReflowOnTop); // insert the column in the right place in the array so that // it stays sorted ascending by zoneIndex let pos: number = canvasContent.findIndex(c => typeof c.controlType === 'undefined' && c.position.zoneIndex > zoneIndex); @@ -174,42 +201,45 @@ class SpoPageSectionAddCommand extends SpoCommand { return zoneIndices[order - 2] + ((zoneIndices[order - 1] - zoneIndices[order - 2]) / 2); } - private getColumns(zoneIndex: number, sectionTemplate: string): Control[] { + private getColumns(zoneIndex: number, sectionTemplate: string, zoneEmphasis?: string, isLayoutReflowOnTop?: boolean): Control[] { const columns: Control[] = []; let sectionIndex: number = 1; switch (sectionTemplate) { case 'OneColumnFullWidth': - columns.push(this.getColumn(zoneIndex, sectionIndex++, 0)); + columns.push(this.getColumn(zoneIndex, sectionIndex++, 0, zoneEmphasis)); break; case 'TwoColumn': - columns.push(this.getColumn(zoneIndex, sectionIndex++, 6)); - columns.push(this.getColumn(zoneIndex, sectionIndex++, 6)); + columns.push(this.getColumn(zoneIndex, sectionIndex++, 6, zoneEmphasis)); + columns.push(this.getColumn(zoneIndex, sectionIndex++, 6, zoneEmphasis)); break; case 'ThreeColumn': - columns.push(this.getColumn(zoneIndex, sectionIndex++, 4)); - columns.push(this.getColumn(zoneIndex, sectionIndex++, 4)); - columns.push(this.getColumn(zoneIndex, sectionIndex++, 4)); + columns.push(this.getColumn(zoneIndex, sectionIndex++, 4, zoneEmphasis)); + columns.push(this.getColumn(zoneIndex, sectionIndex++, 4, zoneEmphasis)); + columns.push(this.getColumn(zoneIndex, sectionIndex++, 4, zoneEmphasis)); break; case 'TwoColumnLeft': - columns.push(this.getColumn(zoneIndex, sectionIndex++, 8)); - columns.push(this.getColumn(zoneIndex, sectionIndex++, 4)); + columns.push(this.getColumn(zoneIndex, sectionIndex++, 8, zoneEmphasis)); + columns.push(this.getColumn(zoneIndex, sectionIndex++, 4, zoneEmphasis)); break; case 'TwoColumnRight': - columns.push(this.getColumn(zoneIndex, sectionIndex++, 4)); - columns.push(this.getColumn(zoneIndex, sectionIndex++, 8)); + columns.push(this.getColumn(zoneIndex, sectionIndex++, 4, zoneEmphasis)); + columns.push(this.getColumn(zoneIndex, sectionIndex++, 8, zoneEmphasis)); + break; + case 'Vertical': + columns.push(this.getVerticalColumn(zoneEmphasis, isLayoutReflowOnTop)); break; case 'OneColumn': default: - columns.push(this.getColumn(zoneIndex, sectionIndex++, 12)); + columns.push(this.getColumn(zoneIndex, sectionIndex++, 12, zoneEmphasis)); break; } return columns; } - private getColumn(zoneIndex: number, sectionIndex: number, sectionFactor: number): Control { - return { + private getColumn(zoneIndex: number, sectionIndex: number, sectionFactor: number, zoneEmphasis?: string): Control { + const columnValue: Control = { displayMode: 2, position: { zoneIndex: zoneIndex, @@ -217,8 +247,25 @@ class SpoPageSectionAddCommand extends SpoCommand { sectionFactor: sectionFactor, layoutIndex: 1 }, - emphasis: {} + emphasis: { + } }; + + if (zoneEmphasis) { + const zoneEmphasisValue: number = ZoneEmphasis[zoneEmphasis as keyof typeof ZoneEmphasis]; + columnValue.emphasis = { zoneEmphasis: zoneEmphasisValue }; + } + + return columnValue; + } + + private getVerticalColumn(zoneEmphasis?: string, isLayoutReflowOnTop?: boolean): Control { + const columnValue: Control = this.getColumn(1, 1, 12, zoneEmphasis); + columnValue.position.isLayoutReflowOnTop = isLayoutReflowOnTop !== undefined ? true : false; + columnValue.position.layoutIndex = 2; + columnValue.position.controlIndex = 1; + + return columnValue; } }