diff --git a/playlists/excel.yaml b/playlists/excel.yaml index 1407b7977..f29a26ca4 100644 --- a/playlists/excel.yaml +++ b/playlists/excel.yaml @@ -1,227 +1,3 @@ -- id: excel-basics-basic-api-call - name: Basic API call (TypeScript) - fileName: basic-api-call.yaml - description: Performs a basic Excel API call using TypeScript. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/01-basics/basic-api-call.yaml - group: Basics - api_set: - ExcelApi: '1.1' -- id: excel-basics-basic-api-call-es5 - name: Basic API call (JavaScript) - fileName: basic-api-call-es5.yaml - description: Performs a basic Excel API call using plain JavaScript & Promises. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/01-basics/basic-api-call-es5.yaml - group: Basics - api_set: - ExcelApi: '1.1' -- id: excel-basics-basic-common-api-call - name: Basic API call (Office 2013) - fileName: basic-common-api-call.yaml - description: >- - Performs a basic Excel API call using JavaScript with the "common API" - syntax (compatible with Office 2013). - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/01-basics/basic-common-api-call.yaml - group: Basics - api_set: - Selection: 1.1 -- id: excel-chart-axis - name: Axis details - fileName: chart-axis.yaml - description: 'Gets, sets, and removes axis unit, label, and title in a chart.' - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-axis.yaml - group: Chart - api_set: - ExcelApi: '1.7' -- id: excel-chart-axis-formatting - name: Axis formatting - fileName: chart-axis-formatting.yaml - description: Formats the vertical and horizontal axes in a chart. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-axis-formatting.yaml - group: Chart - api_set: - ExcelApi: '1.8' -- id: excel-chart-data-table - name: Chart data table - fileName: chart-data-table.yaml - description: Add a data table to a chart and then format that data table. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-data-table.yaml - group: Chart - api_set: - ExcelApi: '1.14' -- id: excel-chart-bubble-chart - name: Create bubble chart - fileName: chart-bubble-chart.yaml - description: >- - Creates a bubble chart with each data row represented as a single chart - series (bubble). - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-bubble-chart.yaml - group: Chart - api_set: - ExcelApi: '1.12' -- id: excel-chart-create-several-charts - name: Create charts - fileName: chart-create-several-charts.yaml - description: >- - Creates column-clustered, line, XY-scatter, area, radar, pie, 3D, cylinder, - and 100% charts. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-create-several-charts.yaml - group: Chart - api_set: - ExcelApi: '1.4' -- id: excel-chart-create-doughnut-chart - name: Doughnut chart - fileName: create-doughnut-chart.yaml - description: Creates a doughnut chart and adjusts its size. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/create-doughnut-chart.yaml - group: Chart - api_set: - ExcelApi: '1.7' -- id: excel-chart-formatting - name: Formatting - fileName: chart-formatting.yaml - description: Formats labels and lines of a slope chart. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-formatting.yaml - group: Chart - api_set: - ExcelApi: '1.8' -- id: excel-chart-legend - name: Legend - fileName: chart-legend.yaml - description: Formats the legend's font. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-legend.yaml - group: Chart - api_set: - ExcelApi: '1.7' -- id: excel-chart-point - name: Points - fileName: chart-point.yaml - description: Sets the color of a point on the chart. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-point.yaml - group: Chart - api_set: - ExcelApi: '1.7' -- id: excel-chart-series - name: Series - fileName: chart-series.yaml - description: Adds and deletes series in a chart. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-series.yaml - group: Chart - api_set: - ExcelApi: '1.7' -- id: excel-chart-series-markers - name: Series markers - fileName: chart-series-markers.yaml - description: Sets the chart series marker properties. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-series-markers.yaml - group: Chart - api_set: - ExcelApi: '1.7' -- id: excel-chart-series-plotorder - name: Series plot order - fileName: chart-series-plotorder.yaml - description: Orders the plotting of series in a chart. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-series-plotorder.yaml - group: Chart - api_set: - ExcelApi: '1.7' -- id: excel-chart-title-format - name: Title format - fileName: chart-title-format.yaml - description: Adjust a chart title's format. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-title-format.yaml - group: Chart - api_set: - ExcelApi: '1.7' -- id: excel-chart-data-source - name: Chart series data source - fileName: chart-data-source.yaml - description: >- - This sample shows how to get information about the data source of a chart - series. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-data-source.yaml - group: Chart - api_set: - ExcelApi: '1.15' -- id: excel-chart-trendlines - name: Trendlines - fileName: chart-trendlines.yaml - description: 'Adds, gets, and formats trendlines in a chart.' - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-trendlines.yaml - group: Chart - api_set: - ExcelApi: '1.7' -- id: excel-comment-basics - name: Comment basics - fileName: comment-basics.yaml - description: 'Adds, edits, and removes comments.' - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/12-comment/comment-basics.yaml - group: Comment - api_set: - ExcelApi: '1.10' -- id: excel-comment-mentions - name: Comment mentions - fileName: comment-mentions.yaml - description: Mentions someone in a comment. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/12-comment/comment-mentions.yaml - group: Comment - api_set: - ExcelApi: '1.11' -- id: excel-comment-replies - name: Comment replies - fileName: comment-replies.yaml - description: 'Adds, edits, and removes comment replies.' - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/12-comment/comment-replies.yaml - group: Comment - api_set: - ExcelApi: '1.10' -- id: excel-comment-resolution - name: Comment resolution - fileName: comment-resolution.yaml - description: Resolves and reopens a comment thread. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/12-comment/comment-resolution.yaml - group: Comment - api_set: - ExcelApi: '1.10' -- id: excel-range-conditional-formatting-basic - name: Basic conditional formatting - fileName: conditional-formatting-basic.yaml - description: Applies common types of conditional formatting to ranges. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml - group: Conditional Formatting - api_set: - ExcelApi: '1.6' -- id: excel-range-conditional-formatting-advanced - name: Advanced conditional formatting - fileName: conditional-formatting-advanced.yaml - description: Applies more than one conditional format on the same range. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/14-conditional-formatting/conditional-formatting-advanced.yaml - group: Conditional Formatting - api_set: - ExcelApi: '1.6' - id: excel-custom-functions-basic name: Basic custom function fileName: basic-function.yaml @@ -277,1084 +53,4 @@ https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/data-types-custom-functions.yaml group: Custom Functions api_set: - CustomFunctionsRuntime: 1.4 -- id: excel-custom-xml-parts-create-set-get-and-delete-custom-xml-parts - name: Using custom XML parts - fileName: create-set-get-and-delete-custom-xml-parts.yaml - description: 'Creates, sets, gets, and deletes a custom XML part.' - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml - group: Custom XML Parts - api_set: - ExcelApi: '1.5' -- id: excel-custom-xml-parts-test-xml-for-unique-namespace - name: Unique namespaces in custom XML - fileName: test-xml-for-unique-namespace.yaml - description: Tests to see if there is only one XML part for a specified namespace. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml - group: Custom XML Parts - api_set: - ExcelApi: '1.5' -- id: excel-data-types-formatted-number - name: 'Data types: Formatted numbers' - fileName: data-types-formatted-number.yaml - description: >- - This sample shows how to set and get data types using the formatted number - properties. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-formatted-number.yaml - group: Data Types - api_set: - ExcelApi: '1.16' -- id: excel-data-types-web-image - name: 'Data types: Web images' - fileName: data-types-web-image.yaml - description: >- - This sample shows how to set and get web images in a worksheet using data - types. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-web-image.yaml - group: Data Types - api_set: - ExcelApi: '1.16' -- id: excel-data-types-entity-values - name: 'Data types: Create entity cards from data in a table' - fileName: data-types-entity-values.yaml - description: >- - This sample shows how to create entity cards for each row in a table. An - entity is a container for data types, similar to an object in - object-oriented programming. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-entity-values.yaml - group: Data Types - api_set: - ExcelApi: '1.16' -- id: excel-data-types-error-values - name: 'Data types: Set error values' - fileName: data-types-error-values.yaml - description: This sample shows how to set a cell value to an error data type. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-error-values.yaml - group: Data Types - api_set: - ExcelApi: '1.16' -- id: excel-data-types-icons - name: 'Data types: Create entity icons' - fileName: data-types-entity-icons.yaml - description: Display all the icons available for entity data types. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-entity-icons.yaml - group: Data Types - api_set: - ExcelApi: '1.16' -- id: excel-data-types-entity-attribution - name: 'Data types: Entity value attribution properties' - fileName: data-types-entity-attribution.yaml - description: >- - This sample shows how to set data provider attributions on entity values in - the card layout. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-entity-attribution.yaml - group: Data Types - api_set: - ExcelApi: '1.16' -- id: excel-data-types-references - name: 'Data types: Entity values with references' - fileName: data-types-references.yaml - description: >- - This sample shows how to create entity values with references to other - entity values. An entity value is a container for data, and this container - can reference (or contain) other entities within the original entity. One - entity can contain multiple additional entities. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-references.yaml - group: Data Types - api_set: - ExcelApi: '1.16' -- id: excel-data-validation - name: Data validation - fileName: data-validation.yaml - description: >- - Sets data validation rules on ranges, prompts users to enter valid data, and - displays messages when invalid data is entered. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/22-data-validation/data-validation.yaml - group: Data Validation - api_set: - ExcelApi: '1.8' -- id: excel-document-get-file-in-slices-async - name: Get file using slicing - fileName: get-file-in-slices-async.yaml - description: >- - Uses slicing to get the byte array and Base64-encoded string that represent - the current document. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/26-document/get-file-in-slices-async.yaml - group: Document - api_set: - ExcelApi: '1.4' -- id: excel-document-properties - name: Properties - fileName: properties.yaml - description: Gets and sets document properties. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/26-document/properties.yaml - group: Document - api_set: - ExcelApi: '1.7' -- id: excel-document-custom-properties - name: Custom properties - fileName: custom-properties.yaml - description: Gets and sets custom properties at the document and worksheet levels. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/26-document/custom-properties.yaml - group: Document - api_set: - ExcelAPI: '1.12' -- id: excel-events-chartcollection-added-activated - name: Chart collection events - fileName: events-chartcollection-added-activated.yaml - description: >- - Registers event handlers on a worksheet's chart collection that run when any - chart within is activated or deactivated, as well as when charts are added - to or deleted from the collection. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-chartcollection-added-activated.yaml - group: Events - api_set: - ExcelApi: '1.8' -- id: excel-events-chart-activated - name: Chart events - fileName: events-chart-activated.yaml - description: >- - Registers event handlers on an individual chart that run when the chart is - activated or deactivated. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-chart-activated.yaml - group: Events - api_set: - ExcelApi: '1.8' -- id: excel-event-column-and-row-sort - name: Column and row sort events - fileName: event-column-and-row-sort.yaml - description: >- - Registers event handlers that run when column or row sorting events occur in - the current worksheet. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/event-column-and-row-sort.yaml - group: Events - api_set: - ExcelApi: '1.10' -- id: excel-events-comments - name: Comment events - fileName: events-comment-event-handler.yaml - description: >- - Registers event handlers to listen for comment additions, changes, and - deletions. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-comment-event-handler.yaml - group: Events - api_set: - ExcelAPI: '1.12' -- id: excel-events-data-changed - name: Data changed event - fileName: data-changed.yaml - description: Registers an event handler that runs when data is changed. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/data-changed.yaml - group: Events - api_set: - ExcelApi: '1.4' -- id: excel-data-change-event-details - name: Data changed event details - fileName: data-change-event-details.yaml - description: Uses the onChanged event of a table to determine the specifics of changes. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/data-change-event-details.yaml - group: Events - api_set: - ExcelApi: '1.9' -- id: excel-events-disable-events - name: Enable and disable events - fileName: events-disable-events.yaml - description: Toggles event firing on and off. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-disable-events.yaml - group: Events - api_set: - ExcelApi: '1.8' -- id: excel-events-formula-changed - name: Formula changed event - fileName: events-formula-changed.yaml - description: Registers an event handler to detect changes to formulas. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-formula-changed.yaml - group: Events - api_set: - ExcelAPI: '1.13' -- id: excel-selection-changed-events - name: Selection changed events - fileName: selection-changed-events.yaml - description: >- - Registers handlers all the different `onSelectionChanged` events and - displays how each event reports the selected addresses. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/selection-changed-events.yaml - group: Events - api_set: - ExcelApi: '1.7' -- id: excel-events-tablecollection-changed - name: Table collection events - fileName: events-tablecollection-changed.yaml - description: Registers an event handler that runs when a table collection is changed. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-tablecollection-changed.yaml - group: Events - api_set: - ExcelApi: '1.7' -- id: excel-event-worksheet-single-click - name: Single click event - fileName: event-worksheet-single-click.yaml - description: >- - Registers an event handler that runs when a single-click event occurs in the - current worksheet. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/event-worksheet-single-click.yaml - group: Events - api_set: - ExcelApi: '1.10' -- id: excel-events-table-changed - name: Table events - fileName: events-table-changed.yaml - description: Registers event handlers that run when a table is changed or selected. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-table-changed.yaml - group: Events - api_set: - ExcelApi: '1.7' -- id: excel-events-workbook-activated - name: Workbook activated event - fileName: events-workbook-activated.yaml - description: This sample shows how to register a workbook activated event handler. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-workbook-activated.yaml - group: Events - api_set: - ExcelAPI: '1.13' -- id: excel-events-workbook-and-worksheet-collection - name: Workbook and worksheet collection events - fileName: events-workbook-and-worksheet-collection.yaml - description: >- - Registers event handlers that run when a worksheet is added, activated, or - deactivated, or when the settings of a workbook are changed. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml - group: Events - api_set: - ExcelApi: '1.7' -- id: excel-events-worksheet - name: Worksheet events - fileName: events-worksheet.yaml - description: >- - Registers event handlers that run when data is changed in worksheet, the - selected range changes in a worksheet, or the worksheet is recalculated. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-worksheet.yaml - group: Events - api_set: - ExcelApi: '1.7' -- id: excel-events-worksheet-protection - name: Worksheet protection events - fileName: events-worksheet-protection.yaml - description: >- - Registers an event handler to listen for worksheet protection status - changes. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-worksheet-protection.yaml - group: Events - api_set: - ExcelAPI: '1.14' -- id: excel-named-item-create-and-remove-named-item - name: 'Create, access, and remove' - fileName: create-and-remove-named-item.yaml - description: 'Creates, accesses, and removes named items in a worksheet.' - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/34-named-item/create-and-remove-named-item.yaml - group: Named Item - api_set: - ExcelApi: '1.4' -- id: excel-update-named-item - name: Update - fileName: update-named-item.yaml - description: Creates and then updates a named item. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/34-named-item/update-named-item.yaml - group: Named Item - api_set: - ExcelApi: '1.7' -- id: excel-pivottable-calculations - name: Calculations - fileName: pivottable-calculations.yaml - description: Changes the calculations the PivotTable performs. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-calculations.yaml - group: PivotTable - api_set: - ExcelApi: '1.8' -- id: excel-pivottable-create-and-modify - name: Create and modify - fileName: pivottable-create-and-modify.yaml - description: Creates and modifies a PivotTable. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-create-and-modify.yaml - group: PivotTable - api_set: - ExcelApi: '1.8' -- id: excel-pivottable-filters-and-summaries - name: Filters and summaries - fileName: pivottable-filters-and-summaries.yaml - description: Filters PivotTable data and shows different summarizations. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-filters-and-summaries.yaml - group: PivotTable - api_set: - ExcelApi: '1.8' -- id: excel-pivottables-get-pivottables - name: Get PivotTables - fileName: pivottable-get-pivottables.yaml - description: >- - Get existing PivotTables in the workbook through their collections and - through the ranges they occupy. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-get-pivottables.yaml - group: PivotTable - api_set: - ExcelAPI: '1.12' -- id: excel-pivottables-pivotfilters - name: PivotFilters - fileName: pivottable-pivotfilters.yaml - description: Applies PivotFilters to a PivotTable. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-pivotfilters.yaml - group: PivotTable - api_set: - ExcelAPI: '1.12' -- id: excel-pivottable-pivotlayout - name: PivotLayout - fileName: pivottable-pivotlayout.yaml - description: Sets PivotTable layout settings through the PivotLayout. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-pivotlayout.yaml - group: PivotTable - api_set: - ExcelAPI: '1.13' -- id: excel-pivottable-data-source - name: PivotTable data source - fileName: pivottable-source-data.yaml - description: Gets information about the data source of a PivotTable. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-source-data.yaml - group: PivotTable - api_set: - ExcelApi: '1.15' -- id: excel-pivottable-refresh - name: Refresh - fileName: pivottable-refresh.yaml - description: Refreshes a PivotTable based on table row additions. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-refresh.yaml - group: PivotTable - api_set: - ExcelApi: '1.8' -- id: excel-pivottable-slicer - name: Slicer - fileName: pivottable-slicer.yaml - description: Adds a slicer to a PivotTable. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-slicer.yaml - group: PivotTable - api_set: - ExcelApi: '1.10' -- id: excel-range-auto-fill - name: Auto fill - fileName: range-auto-fill.yaml - description: Writes to cells with the auto fill feature. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-auto-fill.yaml - group: Range - api_set: - ExcelApi: '1.10' -- id: excel-range-copyfrom - name: Copy and paste ranges - fileName: range-copyfrom.yaml - description: Copies or moves data and formatting from one range to another. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-copyfrom.yaml - group: Range - api_set: - ExcelApi: '1.10' -- id: excel-range-areas - name: Discontiguous ranges (RangeAreas) and special cells - fileName: range-areas.yaml - description: >- - Creates and uses RangeAreas, which are sets of ranges that need not be - contiguous, through user selection and programmatic selection of special - cells. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-areas.yaml - group: Range - api_set: - ExcelApi: '1.9' -- id: excel-range-find - name: Find text matches within a range - fileName: range-find.yaml - description: Finds a cell within a range based on string matching. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-find.yaml - group: Range - api_set: - ExcelApi: '1.9' -- id: excel-range-formatting - name: Formatting - fileName: formatting.yaml - description: Formats a range. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/formatting.yaml - group: Range - api_set: - ExcelApi: '1.4' -- id: excel-range-cell-properties - name: Get and set cell properties - fileName: cell-properties.yaml - description: Sets different properties across a range then retrieves those properties. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/cell-properties.yaml - group: Range - api_set: - ExcelApi: '1.9' -- id: excel-range-hyperlink - name: Hyperlinks - fileName: range-hyperlink.yaml - description: 'Creates, updates, and clears hyperlinks in a range.' - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-hyperlink.yaml - group: Range - api_set: - ExcelApi: '1.7' -- id: excel-range-insert-delete-and-clear-range - name: 'Insert, delete, and clear' - fileName: insert-delete-clear-range.yaml - description: 'Inserts, deletes, and clears a range.' - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/insert-delete-clear-range.yaml - group: Range - api_set: - ExcelApi: '1.4' -- id: excel-outline - name: Outline - fileName: outline.yaml - description: Creates an outline by grouping rows and columns. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/outline.yaml - group: Range - api_set: - ExcelApi: '1.10' -- id: excel-range-range-relationships - name: Range relationships - fileName: range-relationships.yaml - description: >- - Shows relationships between ranges, such as bounding rectangles and - intersections. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-relationships.yaml - group: Range - api_set: - ExcelApi: '1.4' -- id: excel-range-remove-duplicates - name: Remove duplicates - fileName: range-remove-duplicates.yaml - description: Removes duplicate entries from a range. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-remove-duplicates.yaml - group: Range - api_set: - ExcelApi: '1.9' -- id: excel-range-selected-range - name: Selected range - fileName: selected-range.yaml - description: Gets and sets the currently selected range. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/selected-range.yaml - group: Range - api_set: - ExcelApi: '1.1' -- id: excel-precedents - name: Precedents - fileName: precedents.yaml - description: >- - This sample shows how to find and highlight the precedents of the currently - selected cell. Precedents are cells referenced by the formula in a cell. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/precedents.yaml - group: Range - api_set: - ExcelApi: '1.14' -- id: excel-range-style - name: Style - fileName: style.yaml - description: >- - Creates a custom style, applies a custom and built-in styles to a range, - gets style properties, and deletes the custom style. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/style.yaml - group: Range - api_set: - ExcelApi: '1.7' -- id: excel-range-text-orientation - name: Text orientation - fileName: range-text-orientation.yaml - description: Gets and sets the text orientation within a range. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-text-orientation.yaml - group: Range - api_set: - ExcelApi: '1.7' -- id: excel-range-dynamic-arrays - name: Dynamic arrays - fileName: dynamic-arrays.yaml - description: >- - Applies formulas that use dynamic arrays and displays information about the - ranges used to display the data. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/dynamic-arrays.yaml - group: Range - api_set: - ExcelAPI: '1.12' -- id: excel-range-used-range - name: Used range - fileName: used-range.yaml - description: >- - Tests for a used range and creates a chart from a table only if there's data - in the table. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/used-range.yaml - group: Range - api_set: - ExcelApi: '1.4' -- id: excel-range-values-and-formulas - name: Values and formulas - fileName: set-get-values.yaml - description: Gets and sets values and formulas for a range. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/set-get-values.yaml - group: Range - api_set: - ExcelApi: '1.4' -- id: excel-merged-ranges - name: Merged ranges - fileName: range-merged-ranges.yaml - description: This sample shows how to create and find merged ranges in a worksheet. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-merged-ranges.yaml - group: Range - api_set: - ExcelAPI: '1.13' -- id: excel-range-get-range-edge - name: Select used range edge - fileName: range-get-range-edge.yaml - description: >- - This sample shows how to select the edges of the used range, based on the - currently selected range. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-get-range-edge.yaml - group: Range - api_set: - ExcelAPI: '1.13' -- id: excel-direct-dependents - name: Direct dependents - fileName: range-direct-dependents.yaml - description: >- - This sample shows how to find and highlight the direct dependents of the - currently selected cell. Dependent cells contain formulas that refer to - other cells. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-direct-dependents.yaml - group: Range - api_set: - ExcelAPI: '1.13' -- id: excel-range-dependents - name: Dependents - fileName: range-dependents.yaml - description: >- - This sample shows how to find and highlight the dependents of the currently - selected cell. Dependent cells contain formulas that refer to other cells. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-dependents.yaml - group: Range - api_set: - ExcelAPI: '1.15' -- id: excel-shape-create-and-delete - name: Create and delete geometric shapes - fileName: shape-create-and-delete.yaml - description: >- - Creates a few different geometric shapes and deletes them from the - worksheet. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-create-and-delete.yaml - group: Shape - api_set: - ExcelApi: '1.9' -- id: excel-shape-images - name: Image shapes - fileName: shape-images.yaml - description: Creates and adjusts image-based shapes. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-images.yaml - group: Shape - api_set: - ExcelApi: '1.9' -- id: excel-shape-lines - name: Lines - fileName: shape-lines.yaml - description: Creates and modifies line shapes. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-lines.yaml - group: Shape - api_set: - ExcelApi: '1.9' -- id: excel-shape-move-and-order - name: Move and order shapes - fileName: shape-move-and-order.yaml - description: Moves created shapes around the worksheet and adjusts their z-order. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-move-and-order.yaml - group: Shape - api_set: - ExcelApi: '1.9' -- id: excel-shape-groups - name: Shape groups - fileName: shape-groups.yaml - description: Groups and ungroups shapes. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-groups.yaml - group: Shape - api_set: - ExcelApi: '1.9' -- id: excel-shape-textboxes - name: Textboxes - fileName: shape-textboxes.yaml - description: Creates a textbox shape and works with the text in it and other shapes. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-textboxes.yaml - group: Shape - api_set: - ExcelApi: '1.9' -- id: excel-table-add-rows-and-columns-to-a-table - name: Add rows and columns - fileName: add-rows-and-columns-to-a-table.yaml - description: Adds rows and columns to a table. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/add-rows-and-columns-to-a-table.yaml - group: Table - api_set: - ExcelApi: '1.4' -- id: excel-table-convert-range-to-table - name: Convert a range - fileName: convert-range-to-table.yaml - description: Converts a range to a table. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/convert-range-to-table.yaml - group: Table - api_set: - ExcelApi: '1.4' -- id: excel-table-create-table - name: Create a table - fileName: create-table.yaml - description: Creates a table. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/create-table.yaml - group: Table - api_set: - ExcelApi: '1.4' -- id: excel-table-filter-data - name: Filter data - fileName: filter-data.yaml - description: Filters table data. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/filter-data.yaml - group: Table - api_set: - ExcelApi: '1.4' -- id: excel-table-formatting - name: Formatting - fileName: formatting.yaml - description: Formats a table. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/formatting.yaml - group: Table - api_set: - ExcelApi: '1.4' -- id: excel-table-get-data-from-table - name: Get data - fileName: get-data-from-table.yaml - description: Gets data from a table. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/get-data-from-table.yaml - group: Table - api_set: - ExcelApi: '1.4' -- id: excel-table-get-visible-range-of-a-filtered-table - name: Get visible range - fileName: get-visible-range-of-a-filtered-table.yaml - description: Gets the visible range from a filtered table. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/get-visible-range-of-a-filtered-table.yaml - group: Table - api_set: - ExcelApi: '1.4' -- id: excel-table-import-json-data - name: Import JSON data - fileName: import-json-data.yaml - description: Imports JSON data into a table. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/import-json-data.yaml - group: Table - api_set: - ExcelApi: '1.4' -- id: excel-table-sort-data - name: Sort data - fileName: sort-data.yaml - description: Sorts the data within a table. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/sort-data.yaml - group: Table - api_set: - ExcelApi: '1.4' -- id: excel-table-resize - name: Resize a table - fileName: resize-table.yaml - description: This sample shows how to resize a table. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/resize-table.yaml - group: Table - api_set: - ExcelAPI: '1.13' -- id: excel-workbook-get-active-cell - name: Active cell - fileName: workbook-get-active-cell.yaml - description: Gets the active cell of the entire workbook. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/workbook-get-active-cell.yaml - group: Workbook - api_set: - ExcelApi: '1.7' -- id: excel-settings-create-get-change-delete-settings - name: Add-in settings - fileName: create-get-change-delete-settings.yaml - description: >- - Creates, gets, changes, and deletes settings that are unique to the specific - workbook and add-in combination. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/create-get-change-delete-settings.yaml - group: Workbook - api_set: - ExcelApi: '1.4' -- id: excel-workbook-calculation - name: Calculations - fileName: workbook-calculation.yaml - description: >- - Demonstrates the calculation APIs of the workbook: events for when the - worksheet recalculates and application-level calculation controls. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/workbook-calculation.yaml - group: Workbook - api_set: - ExcelApi: '1.11' -- id: excel-workbook-create-workbook - name: Create workbook - fileName: create-workbook.yaml - description: >- - Creates a new, empty workbook and creates a new workbook by copying an - existing one. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/create-workbook.yaml - group: Workbook - api_set: - ExcelApi: '1.8' -- id: excel-culture-info - name: Culture info - fileName: culture-info.yaml - description: >- - This sample shows how to apply the cultural settings APIs to help normalize - data. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/culture-info.yaml - group: Workbook - api_set: - ExcelApi: '1.11' -- id: excel-culture-info-date-time - name: 'Culture info: date and time' - fileName: culture-info-date-time.yaml - description: >- - This sample shows how to use the read-only cultural settings APIs to - retrieve system date and time settings. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/culture-info-date-time.yaml - group: Workbook - api_set: - ExcelAPI: '1.12' -- id: excel-workbook-data-protection - name: Data protection - fileName: data-protection.yaml - description: Protects data in a worksheet and the workbook structure. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/data-protection.yaml - group: Workbook - api_set: - ExcelApi: '1.7' -- id: excel-workbook-save-and-close - name: Save and close - fileName: workbook-save-and-close.yaml - description: Saves and closes a workbook. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/workbook-save-and-close.yaml - group: Workbook - api_set: - ExcelAPI: '1.11' -- id: excel-workbook-insert-external-worksheets - name: Insert external worksheets - fileName: workbook-insert-external-worksheets.yaml - description: Inserts worksheets from another workbook into the current workbook. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml - group: Workbook - api_set: - ExcelAPI: '1.13' -- id: excel-worksheet-active-worksheet - name: Active worksheet - fileName: active-worksheet.yaml - description: Gets and sets the active worksheet. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/active-worksheet.yaml - group: Worksheet - api_set: - ExcelApi: '1.1' -- id: excel-worksheet-add-delete-rename-move-worksheet - name: 'Add, delete, rename, and move worksheet' - fileName: add-delete-rename-move-worksheet.yaml - description: 'Adds, deletes, renames, and moves a worksheet.' - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/add-delete-rename-move-worksheet.yaml - group: Worksheet - api_set: - ExcelApi: '1.1' -- id: excel-worksheet-auto-filter - name: AutoFilter - fileName: worksheet-auto-filter.yaml - description: Adds an AutoFilter to a worksheet. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-auto-filter.yaml - group: Worksheet - api_set: - ExcelApi: '1.9' -- id: excel-worksheet-copy - name: Copy worksheet - fileName: worksheet-copy.yaml - description: Copies the active worksheet to the specified location. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-copy.yaml - group: Worksheet - api_set: - ExcelApi: '1.7' -- id: excel-worksheet-find-all - name: Find text matches within a worksheet - fileName: worksheet-find-all.yaml - description: Finds cells within a worksheet based on string matching. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-find-all.yaml - group: Worksheet - api_set: - ExcelApi: '1.9' -- id: excel-worksheet-freeze-panes - name: Frozen panes - fileName: worksheet-freeze-panes.yaml - description: >- - Freezes columns, rows, and a range of cells. Gets the address of the frozen - pane. Unfreezes frozen panes. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-freeze-panes.yaml - group: Worksheet - api_set: - ExcelApi: '1.7' -- id: excel-worksheet-worksheet-range-cell - name: Get range or cell - fileName: worksheet-range-cell.yaml - description: >- - Gets the used range, the entire range of a worksheet, the specified range, - and the specified cell. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-range-cell.yaml - group: Worksheet - api_set: - ExcelApi: '1.4' -- id: excel-worksheet-gridlines - name: Gridlines - fileName: gridlines.yaml - description: Hides and shows a worksheet's gridlines. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/gridlines.yaml - group: Worksheet - api_set: - ExcelApi: '1.8' -- id: excel-worksheet-list-worksheets - name: List worksheets - fileName: list-worksheets.yaml - description: Lists the worksheets in the workbook. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/list-worksheets.yaml - group: Worksheet - api_set: - ExcelApi: '1.1' -- id: excel-worksheet-page-layout - name: Page layout and print settings - fileName: worksheet-page-layout.yaml - description: Changes the page layout and other settings for printing a worksheet. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-page-layout.yaml - group: Worksheet - api_set: - ExcelApi: '1.9' -- id: excel-worksheet-reference-worksheets-by-relative-position - name: Reference worksheets by relative position - fileName: reference-worksheets-by-relative-position.yaml - description: Gets a worksheet by using its relative position within the workbook. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml - group: Worksheet - api_set: - ExcelApi: '1.5' -- id: excel-worksheet-tab-color - name: Tab color - fileName: tab-color.yaml - description: Gets and sets the tab color of a worksheet. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/tab-color.yaml - group: Worksheet - api_set: - ExcelApi: '1.7' -- id: excel-worksheet-visibility - name: Visibility - fileName: worksheet-visibility.yaml - description: Hides and unhides a worksheet. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-visibility.yaml - group: Worksheet - api_set: - ExcelApi: '1.1' -- id: excel-performance-optimization - name: Performance optimization - fileName: performance-optimization.yaml - description: >- - Optimizes performance by untracking ranges, turning off screen painting, and - switching the calculation mode. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/performance-optimization.yaml - group: Scenarios - api_set: - ExcelApi: '1.9' -- id: excel-scenarios-report-generation - name: Report generation - fileName: report-generation.yaml - description: >- - Writes data to the workbook, reads and applies basic formatting, and adds a - chart bound to that data. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/report-generation.yaml - group: Scenarios - api_set: - ExcelApi: '1.1' -- id: excel-scenarios-multiple-property-set - name: Set multiple properties - fileName: multiple-property-set.yaml - description: Sets multiple properties at once with the API object set() method. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/multiple-property-set.yaml - group: Scenarios - api_set: - ExcelApi: '1.4' -- id: excel-scenarios-working-with-dates - name: Working with dates - fileName: working-with-dates.yaml - description: >- - Shows how to work with dates by using the Moment JavaScript library with the - Moment-MSDate plug-in. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/working-with-dates.yaml - group: Scenarios - api_set: - ExcelApi: '1.4' -- id: excel-scenarios-currency-converter - name: Currency Converter - fileName: currency-converter.yaml - description: >- - Uses an exchange rate API to convert currency values based on their original - transaction times. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/currency-converter.yaml - group: Scenarios - api_set: - ExcelApi: '1.4' -- id: excel-just-for-fun-patterns - name: Colorful Patterns - fileName: patterns.yaml - description: >- - Uses range formatting to draw interesting pattern. Contributed by Alexander - Zlatkovski. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/99-just-for-fun/patterns.yaml - group: Just For Fun - api_set: - ExcelApi: '1.4' -- id: excel-just-for-fun-gradient - name: Gradient - fileName: gradient.yaml - description: >- - Uses range formatting and external libraries to draw a colorful gradient - within a range. Contributed by Alexander Zlatkovski. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/99-just-for-fun/gradient.yaml - group: Just For Fun - api_set: - ExcelApi: '1.4' -- id: excel-just-for-fun-path-finder-game - name: Path finder - fileName: path-finder-game.yaml - description: >- - Uses range formatting to play a "pathfinder game". Contributed by Alexander - Zlatkovski. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/99-just-for-fun/path-finder-game.yaml - group: Just For Fun - api_set: - ExcelApi: '1.4' -- id: excel-just-for-fun-tetrominos - name: Tetromino stacking - fileName: tetrominos.yaml - description: Arrange moving tetromino shapes to form lines. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/99-just-for-fun/tetrominos.yaml - group: Just For Fun - api_set: - ExcelApi: '1.9' -- id: excel-just-for-fun-color-wheel - name: Wheel of colors - fileName: color-wheel.yaml - description: >- - Uses chart formatting to draw a wheel with changing colors. Contributed by - Alexander Zlatkovski. - rawUrl: >- - https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/99-just-for-fun/color-wheel.yaml - group: Just For Fun - api_set: - ExcelApi: '1.4' + CustomFunctionsRuntime: 1.4 \ No newline at end of file diff --git a/samples/excel/01-basics/basic-api-call-es5.yaml b/samples/excel/01-basics/basic-api-call-es5.yaml deleted file mode 100644 index 949160c1a..000000000 --- a/samples/excel/01-basics/basic-api-call-es5.yaml +++ /dev/null @@ -1,73 +0,0 @@ -order: 2 -id: excel-basics-basic-api-call-es5 -name: Basic API call (JavaScript) -description: Performs a basic Excel API call using plain JavaScript & Promises. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.1' -script: - content: | - $("#run").click(() => tryCatch(run)); - - function run() { - return Excel.run(function (context) { - var range = context.workbook.getSelectedRange(); - range.format.fill.color = "yellow"; - range.load("address"); - return context.sync() - .then(function () { - console.log("The range address was \"" + range.address + "\"."); - }); - }); - } - - /** Default helper for invoking an action and handling errors. */ - function tryCatch(callback) { - Promise.resolve() - .then(callback) - .catch(function (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - }); - } - language: typescript -template: - content: | -
-

This sample demonstrates basic Excel API calls.

-
- -
-

Try it out

-

Select some cells in the worksheet, then press Highlight selected range.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/01-basics/basic-api-call.yaml b/samples/excel/01-basics/basic-api-call.yaml deleted file mode 100644 index ff3e77392..000000000 --- a/samples/excel/01-basics/basic-api-call.yaml +++ /dev/null @@ -1,74 +0,0 @@ -order: 1 -id: excel-basics-basic-api-call -name: Basic API call (TypeScript) -description: Performs a basic Excel API call using TypeScript. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.1' -script: - content: | - $("#run").click(() => tryCatch(run)); - - async function run() { - await Excel.run(async (context) => { - const range = context.workbook.getSelectedRange(); - range.format.fill.color = "yellow"; - range.load("address"); - - await context.sync() - - console.log(`The range address was "${range.address}".`); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample demonstrates basic Excel API calls.

-
- -
-

Try it out

-

Select some cells in the worksheet, then press Highlight selected range.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/01-basics/basic-common-api-call.yaml b/samples/excel/01-basics/basic-common-api-call.yaml deleted file mode 100644 index 4299dd3a7..000000000 --- a/samples/excel/01-basics/basic-common-api-call.yaml +++ /dev/null @@ -1,65 +0,0 @@ -order: 3 -id: excel-basics-basic-common-api-call -name: Basic API call (Office 2013) -description: Performs a basic Excel API call using JavaScript with the "common API" syntax (compatible with Office 2013). -author: OfficeDev -host: EXCEL -api_set: - Selection: 1.1 -script: - content: | - $("#run").click(run); - - function run() { - Office.context.document.getSelectedDataAsync( - Office.CoercionType.Text, - asyncResult => { - if (asyncResult.status === Office.AsyncResultStatus.Failed) { - console.error(asyncResult.error.message); - } else { - console.log(`The selected data is "${asyncResult.value}".`); - } - } - ); - } - language: typescript -template: - content: | -
-

This sample uses the Common APIs compatible with Office 2013.

-
- -
-

Try it out

-

Select a cell in the worksheet and press Write to console to see the contents of that cell in the console.

-

-

Be sure to exit cell-editing context before pressing the button.

-
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-axis-formatting.yaml b/samples/excel/10-chart/chart-axis-formatting.yaml deleted file mode 100644 index 36cadc25a..000000000 --- a/samples/excel/10-chart/chart-axis-formatting.yaml +++ /dev/null @@ -1,170 +0,0 @@ -order: 2 -id: excel-chart-axis-formatting -name: Axis formatting -description: Formats the vertical and horizontal axes in a chart. -host: EXCEL -api_set: - ExcelApi: '1.8' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#format-horizontal-axis").click(() => tryCatch(formatHorizontalAxis)); - $("#format-vertical-axis").click(() => tryCatch(formatVerticalAxis)); - - async function formatHorizontalAxis() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getActiveWorksheet(); - - let chart = sheet.charts.getItem("SalesChart"); - let axis = chart.axes.categoryAxis; - - axis.reversePlotOrder = true; - axis.tickLabelSpacing = 1; - axis.tickMarkSpacing = 2; - axis.isBetweenCategories = false; - axis.tickLabelPosition = "High"; - axis.majorTickMark = "Outside"; - axis.position = "Maximum"; - - await context.sync(); - }); - } - - async function formatVerticalAxis() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getActiveWorksheet(); - - let chart = sheet.charts.getItem("SalesChart"); - let axis = chart.axes.valueAxis; - - axis.displayUnit = "None"; - axis.scaleType = "Logarithmic"; - axis.logBase = 100; - axis.majorTickMark = "Cross"; - - // Set the product name label location. - // In this case, the location is at 100 units. - axis.setPositionAt(100); - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let salesTable = sheet.tables.add('A1:E1', true); - salesTable.name = "SalesTable"; - - salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - salesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - createChart(context); - displayUnit(context); - sheet.activate(); - - await context.sync(); - }); - } - - async function createChart(context: Excel.RequestContext) { - let sheet = context.workbook.worksheets.getItem("Sample"); - let salesTable = sheet.tables.getItem("SalesTable"); - - let dataRange = sheet.getRange("A1:E7"); - let chart = sheet.charts.add("Line", dataRange, "Auto"); - - chart.setPosition("A15", "I30"); - chart.legend.position = "Right" - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - - chart.axes.categoryAxis.majorGridlines.visible = true; - chart.axes.categoryAxis.majorTickMark = "None"; - chart.title.text = "Sales of Bicycle Parts"; - chart.name = "SalesChart"; - - await context.sync(); - } - - function displayUnit(context: Excel.RequestContext) { - let sheet = context.workbook.worksheets.getItem("Sample"); - let chart = sheet.charts.getItem("SalesChart"); - let axis = chart.axes.valueAxis; - axis.displayUnit = "Thousands"; - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- - -
-

This sample shows how to format the vertical and horizontal axis in a chart.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- -
- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-axis.yaml b/samples/excel/10-chart/chart-axis.yaml deleted file mode 100644 index f37d4ee45..000000000 --- a/samples/excel/10-chart/chart-axis.yaml +++ /dev/null @@ -1,239 +0,0 @@ -order: 1 -id: excel-chart-axis -name: Axis details -description: 'Gets, sets, and removes axis unit, label, and title in a chart.' -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - $("#get-axis-unit").click(() => tryCatch(getAxisUnit)); - $("#change-axis-unit").click(() => tryCatch(changeAxisUnit)); - $("#remove-axis-label").click(() => tryCatch(removeAxisLabel)); - $("#show-axis-label").click(() => tryCatch(showAxisLabel)); - $("#set-axis-title").click(() => tryCatch(setAxisTitle)); - - async function getAxisUnit() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let chart = sheet.charts.getItemAt(0); - let categoryAxis = chart.axes.categoryAxis; - let valueAxis = chart.axes.valueAxis; - - // Load to get display unit. - valueAxis.load("displayUnit"); - - await context.sync(); - - console.log("The vertical axis display unit is: " + valueAxis.displayUnit); - }); - } - - async function changeAxisUnit() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let chart = sheet.charts.getItemAt(0); - let axis = chart.axes.valueAxis; - - // Set display unit. - axis.displayUnit = "Hundreds"; - - await context.sync(); - }); - } - - async function removeAxisLabel() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - let chart = sheet.charts.getItemAt(0); - let axis = chart.axes.valueAxis; - - // Remove display unit. - axis.showDisplayUnitLabel = false; - - await context.sync(); - }); - } - - async function showAxisLabel() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let chart = sheet.charts.getItemAt(0); - let axis = chart.axes.valueAxis; - - // Show display unit. - axis.showDisplayUnitLabel = true; - await context.sync(); - }); - } - - async function setAxisTitle() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let chart = sheet.charts.getItemAt(0); - let categoryAxis = chart.axes.categoryAxis; - - // Set horizontal axis title. - categoryAxis.title.text = "Bicycle parts"; - - let valueAxis = chart.axes.valueAxis; - - // Set vertical axis title. - valueAxis.title.text = "Number of items"; - - // Show small gridlines. - valueAxis.minorGridlines.visible = true; - - categoryAxis.title.load("text"); - valueAxis.load("text"); - valueAxis.minorGridlines.load("visible"); - - await context.sync(); - - console.log("The category axis title is: " + categoryAxis.title.text); - console.log("The value axis title is: " + valueAxis.title.text); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add("A1:E1", true); - expensesTable.name = "SalesTable"; - - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - const chart = createChart(context); - addVerticalAxisLabel(chart); - sheet.activate(); - - await context.sync(); - }); - } - - function createChart(context: Excel.RequestContext) { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - - const dataRange = salesTable.getRange(); - - let chart = sheet.charts.add( - "ColumnClustered", - dataRange, - Excel.ChartSeriesBy.columns - ); - - chart.setPosition("A15", "F30"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Right"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - let points = chart.series.getItemAt(0).points; - - return chart; - } - - function addVerticalAxisLabel(chart: Excel.Chart) { - let axis = chart.axes.valueAxis; - axis.displayUnit = "Thousands"; - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to get, set, and remove axis unit, label and title in a chart.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- -
- -
- -
- -
- -
- -
- -
- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-bubble-chart.yaml b/samples/excel/10-chart/chart-bubble-chart.yaml deleted file mode 100644 index 108325244..000000000 --- a/samples/excel/10-chart/chart-bubble-chart.yaml +++ /dev/null @@ -1,164 +0,0 @@ -order: 4 -id: excel-chart-bubble-chart -name: Create bubble chart -description: Creates a bubble chart with each data row represented as a single chart series (bubble). -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.12' -script: - content: | - $("#setup").click(() => tryCatch(setup)); $("#create-bubble-chart").click(() => tryCatch(createBubbleChart)); $("#get-chart-series-dimension-values").click(() => tryCatch(getChartSeriesDimensionValues)); - async function createBubbleChart() { - await Excel.run(async (context) => { - /* - The table is expected to look like this: - Product, Inventory, Price, Current Market Share - Calamansi, 2000, $2.45, 10% - ... - - We want each bubble to represent a single row. - */ - - // Get the worksheet and table data. - const sheet = context.workbook.worksheets.getItem("Sample"); - const table = sheet.tables.getItem("Sales"); - const dataRange = table.getDataBodyRange(); - - // Get the table data without the row names. - const valueRange = dataRange.getOffsetRange(0, 1).getResizedRange(0, -1); - - // Create the chart. - const bubbleChart = sheet.charts.add(Excel.ChartType.bubble, valueRange); - bubbleChart.name = "Product Chart"; - - // Remove the default series, since we want a unique series for each row. - bubbleChart.series.getItemAt(0).delete(); - - // Load the data necessary to make a chart series. - dataRange.load(["rowCount", "values"]); - await context.sync(); - - // For each row, create a chart series (a bubble). - for (let i = 0; i < dataRange.rowCount; i++) { - const newSeries = bubbleChart.series.add(dataRange.values[i][0], i); - newSeries.setXAxisValues(dataRange.getCell(i, 1)); - newSeries.setValues(dataRange.getCell(i, 2)); - newSeries.setBubbleSizes(dataRange.getCell(i, 3)); - - // Show the product name and market share percentage. - newSeries.dataLabels.showSeriesName = true; - newSeries.dataLabels.showBubbleSize = true; - newSeries.dataLabels.showValue = false; - } - - await context.sync(); - }); - } - async function getChartSeriesDimensionValues() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - // The sample chart is of type `Excel.ChartType.bubble`. - const bubbleChart = sheet.charts.getItem("Product Chart"); - - // Get the first series in the chart. - const firstSeries = bubbleChart.series.getItemAt(0); - - // Get the values for the dimensions we're interested in. - const bubbleSize = firstSeries.getDimensionValues(Excel.ChartSeriesDimension.bubbleSizes); - const xValues = firstSeries.getDimensionValues(Excel.ChartSeriesDimension.xvalues); - const yValues = firstSeries.getDimensionValues(Excel.ChartSeriesDimension.yvalues); - const category = firstSeries.getDimensionValues(Excel.ChartSeriesDimension.categories); - - await context.sync(); - - // Log the information. - console.log(`Series ${category.value} - X:${xValues.value},Y:${yValues.value},Bubble:${bubbleSize.value}`); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let inventoryTable = sheet.tables.add("A1:D1", true); - inventoryTable.name = "Sales"; - inventoryTable.getHeaderRowRange().values = [["Product", "Inventory", "Price", "Current Market Share"]]; - - inventoryTable.rows.add(null, [ - ["Calamansi", 2000, "$2.45", "10%"], - ["Cara cara orange", 10000, "$2.12", "45%"], - ["Limequat", 4000, "$0.70", "66%"], - ["Meyer lemon", 100, "$2.65", "5%"], - ["Pomelo", 4000, "$1.69", "14%"], - ["Yuzu", 7500, "$3.23", "34%"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create a bubble chart, with each chart series (or bubble) representing a single table row.

-
- -
-

Set up

- -
- -
-

Try it out

- -

- -

- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-create-several-charts.yaml b/samples/excel/10-chart/chart-create-several-charts.yaml deleted file mode 100644 index 53ffff914..000000000 --- a/samples/excel/10-chart/chart-create-several-charts.yaml +++ /dev/null @@ -1,335 +0,0 @@ -order: 5 -id: excel-chart-create-several-charts -name: Create charts -description: 'Creates column-clustered, line, XY-scatter, area, radar, pie, 3D, cylinder, and 100% charts.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#create-column-clustered-chart").click(() => tryCatch(createColumnClusteredChart)); - $("#create-line-chart").click(() => tryCatch(createLineChart)); - $("#create-xy-scatter-chart").click(() => tryCatch(createXYScatterChart)); - $("#create-area-chart").click(() => tryCatch(createAreaStackedChart)); - $("#create-radar-chart").click(() => tryCatch(createRadarFilledChart)); - $("#create-pie-chart").click(() => tryCatch(createPieChart)); - $("#create-3d-chart").click(() => tryCatch(create3DChart)); - $("#create-cylinder-chart").click(() => tryCatch(createCylinderChart)); - $("#create-bar-100-chart").click(() => tryCatch(createBar100Chart)); - - async function createColumnClusteredChart() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const salesTable = sheet.tables.getItem("SalesTable"); - - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add("ColumnClustered", dataRange, "Auto"); - - chart.setPosition("A9", "F20"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Right"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - let points = chart.series.getItemAt(0).points; - points.getItemAt(0).format.fill.setSolidColor("pink"); - points.getItemAt(1).format.fill.setSolidColor("indigo"); - - await context.sync(); - }); - } - - async function createLineChart() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - let salesTable = sheet.tables.getItem("SalesTable"); - - let dataRange = sheet.getRange("A1:E7"); - let chart = sheet.charts.add(Excel.ChartType.line, dataRange, "Auto"); - - chart.setPosition("A22", "F35"); - chart.legend.position = "Right"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - chart.title.text = "Bicycle Parts Quarterly Sales"; - - await context.sync(); - }); - } - - async function createXYScatterChart() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - let salesTable = sheet.tables.getItem("SalesTable"); - - let dataRange = sheet.getRange("A1:E7"); - - // Create an XY scatter chart. - let chart = sheet.charts.add(Excel.ChartType.xyscatter, dataRange, "Auto"); - chart.title.text = "Bicycle Parts Quarterly Sales"; - chart.setPosition("A36", "F48"); - - await context.sync(); - }); - } - - async function createAreaStackedChart() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add(Excel.ChartType.areaStacked, dataRange, "Auto"); - - chart.setPosition("H1", "M15"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Bottom"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - chart.series.getItemAt(0).name = "Q1"; - chart.series.getItemAt(1).name = "Q2"; - chart.series.getItemAt(2).name = "Q3"; - chart.series.getItemAt(3).name = "Q4"; - - await context.sync(); - }); - } - - async function createRadarFilledChart() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add(Excel.ChartType.radarFilled, dataRange, "Auto"); - - chart.setPosition("H17", "M35"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Bottom"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - chart.series.getItemAt(0).name = "Q1"; - chart.series.getItemAt(1).name = "Q2"; - chart.series.getItemAt(2).name = "Q3"; - chart.series.getItemAt(3).name = "Q4"; - - await context.sync(); - }); - } - - async function createPieChart() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add("Pie", dataRange, "Auto"); - - chart.setPosition("H37", "M52"); - chart.title.text = "1st Quarter sales chart"; - chart.legend.position = "Bottom"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - - await context.sync(); - }); - } - - async function create3DChart() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add(Excel.ChartType._3DBarClustered, dataRange, "Auto"); - - chart.setPosition("O1", "T20"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Bottom"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - chart.series.getItemAt(0).name = "Q1"; - chart.series.getItemAt(1).name = "Q2"; - chart.series.getItemAt(2).name = "Q3"; - chart.series.getItemAt(3).name = "Q4"; - - await context.sync(); - }); - } - - async function createCylinderChart() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add(Excel.ChartType.cylinderCol, dataRange, "Auto"); - - chart.setPosition("O22", "T36"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Bottom"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - chart.series.getItemAt(0).name = "Q1"; - chart.series.getItemAt(1).name = "Q2"; - chart.series.getItemAt(2).name = "Q3"; - chart.series.getItemAt(3).name = "Q4"; - - await context.sync(); - }); - } - - async function createBar100Chart() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add(Excel.ChartType.barStacked100, dataRange, "Auto"); - - chart.setPosition("O38", "T50"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Bottom"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - chart.series.getItemAt(0).name = "Q1"; - chart.series.getItemAt(1).name = "Q2"; - chart.series.getItemAt(2).name = "Q3"; - chart.series.getItemAt(3).name = "Q4"; - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add("A1:E1", true); - expensesTable.name = "SalesTable"; - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create column-clustered, line, XY-scatter, area, radar, pie, 3D, cylinder, and 100% charts.

-
- -
-

Set up

- -
- -
-

Try it out

- -

- - -

- - -

- - -

- - -

- - -

- - -

- - -

- - -

- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-data-source.yaml b/samples/excel/10-chart/chart-data-source.yaml deleted file mode 100644 index cb0b65ca1..000000000 --- a/samples/excel/10-chart/chart-data-source.yaml +++ /dev/null @@ -1,127 +0,0 @@ -order: 14 -id: excel-chart-data-source -name: Chart series data source -description: This sample shows how to get information about the data source of a chart series. -host: EXCEL -api_set: - ExcelApi: '1.15' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#log-chart-series-source").click(() => tryCatch(logChartSeriesSource)); - - async function logChartSeriesSource() { - // This function retrieves the data source information of a chart series in the Sample worksheet. - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - // Get the first chart series from the first chart on the worksheet. - const seriesCollection = sheet.charts.getItemAt(0).series; - const series = seriesCollection.getItemAt(0); - - // Get the series data source string and type values. - const dataSourceString = series.getDimensionDataSourceString("Values"); - const dataSourceType = series.getDimensionDataSourceType("Values"); - - series.load("name"); - await context.sync(); - - // Log the data source information to the console. - console.log(series.name + " data source string: " + dataSourceString.value); - console.log(series.name + " data source type: " + dataSourceType.value); - }); - } - - async function setup() { - await Excel.run(async (context) => { - // Create a new worksheet called "Sample" and activate it. - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - // Create an a table named SalesTable on the Sample worksheet. - let expensesTable = sheet.tables.add("A1:E1", true); - expensesTable.name = "SalesTable"; - - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - sheet.activate(); - - // Create a line chart based on data from SalesTable. - let dataRange = sheet.getRange("A1:E7"); - let chart = sheet.charts.add("Line", dataRange, Excel.ChartSeriesBy.rows); - - // Position and style the chart. - chart.setPosition("A15", "E30"); - chart.legend.position = "Right"; - chart.legend.format.fill.setSolidColor("white"); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to get information about the data source of a chart series.

-
- -
-

Set up

-

Add a product table and line chart to a sample worksheet.

- -
- -
-

Try it out

-

Log information to the console about the data source of the chart series Frames.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-data-table.yaml b/samples/excel/10-chart/chart-data-table.yaml deleted file mode 100644 index 9d0c5b04d..000000000 --- a/samples/excel/10-chart/chart-data-table.yaml +++ /dev/null @@ -1,163 +0,0 @@ -order: 3 -id: excel-chart-data-table -name: Chart data table -description: Add a data table to a chart and then format that data table. -host: EXCEL -api_set: - ExcelApi: '1.14' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#create-column-clustered-chart").click(() => tryCatch(createColumnClusteredChart)); - $("#add-chart-data-table").click(() => tryCatch(addChartDataTable)); - $("#format-chart-data-table").click(() => tryCatch(formatChartDataTable)); - - async function createColumnClusteredChart() { - // This function creates a clustered column chart based on data from a table on - // this worksheet and then sets name, position, and format for the chart. - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - // Create a clustered column chart with data from "SalesTable". - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - const chart = sheet.charts.add("ColumnClustered", dataRange, "Auto"); - - // Set name, position, and format for the chart. - chart.name = "SalesChart"; - chart.title.text = "Quarterly sales chart"; - chart.setPosition("A9", "L20"); - chart.legend.position = "Right"; - chart.legend.format.fill.setSolidColor("white"); - - const points = chart.series.getItemAt(0).points; - points.getItemAt(0).format.fill.setSolidColor("pink"); - points.getItemAt(1).format.fill.setSolidColor("indigo"); - - await context.sync(); - }); - } - - async function addChartDataTable() { - // This function adds a data table to a chart that already exists on the worksheet. - await Excel.run(async (context) => { - // Retrieve the chart named "SalesChart" from the "Sample" worksheet. - const chart = context.workbook.worksheets.getItem("Sample").charts.getItem("SalesChart"); - - // Get the data table object for the chart and set it to visible. - const chartDataTable = chart.getDataTableOrNullObject(); - chartDataTable.load("visible"); - chartDataTable.visible = true; - await context.sync(); - }); - } - - async function formatChartDataTable() { - // This function adjusts the display and format of a chart data table that already exists on the worksheet. - await Excel.run(async (context) => { - // Retrieve the chart named "SalesChart" from the "Sample" worksheet. - const chart = context.workbook.worksheets.getItem("Sample").charts.getItem("SalesChart"); - - // Get the chart data table object and load its properties. - const chartDataTable = chart.getDataTableOrNullObject(); - chartDataTable.load(); - - // Set the display properties of the chart data table. - chartDataTable.showLegendKey = true; - chartDataTable.showHorizontalBorder = false; - chartDataTable.showVerticalBorder = true; - chartDataTable.showOutlineBorder = true; - - // Retrieve the chart data table format object and set font and border properties. - const chartDataTableFormat = chartDataTable.format; - chartDataTableFormat.font.color = "#B76E79"; - chartDataTableFormat.font.name = "Comic Sans"; - chartDataTableFormat.border.color = "blue"; - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add("A1:E1", true); - expensesTable.name = "SalesTable"; - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to add a data table to a chart and then format that data table.

-
- -
-

Set up

- -

- -
- -
-

Try it out

- -

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - core-js@2.4.1/client/core.min.js - @types/core-js - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-formatting.yaml b/samples/excel/10-chart/chart-formatting.yaml deleted file mode 100644 index 319878a32..000000000 --- a/samples/excel/10-chart/chart-formatting.yaml +++ /dev/null @@ -1,225 +0,0 @@ -order: 7 -id: excel-chart-formatting -name: Formatting -description: Formats labels and lines of a slope chart. -host: EXCEL -api_set: - ExcelApi: '1.8' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#format-chart").click(() => tryCatch(formatChart)); - $("#show-datalabels").click(() => tryCatch(dataLabels)); - $("#change-color").click(() => tryCatch(changeColor)); - $("#clear").click(() => tryCatch(clearChart)); - - async function formatChart() { - await Excel.run(async (context) => { - const worksheet = context.workbook.worksheets.getActiveWorksheet(); - const chart = worksheet.charts.getItem("SlopeChart"); - - chart.axes.valueAxis.tickLabelPosition = "None"; - chart.plotArea.width = 800; - chart.plotArea.left = 80; - - chart.title.format.font.size = 14.4; - chart.title.text = "Contoso Bike Parts - 2018"; - chart.title.format.font.name = "Times New Roman"; - chart.title.format.font.color = "#D9D9D9"; - - chart.legend.format.font.name = "Times New Roman"; - chart.legend.format.font.color = "#D9D9D9"; - - chart.axes.categoryAxis.format.font.name = "Times New Roman"; - chart.axes.categoryAxis.format.font.color = "#D9D9D9"; - chart.axes.valueAxis.majorGridlines.format.line.color = "#585858"; - chart.format.fill.setSolidColor("#404040"); - await context.sync(); - }); - } - - async function dataLabels() { - await Excel.run(async (context) => { - const worksheet = context.workbook.worksheets.getActiveWorksheet(); - const chart = worksheet.charts.getItem("SlopeChart"); - chart.series.load("count"); - await context.sync(); - let pointsLoaded = -1; - for (let i = 0; i < chart.series.count; i++) { - const series = chart.series.getItemAt(i); - series.hasDataLabels = true; - series.markerSize = 20; - - series.markerBackgroundColor = "#404040"; - series.markerForegroundColor = "#404040"; - - // there are an equal number of points in each series, so we only want to load and sync once - if (pointsLoaded < 0) { - series.points.load("count"); - await context.sync(); - pointsLoaded = series.points.count; - } - - for (let j = 0; j < pointsLoaded; j++) { - // the colors assume "Format chart" has been pressed - series.points.getItemAt(j).markerBackgroundColor = "#404040"; - series.points.getItemAt(j).markerForegroundColor = "#404040"; - } - - series.points.getItemAt(3).dataLabel.showSeriesName = true; - } - - chart.dataLabels.position = "Center"; - chart.dataLabels.separator = "\n"; - chart.dataLabels.format.font.color = "#D9D9D9"; - await context.sync(); - }); - } - - async function changeColor() { - await Excel.run(async (context) => { - const worksheet = context.workbook.worksheets.getActiveWorksheet(); - const chart = worksheet.charts.getItem("SlopeChart"); - chart.series.load("count"); - await context.sync(); - - // color everything grey before highlighting spokes - for (let i = 0; i < chart.series.count; i++) { - chart.series.getItemAt(i).format.line.color = "#636363"; - chart.series.getItemAt(i).dataLabels.format.font.color = "#636363"; - } - - const highlight = chart.series.getItemAt(5); - highlight.format.line.color = "#4472C4"; - highlight.dataLabels.format.font.color = "#D9D9D9"; - - highlight.load("name"); - await context.sync(); - highlight.name += " (Focus)"; - await context.sync(); - }); - } - - async function clearChart() { - await Excel.run(async (context) => { - const charts = context.workbook.worksheets.getActiveWorksheet().charts; - charts.load("count"); - await context.sync(); - - for (let i = 0; i < charts.count; i++) { - charts.getItemAt(0).delete(); - } - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let salesTable = sheet.tables.add("A1:E1", true); - salesTable.name = "SalesTable"; - - salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - salesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 5377], - ["Saddles", 400, 323, 276, 1451], - ["Brake levers", 9000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 2553], - ["Mirrors", 225, 600, 923, 344], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - createChart(context); - sheet.activate(); - }); - } - - async function createChart(context: Excel.RequestContext) { - const worksheet = context.workbook.worksheets.getActiveWorksheet(); - const chart = worksheet.charts.add( - Excel.ChartType.lineMarkers, - worksheet.getRange("A1:E7"), - Excel.ChartSeriesBy.rows - ); - chart.axes.categoryAxis.setCategoryNames(worksheet.getRange("B1:E1")); - chart.name = "SlopeChart"; - - // place chart below sample data - chart.top = 125; - chart.left = 5; - chart.height = 300; - chart.width = 450; - - chart.title.text = "Bicycle Part Production"; - chart.legend.position = "Bottom"; - - await context.sync(); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to format different aspects of a chart.

-
- -
-

Set up

- -
- -
-

Try it out

-

-

-

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-legend.yaml b/samples/excel/10-chart/chart-legend.yaml deleted file mode 100644 index 9275934e9..000000000 --- a/samples/excel/10-chart/chart-legend.yaml +++ /dev/null @@ -1,145 +0,0 @@ -order: 8 -id: excel-chart-legend -name: Legend -description: Formats the legend's font. -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#format-legend-font").click(() => tryCatch(formatLegendFont)); - - async function formatLegendFont() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let chart = sheet.charts.getItemAt(0); - chart.legend.visible = true; - - // Format the legend font. - let font = chart.legend.format.font; - font.bold = true; - font.color = "red"; - font.italic = true; - font.size = 15; - font.name = "Calibri"; - font.underline = "Single"; - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add('A1:E1', true); - expensesTable.name = "SalesTable"; - - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - createChart(context); - addVerticalAxisLabel(context); - sheet.activate(); - - await context.sync(); - }); - } - - function createChart(context: Excel.RequestContext) { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add("ColumnClustered", dataRange, Excel.ChartSeriesBy.columns); - - chart.setPosition("A15", "F30"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Right" - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - let points = chart.series.getItemAt(0).points; - points.getItemAt(0).format.fill.setSolidColor("pink"); - points.getItemAt(1).format.fill.setSolidColor("indigo"); - } - - function addVerticalAxisLabel(context: Excel.RequestContext) { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let chart = sheet.charts.getItemAt(0); - let axis = chart.axes.valueAxis; - axis.displayUnit = "Thousands"; - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to format the legend font in a chart.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-point.yaml b/samples/excel/10-chart/chart-point.yaml deleted file mode 100644 index 582fecda5..000000000 --- a/samples/excel/10-chart/chart-point.yaml +++ /dev/null @@ -1,131 +0,0 @@ -order: 9 -id: excel-chart-point -name: Points -description: Sets the color of a point on the chart. -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: |+ - $("#setup").click(() => tryCatch(setup)); - $("#set-chart-point-color").click(() => tryCatch(setChartPointColor)); - - async function setChartPointColor() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let pointsCollection = sheet.charts.getItemAt(0).series.getItemAt(0).points; - let point = pointsCollection.getItemAt(2); - - // Set color for chart point. - point.format.fill.setSolidColor('red'); - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add('A1:E1', true); - expensesTable.name = "SalesTable"; - - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - createChart(context); - sheet.activate(); - - await context.sync(); - }); - } - - function createChart(context: Excel.RequestContext) { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add("ColumnClustered", dataRange, Excel.ChartSeriesBy.columns); - - chart.setPosition("A15", "F30"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Right" - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - - - - language: typescript -template: - content: |+ -
-

This sample shows how to set chart point color.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- - language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-series-markers.yaml b/samples/excel/10-chart/chart-series-markers.yaml deleted file mode 100644 index 307aa18c0..000000000 --- a/samples/excel/10-chart/chart-series-markers.yaml +++ /dev/null @@ -1,126 +0,0 @@ -order: 11 -id: excel-chart-series-markers -name: Series markers -description: Sets the chart series marker properties. -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#set-markers").click(() => tryCatch(setMarkers)); - - async function setMarkers() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - let salesTable = sheet.tables.getItem("SalesTable"); - let dataRange = sheet.getRange("A1:E7"); - - // Create an XY scatter chart. - let chart = sheet.charts.add("XYScatterSmooth", dataRange, "Auto"); - chart.title.text = "Bicycle Parts Quarterly Sales"; - - let series = chart.series; - let series0 = series.getItemAt(0); - let series1 = series.getItemAt(1); - let series2 = series.getItemAt(2); - let series3 = series.getItemAt(3); - - // Set markers. - series0.markerStyle = "Dash"; - series0.markerForegroundColor = "black"; - series1.markerStyle = "Star"; - series1.markerForegroundColor = "black"; - series2.markerStyle = "X"; - series2.markerSize = 12; - series3.markerStyle = "Triangle"; - series3.markerBackgroundColor = "purple"; - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let salesTable = sheet.tables.add('A1:E1', true); - salesTable.name = "SalesTable"; - - salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - salesTable.rows.add(null, [ - ["Frames", 5000, 3000, 544, 1377], - ["Saddles", 400, 1323, 876, 251], - ["Brake levers", 1200, 5766, 2456, 812], - ["Chains", 1550, 1088, 692, 253], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to set chart series marker properties.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-series-plotorder.yaml b/samples/excel/10-chart/chart-series-plotorder.yaml deleted file mode 100644 index 2d1db67a8..000000000 --- a/samples/excel/10-chart/chart-series-plotorder.yaml +++ /dev/null @@ -1,137 +0,0 @@ -order: 12 -id: excel-chart-series-plotorder -name: Series plot order -description: Orders the plotting of series in a chart. -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#order-series-plot").click(() => tryCatch(addSeries)); - - async function addSeries() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - - let seriesCollection = sheet.charts.getItemAt(0); - let rangeSelection = sheet.getRange("C2:C7"); - let xRangeSelection = sheet.getRange("A1:A7"); - - // Add series. - let newSeries = seriesCollection.series.add("Qtr2"); - newSeries.setValues(rangeSelection); - newSeries.setXAxisValues(xRangeSelection); - let newSeries2 = seriesCollection.series.add("Qtr3"); - newSeries2.setValues(rangeSelection); - newSeries2.setXAxisValues(xRangeSelection); - - // Order the plotting of the series. - // In this case, Qtr 3 appears first, - // followed by Qtr 2, then Qtr 1. - newSeries2.plotOrder = 0; - newSeries.plotOrder = 1; - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let salesTable = sheet.tables.add('A1:E1', true); - salesTable.name = "SalesTable"; - - salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - salesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - createChart(context); - sheet.activate(); - - await context.sync(); - }); - } - - async function createChart(context: Excel.RequestContext) { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - - let dataRange = sheet.getRange("A1:B7"); - let chart = sheet.charts.add("ColumnClustered", dataRange, "Auto"); - - chart.setPosition("A15", "E30"); - chart.legend.position = "Right" - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to change the plot order of series in a chart.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-series.yaml b/samples/excel/10-chart/chart-series.yaml deleted file mode 100644 index a7c73fe60..000000000 --- a/samples/excel/10-chart/chart-series.yaml +++ /dev/null @@ -1,154 +0,0 @@ -order: 10 -id: excel-chart-series -name: Series -description: Adds and deletes series in a chart. -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#add-series").click(() => tryCatch(addSeries)); - $("#delete-series").click(() => tryCatch(deleteSeries)); - - async function addSeries() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let seriesCollection = sheet.charts.getItemAt(0); - let rangeSelection = sheet.getRange("C2:C7"); - let xRangeSelection = sheet.getRange("A1:A7"); - - // Add a series. - let newSeries = seriesCollection.series.add("Qtr2"); - newSeries.setValues(rangeSelection); - newSeries.setXAxisValues(xRangeSelection); - - await context.sync(); - }); - } - - async function deleteSeries() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const seriesCollection = sheet.charts.getItemAt(0).series; - seriesCollection.load("count"); - await context.sync(); - - if (seriesCollection.count > 0) { - const series = seriesCollection.getItemAt(0); - - // Delete the first series. - series.delete(); - } - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add("A1:E1", true); - expensesTable.name = "SalesTable"; - - expensesTable.getHeaderRowRange().values = [ - ["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"] - ]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - createLineChart(context); - sheet.activate(); - - await context.sync(); - }); - } - - async function createLineChart(context: Excel.RequestContext) { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - - let dataRange = sheet.getRange("A1:B7"); - let chart = sheet.charts.add("Line", dataRange, "Auto"); - - chart.setPosition("A15", "E30"); - chart.legend.position = "Right"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to add and delete a series in a chart.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- -
- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-title-format.yaml b/samples/excel/10-chart/chart-title-format.yaml deleted file mode 100644 index 85d6674c3..000000000 --- a/samples/excel/10-chart/chart-title-format.yaml +++ /dev/null @@ -1,162 +0,0 @@ -order: 13 -id: excel-chart-title-format -name: Title format -description: Adjust a chart title's format. -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#change-title-format").click(() => tryCatch(changeTitleFormat)); - $("#change-title-substring").click(() => tryCatch(changeTitleSubstring)); - $("#change-title-orientation").click(() => tryCatch(changeTitleOrientation)); - $("#add-title-shadow").click(() => tryCatch(addTitleShadow)); - - async function changeTitleFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const title = sheet.charts.getItemAt(0).title; - title.format.fill.setSolidColor("SkyBlue"); - title.format.border.lineStyle = "Dash"; - - await context.sync(); - }); - } - - async function changeTitleSubstring() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - let chart = sheet.charts.getItemAt(0); - - // Get first seven characters of the title and color them green. - chart.title.getSubstring(0, 7).font.color = "Yellow"; - await context.sync(); - }); - } - - async function changeTitleOrientation() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const title = sheet.charts.getItemAt(0).title; - title.textOrientation = -45; - - await context.sync(); - }); - } - - async function addTitleShadow() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const title = sheet.charts.getItemAt(0).title; - title.format.font.size = 16; - title.showShadow = true; - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add("A1:E1", true); - expensesTable.name = "SalesTable"; - - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - createChart(context); - sheet.activate(); - - await context.sync(); - }); - } - - function createChart(context: Excel.RequestContext) { - let sheet = context.workbook.worksheets.getItem("Sample"); - - let dataRange = sheet.getRange("A3:E7"); - let chart = sheet.charts.add("ColumnStacked", dataRange, "Auto"); - chart.title.text = "Bicycle Parts Sales"; - chart.setPosition("A10", "H33"); - chart.legend.position = "Right"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |+ -
-

This sample shows how to adjust format a chart's title.

-
- -
-

Set up

- -
- -
-

Try it out

-

-

-

- -

- - language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/chart-trendlines.yaml b/samples/excel/10-chart/chart-trendlines.yaml deleted file mode 100644 index 4772af54c..000000000 --- a/samples/excel/10-chart/chart-trendlines.yaml +++ /dev/null @@ -1,202 +0,0 @@ -order: 14 -id: excel-chart-trendlines -name: Trendlines -description: 'Adds, gets, and formats trendlines in a chart.' -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: |+ - $("#setup").click(() => tryCatch(setup)); - $("#add-trendline").click(() => tryCatch(addTrendline)); - $("#get-trendline").click(() => tryCatch(getTrendline)); - $("#get-trendline-color").click(() => tryCatch(getTrendlineColor)); - $("#set-trendline-color").click(() => tryCatch(setTrendlineColor)); - - async function addTrendline() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let seriesCollection = sheet.charts.getItemAt(0).series; - - // Add a trendline. - seriesCollection.getItemAt(0).trendlines.add("Linear"); - - await context.sync(); - }); - } - - async function getTrendline() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let seriesCollection = sheet.charts.getItemAt(0).series; - - // Get the trendline for series 1 and load its type property. - let trendline = seriesCollection.getItemAt(0).trendlines.getItem(0); - trendline.load("type"); - - await context.sync(); - - console.log("The trendline type is:" + trendline.type); - }); - } - - async function getTrendlineColor() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let seriesCollection = sheet.charts.getItemAt(0).series; - - // Get the color of the chart trendline. - let trendline = seriesCollection.getItemAt(0).trendlines.getItem(0); - let line = trendline.format.line; - line.load("color"); - - await context.sync(); - - console.log("The trendline color is:" + line.color); - }); - } - - async function setTrendlineColor() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let seriesCollection = sheet.charts.getItemAt(0).series; - let trendline = seriesCollection.getItemAt(0).trendlines.getItem(0); - - // Set format of the trendline to a solid, red line. - let line = trendline.format.line; - line.color = '#FF0000'; - - await context.sync(); - - console.log("The trendline color has been set to:" + line.color); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add('A1:E1', true); - expensesTable.name = "SalesTable"; - - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - createChart(context); - sheet.activate(); - - await context.sync(); - }); - } - - async function createChart(context: Excel.RequestContext) { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add("ColumnClustered", dataRange, Excel.ChartSeriesBy.columns); - - chart.setPosition("A15", "F30"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Right" - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - let points = chart.series.getItemAt(0).points; - points.getItemAt(0).format.fill.setSolidColor("pink"); - points.getItemAt(1).format.fill.setSolidColor("indigo"); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - - - - language: typescript -template: - content: |- -
-

This sample shows how to add, get, and format trendlines in a chart.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- -
- -
- -
- -
-
- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/10-chart/create-doughnut-chart.yaml b/samples/excel/10-chart/create-doughnut-chart.yaml deleted file mode 100644 index c618f49fb..000000000 --- a/samples/excel/10-chart/create-doughnut-chart.yaml +++ /dev/null @@ -1,152 +0,0 @@ -order: 6 -id: excel-chart-create-doughnut-chart -name: Doughnut chart -description: Creates a doughnut chart and adjusts its size. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#create-doughnut-chart").click(() => tryCatch(createChart)); - $("#add-series").click(() => tryCatch(addSeries)); - - async function createChart() { - Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const expensesByCategoryTable = sheet.tables.getItem("ExpensesByCategoryTable"); - const dataRange = expensesByCategoryTable.getDataBodyRange(); - - let categoryChart = sheet.charts.add(Excel.ChartType.doughnut, dataRange, "Auto"); - - categoryChart.setPosition("A15", "F25"); - categoryChart.title.text = "Expenses By Category"; - categoryChart.title.format.font.size = 10; - categoryChart.title.format.font.name = "Corbel"; - categoryChart.title.format.font.color = "#41AEBD"; - categoryChart.legend.format.font.name = "Corbel"; - categoryChart.legend.format.font.size = 8; - categoryChart.legend.position = "Right"; - categoryChart.dataLabels.showPercentage = true; - categoryChart.dataLabels.format.font.size = 8; - categoryChart.dataLabels.format.font.color = "gray"; - let points = categoryChart.series.getItemAt(0).points; - points.getItemAt(0).format.fill.setSolidColor("#0C8DB9"); - points.getItemAt(1).format.fill.setSolidColor("#B1D9F7"); - points.getItemAt(2).format.fill.setSolidColor("#4C66C5"); - points.getItemAt(3).format.fill.setSolidColor("#5CC9EF"); - points.getItemAt(4).format.fill.setSolidColor("#5CCBAD"); - points.getItemAt(5).format.fill.setSolidColor("#A5E750"); - - await context.sync(); - }); - } - - async function addSeries() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let seriesCollection = sheet.charts.getItemAt(0); - let rangeSelection = sheet.getRange("C2:C7"); - let xRangeSelection = sheet.getRange("A1:A7"); - - // Add a series. - let newSeries = seriesCollection.series.add("Qtr2"); - newSeries.setValues(rangeSelection); - newSeries.setXAxisValues(xRangeSelection); - - // Set the size of the doughnut hole. - // The hole size is expressed as a percentage of the chart size. - newSeries.doughnutHoleSize = 80; - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const expensesTable = sheet.tables.add('A1:B1', true); - - expensesTable.name = "ExpensesByCategoryTable"; - expensesTable.getHeaderRowRange().values = [["Category", "Expense"]]; - expensesTable.rows.add(null, [ - ["Groceries", 5000], - ["Entertaiment", 400], - ["Education", 12000], - ["Charity", 1550], - ["Transportation", 225], - ["Other", 6005] - ]); - - sheet.getUsedRange().getEntireColumn().format.autofitColumns(); - sheet.getUsedRange().getEntireRow().format.autofitRows(); - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create a doughnut chart.

-
- -
-

Set up

- -
- -
-

Try it out

-

-

Use the chart series to adjust the doughtnut hole size.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/12-comment/comment-basics.yaml b/samples/excel/12-comment/comment-basics.yaml deleted file mode 100644 index 282e4627c..000000000 --- a/samples/excel/12-comment/comment-basics.yaml +++ /dev/null @@ -1,143 +0,0 @@ -order: 1 -id: excel-comment-basics -name: Comment basics -description: 'Adds, edits, and removes comments.' -host: EXCEL -api_set: - ExcelApi: '1.10' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#add-comment-to-selected-cell").click(() => tryCatch(addCommentToSelectedCell)); - $("#add-comment-to-cell").click(() => tryCatch(addCommentToCell)); - $("#get-comment-metadata").click(() => tryCatch(getCommentMetadata)); - $("#edit-comment").click(() => tryCatch(editComment)); - $("#delete-comment").click(() => tryCatch(deleteComment)); - - async function addCommentToSelectedCell() { - await Excel.run(async (context) => { - const selectedRange = context.workbook.getSelectedRange(); - - // Note that an InvalidArgument error will be thrown if multiple cells are selected. - context.workbook.comments.add(selectedRange, "TODO: add headers here."); - await context.sync(); - }); - } - - async function addCommentToCell() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Comments"); - - // Note that an InvalidArgument error will be thrown if multiple cells passed to `comment.add`. - sheet.comments.add("A2", "TODO: add data."); - await context.sync(); - }); - } - - async function getCommentMetadata() { - await Excel.run(async (context) => { - const comment = context.workbook.comments.getItemByCell("Comments!A2"); - comment.load(["authorEmail", "authorName", "creationDate"]); - await context.sync(); - - console.log(`${comment.creationDate.toDateString()}: ${comment.authorName} (${comment.authorEmail})`); - await context.sync(); - }); - } - - async function editComment() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Comments"); - const comment = sheet.comments.getItemAt(0); - comment.content = "PLEASE add headers here."; - await context.sync(); - }); - } - - async function deleteComment() { - await Excel.run(async (context) => { - context.workbook.comments.getItemByCell("Comments!A2").delete(); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Comments").delete(); - const sheet = context.workbook.worksheets.add("Comments"); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to add, edit, and remove comments.

-
-
-

Setup

- -
-
-

Try it out

-

To better view the comment changes, open the Comments pane by selecting Show Comments from the Review tab.

- -

- -

- -

- -

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/12-comment/comment-mentions.yaml b/samples/excel/12-comment/comment-mentions.yaml deleted file mode 100644 index 22b67a2ee..000000000 --- a/samples/excel/12-comment/comment-mentions.yaml +++ /dev/null @@ -1,102 +0,0 @@ -order: 2 -id: excel-comment-mentions -name: Comment mentions -description: Mentions someone in a comment. -host: EXCEL -api_set: - ExcelApi: '1.11' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#add-comment-with-mention").click(() => tryCatch(addCommentWithMention)); - - async function addCommentWithMention() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Comments"); - const mention = { - email: "kakri@contoso.com", - id: 0, - name: "Kate Kristensen" - }; - - // This will tag the mention's name using the '@' syntax. - // They will be notified via email. - const commentBody = { - mentions: [mention], - richContent: '' + mention.name + " - Can you take a look?" - }; - - // Note that an InvalidArgument error will be thrown if multiple cells passed to `comment.add`. - sheet.comments.add("A1", commentBody, Excel.ContentType.mention); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Comments").delete(); - const sheet = context.workbook.worksheets.add("Comments"); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to mention someone in a comment.

-
-
-

IMPORTANT: This sample is currently only supported by Excel on the web.

-

Setup

- -
-
-

Try it out

-

To better view the comment changes, open the Comments pane by selecting Show Comments from the Review tab.

-

- -

-

Change the email and name fields in the addCommentWithMention function to test the notification functionality.

-
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/12-comment/comment-replies.yaml b/samples/excel/12-comment/comment-replies.yaml deleted file mode 100644 index acade0f0a..000000000 --- a/samples/excel/12-comment/comment-replies.yaml +++ /dev/null @@ -1,164 +0,0 @@ -order: 3 -id: excel-comment-replies -name: Comment replies -description: 'Adds, edits, and removes comment replies.' -host: EXCEL -api_set: - ExcelApi: '1.10' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#add-first-comment-reply").click(() => tryCatch(addFirstCommentReply)); - $("#add-second-comment-reply").click(() => tryCatch(addSecondCommentReply)); - $("#get-comment-reply-metadata").click(() => tryCatch(getCommentReplyMetadata)); - $("#edit-comment-reply").click(() => tryCatch(editCommentReply)); - $("#delete-comment-reply").click(() => tryCatch(deleteCommentReply)); - - async function addFirstCommentReply() { - await Excel.run(async (context) => { - // Adds a reply to the first comment in this worksheet. - const sheet = context.workbook.worksheets.getItem("Comments"); - const comment = sheet.comments.getItemAt(0); - comment.replies.add("Add content to this worksheet."); - await context.sync(); - }); - } - - async function addSecondCommentReply() { - await Excel.run(async (context) => { - // Adds a reply to the first comment in this worksheet. - const sheet = context.workbook.worksheets.getItem("Comments"); - const comment = sheet.comments.getItemAt(0); - comment.replies.add("You can do it. Believe in yourself!"); - await context.sync(); - }); - } - - async function getCommentReplyMetadata() { - await Excel.run(async (context) => { - const comment = context.workbook.comments.getItemByCell("Comments!A1"); - const replyCount = comment.replies.getCount(); - // Sync to get the current number of comment replies. - await context.sync(); - - // Get the last comment reply in the comment thread. - const reply = comment.replies.getItemAt(replyCount.value - 1); - reply.load(["authorEmail", "authorName", "creationDate"]); - // Sync to load the reply metadata. - await context.sync(); - - console.log(`Latest reply: ${reply.creationDate.toDateString()}: ${reply.authorName} ${reply.authorEmail})`); - await context.sync(); - }); - } - - async function editCommentReply() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Comments"); - const comment = sheet.comments.getItemAt(0); - const reply = comment.replies.getItemAt(0); - reply.load("content"); - // Sync to load the content of the comment reply. - await context.sync(); - - // Append "Please!" to the end of the comment reply. - reply.content += " Please!"; - await context.sync(); - }); - } - - async function deleteCommentReply() { - await Excel.run(async (context) => { - // Remove the first comment reply from this worksheet's first comment. - const sheet = context.workbook.worksheets.getItem("Comments"); - const comment = sheet.comments.getItemAt(0); - comment.replies.getItemAt(0).delete(); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Comments").delete(); - const sheet = context.workbook.worksheets.add("Comments"); - - // Note that an InvalidArgument error will be thrown if multiple cells passed to `comment.add`. - sheet.comments.add("A1", "TODO: add data."); - await context.sync(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to add, edit, and remove comment replies.

-
-
-

Setup

- -
-
-

Try it out

-

To better view the comment changes, open the Comments pane by selecting Show Comments from the Review tab.

- -

- -

- -

- -

- -

-

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/12-comment/comment-resolution.yaml b/samples/excel/12-comment/comment-resolution.yaml deleted file mode 100644 index b2e4e9511..000000000 --- a/samples/excel/12-comment/comment-resolution.yaml +++ /dev/null @@ -1,113 +0,0 @@ -order: 4 -id: excel-comment-resolution -name: Comment resolution -description: Resolves and reopens a comment thread. -host: EXCEL -api_set: - ExcelApi: '1.10' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#add-comment").click(() => tryCatch(addComment)); - $("#resolve-comment").click(() => tryCatch(resolveComment)); - $("#reopen-comment").click(() => tryCatch(reopenComment)); - - async function addComment() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Comments"); - - // Note that an InvalidArgument error will be thrown if multiple cells passed to `comment.add`. - sheet.comments.add("A1", "TODO: add data."); - await context.sync(); - }); - } - - async function resolveComment() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Comments"); - sheet.comments.getItemAt(0).resolved = true; - await context.sync(); - }); - } - - async function reopenComment() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Comments"); - sheet.comments.getItemAt(0).resolved = false; - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Comments").delete(); - const sheet = context.workbook.worksheets.add("Comments"); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to resolve and reopen comment threads.

-
-
-

Setup

- -
-
-

Try it out

-

To better view the comment changes, open the Comments pane by selecting Show Comments from the Review tab.

-

- -

- -

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/14-conditional-formatting/conditional-formatting-advanced.yaml b/samples/excel/14-conditional-formatting/conditional-formatting-advanced.yaml deleted file mode 100644 index 07bcbf4c2..000000000 --- a/samples/excel/14-conditional-formatting/conditional-formatting-advanced.yaml +++ /dev/null @@ -1,238 +0,0 @@ -order: 2 -id: excel-range-conditional-formatting-advanced -name: Advanced conditional formatting -description: Applies more than one conditional format on the same range. -host: EXCEL -api_set: - ExcelApi: '1.6' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#apply-conditional-formats-default-priority").click(() => tryCatch(applyConditionalFormatsWithDefaultPriority)); - $("#apply-conditional-formats-explicit-priority").click(() => tryCatch(applyPrioritizedConditionalFormats)); - $("#apply-conditional-formats-stop-if-true").click(() => tryCatch(applyPrioritizedConditionalFormatsWithStopOnTrue)); - $("#remove-conditional-format").click(() => tryCatch(removeConditionalFormat)); - - - async function applyConditionalFormatsWithDefaultPriority() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - queueCommandsToClearAllConditionalFormats(sheet); - - const temperatureDataRange = sheet.tables.getItem("TemperatureTable").getDataBodyRange(); - - /* When the priority property of ConditionalFormat objects - is not explicitly set, they are prioritized in the order - that they are added, with zero-based numbering: 0, 1, ... - Contradictions are resolved in favor of the format with - the lower priority number. In the example below, negative - numbers will get a green background, but NOT a blue font, - because priority goes to the format that gives them a red font. - */ - - // Set low numbers to bold, dark red font. This format will - // get priority 0. - const presetFormat = temperatureDataRange.conditionalFormats - .add(Excel.ConditionalFormatType.presetCriteria); - presetFormat.preset.format.font.color = "red"; - presetFormat.preset.format.font.bold = true; - presetFormat.preset.rule = { criterion: Excel.ConditionalFormatPresetCriterion.oneStdDevBelowAverage }; - - // Set negative numbers to blue font with green background. - // This format will get priority 1. - const cellValueFormat = temperatureDataRange.conditionalFormats - .add(Excel.ConditionalFormatType.cellValue); - cellValueFormat.cellValue.format.font.color = "blue"; - cellValueFormat.cellValue.format.fill.color = "lightgreen"; - cellValueFormat.cellValue.rule = { formula1: "=0", operator: "LessThan" }; - - await context.sync(); - }); - } - - async function applyPrioritizedConditionalFormats() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - queueCommandsToClearAllConditionalFormats(sheet); - - const temperatureDataRange = sheet.tables.getItem("TemperatureTable").getDataBodyRange(); - - /* Contradictions are resolved in favor of the format with - the lower priority number. In the example below, negative - numbers will get a bold font, but NOT a red font, because - priority goes to the format that gives them a blue font. - */ - - // Set low numbers to bold, dark red font and assign priority 1. - const presetFormat = temperatureDataRange.conditionalFormats - .add(Excel.ConditionalFormatType.presetCriteria); - presetFormat.preset.format.font.color = "red"; - presetFormat.preset.format.font.bold = true; - presetFormat.preset.rule = { criterion: Excel.ConditionalFormatPresetCriterion.oneStdDevBelowAverage }; - presetFormat.priority = 1; - - // Set negative numbers to blue font with green background and - // set priority 0. - const cellValueFormat = temperatureDataRange.conditionalFormats - .add(Excel.ConditionalFormatType.cellValue); - cellValueFormat.cellValue.format.font.color = "blue"; - cellValueFormat.cellValue.format.fill.color = "lightgreen"; - cellValueFormat.cellValue.rule = { formula1: "=0", operator: "LessThan" }; - cellValueFormat.priority = 0; - - await context.sync(); - }); - } - - async function applyPrioritizedConditionalFormatsWithStopOnTrue() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - queueCommandsToClearAllConditionalFormats(sheet); - - const temperatureDataRange = sheet.tables.getItem("TemperatureTable").getDataBodyRange(); - - /* Contradictions are resolved in favor of the format with - the lower priority number. In the example below, negative - numbers will get a blue font, but NOT a red font, because - priority goes to the format that gives them a blue font. - And the font will not be bolded because setting stopIfTrue - to true on the conditional format with priority 0 blocks - all formatting for any conditional formats with a higher - priority value. - */ - - // Set low numbers to bold, dark red font and assign priority 1. - const presetFormat = temperatureDataRange.conditionalFormats - .add(Excel.ConditionalFormatType.presetCriteria); - presetFormat.preset.format.font.color = "red"; - presetFormat.preset.format.font.bold = true; - presetFormat.preset.rule = { criterion: Excel.ConditionalFormatPresetCriterion.oneStdDevBelowAverage }; - presetFormat.priority = 1; - - // Set negative numbers to blue font with green background and - // set priority 0, but set stopIfTrue to true, so none of the - // formatting of the conditional format with the higher priority - // value will apply, not even the bolding of the font. - const cellValueFormat = temperatureDataRange.conditionalFormats - .add(Excel.ConditionalFormatType.cellValue); - cellValueFormat.cellValue.format.font.color = "blue"; - cellValueFormat.cellValue.format.fill.color = "lightgreen"; - cellValueFormat.cellValue.rule = { formula1: "=0", operator: "LessThan" }; - cellValueFormat.priority = 0; - cellValueFormat.stopIfTrue = true; - - await context.sync(); - }); - } - - async function removeConditionalFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const temperatureDataRange = sheet.tables.getItem("TemperatureTable").getDataBodyRange(); - temperatureDataRange.conditionalFormats.getItemAt(0).delete(); - - await context.sync(); - }); - } - - function queueCommandsToClearAllConditionalFormats(sheet: Excel.Worksheet) { - const range = sheet.getRange(); - range.conditionalFormats.clearAll(); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - queueCommandsToCreateTemperatureTable(sheet); - sheet.activate(); - - await context.sync(); - }); - } - - function queueCommandsToCreateTemperatureTable(sheet: Excel.Worksheet) { - let temperatureTable = sheet.tables.add('A1:M1', true); - temperatureTable.name = "TemperatureTable"; - temperatureTable.getHeaderRowRange().values = [["Category", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]]; - temperatureTable.rows.add(null, [ - ["Avg High", 40, 38, 44, 45, 51, 56, 67, 72, 79, 59, 45, 41], - ["Avg Low", 34, 33, 38, 41, 45, 48, 51, 55, 54, 45, 41, 38], - ["Record High", 61, 69, 79, 83, 95, 97, 100, 101, 94, 87, 72, 66], - ["Record Low", -1, 2, 9, 24, 28, 32, 36, 39, 35, 21, 12, 4] - ]); - temperatureTable.getRange().format.autofitColumns(); - temperatureTable.getRange().format.autofitRows(); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to use priorities to work with conditional formatting of ranges when more than one conditional format - applies to some cells.

-
- -
-

Set up

- -
- -
-

Try it out

- - - - - - - - -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml b/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml deleted file mode 100644 index fbbaf5dff..000000000 --- a/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml +++ /dev/null @@ -1,355 +0,0 @@ -order: 1 -id: excel-range-conditional-formatting-basic -name: Basic conditional formatting -description: Applies common types of conditional formatting to ranges. -host: EXCEL -api_set: - ExcelApi: '1.6' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - $("#apply-color-scale-format").click(() => tryCatch(applyColorScaleFormat)); - $("#apply-preset-format").click(() => tryCatch(applyPresetFormat)); - $("#apply-databar-format").click(() => tryCatch(applyDataBarFormat)); - $("#apply-icon-set-format").click(() => tryCatch(applyIconSetFormat)); - $("#apply-text-format").click(() => tryCatch(applyTextFormat)); - $("#apply-cell-value-format").click(() => tryCatch(applyCellValueFormat)); - $("#apply-top-bottom-format").click(() => tryCatch(applyTopBottomFormat)); - $("#apply-custom-format").click(() => tryCatch(applyCustomFormat)); - $("#list-conditional-formats").click(() => tryCatch(listConditionalFormats)); - $("#clear-all-conditional-formats").click(() => tryCatch(clearAllConditionalFormats)); - - async function applyColorScaleFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B2:M5"); - const conditionalFormat = range.conditionalFormats - .add(Excel.ConditionalFormatType.colorScale); - const criteria = { - minimum: { formula: null, type: Excel.ConditionalFormatColorCriterionType.lowestValue, color: "blue" }, - midpoint: { formula: "50", type: Excel.ConditionalFormatColorCriterionType.percent, color: "yellow" }, - maximum: { formula: null, type: Excel.ConditionalFormatColorCriterionType.highestValue, color: "red" } - }; - conditionalFormat.colorScale.criteria = criteria; - - await context.sync(); - }); - } - - async function applyPresetFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B2:M5"); - const conditionalFormat = range.conditionalFormats - .add(Excel.ConditionalFormatType.presetCriteria); - conditionalFormat.preset.format.font.color = "white"; - conditionalFormat.preset.rule = { criterion: Excel.ConditionalFormatPresetCriterion.oneStdDevAboveAverage }; - - await context.sync(); - }); - } - - async function applyDataBarFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B8:E13"); - const conditionalFormat = range.conditionalFormats - .add(Excel.ConditionalFormatType.dataBar); - conditionalFormat.dataBar.barDirection = Excel.ConditionalDataBarDirection.leftToRight; - - await context.sync(); - }); - } - - async function applyIconSetFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B8:E13"); - const conditionalFormat = range.conditionalFormats - .add(Excel.ConditionalFormatType.iconSet); - const iconSetCF = conditionalFormat.iconSet; - iconSetCF.style = Excel.IconSet.threeTriangles; - - /* - The iconSetCF.criteria array is automatically prepopulated with - criterion elements whose properties have been given default settings. - You can't write to each property of a criterion directly. Instead, - replace the whole criteria object. - - With a "three*" icon set style, such as "threeTriangles", the third - element in the criteria array (criteria[2]) defines the "top" icon; - e.g., a green triangle. The second (criteria[1]) defines the "middle" - icon. The first (criteria[0]) defines the "low" icon, but it - can often be left empty as the following object shows, because every - cell that does not match the other two criteria always gets the low - icon. - */ - iconSetCF.criteria = [ - {} as any, - { - type: Excel.ConditionalFormatIconRuleType.number, - operator: Excel.ConditionalIconCriterionOperator.greaterThanOrEqual, - formula: "=700" - }, - { - type: Excel.ConditionalFormatIconRuleType.number, - operator: Excel.ConditionalIconCriterionOperator.greaterThanOrEqual, - formula: "=1000", - } - ]; - - await context.sync(); - }); - } - - async function applyTextFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B16:D18"); - const conditionalFormat = range.conditionalFormats - .add(Excel.ConditionalFormatType.containsText); - conditionalFormat.textComparison.format.font.color = "red"; - conditionalFormat.textComparison.rule = { operator: Excel.ConditionalTextOperator.contains, text: "Delayed" }; - - await context.sync(); - }); - } - - async function applyCellValueFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B21:E23"); - const conditionalFormat = range.conditionalFormats - .add(Excel.ConditionalFormatType.cellValue); - conditionalFormat.cellValue.format.font.color = "red"; - conditionalFormat.cellValue.rule = { formula1: "=0", operator: "LessThan" }; - - await context.sync(); - }); - } - - async function applyTopBottomFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B21:E23"); - const conditionalFormat = range.conditionalFormats - .add(Excel.ConditionalFormatType.topBottom); - conditionalFormat.topBottom.format.fill.color = "green" - conditionalFormat.topBottom.rule = { rank: 1, type: "TopItems"} - - await context.sync(); - }); - } - - async function applyCustomFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B8:E13"); - const conditionalFormat = range.conditionalFormats.add(Excel.ConditionalFormatType.custom); - conditionalFormat.custom.rule.formula = '=IF(B8>INDIRECT("RC[-1]",0),TRUE)'; - conditionalFormat.custom.format.font.color = "green"; - - await context.sync(); - }); - } - - async function listConditionalFormats() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const worksheetRange = sheet.getRange(); - worksheetRange.conditionalFormats.load("type"); - - await context.sync(); - - let cfRangePairs: { cf: Excel.ConditionalFormat, range: Excel.Range }[] = []; - worksheetRange.conditionalFormats.items.forEach(item => { - cfRangePairs.push({ - cf: item, - range: item.getRange().load("address") - }); - }); - - await context.sync(); - - if (cfRangePairs.length > 0) { - cfRangePairs.forEach(item => { - console.log(item.cf.type); - }); - } else { - console.log("No conditional formats applied."); - } - }); - } - - async function clearAllConditionalFormats() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange(); - range.conditionalFormats.clearAll(); - - await context.sync(); - - $(".conditional-formats").hide(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - queueCommandsToCreateTemperatureTable(sheet); - queueCommandsToCreateSalesTable(sheet); - queueCommandsToCreateProjectTable(sheet); - queueCommandsToCreateProfitLossTable(sheet); - - let format = sheet.getRange().format; - format.autofitColumns(); - format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - function queueCommandsToCreateTemperatureTable(sheet: Excel.Worksheet) { - let temperatureTable = sheet.tables.add('A1:M1', true); - temperatureTable.name = "TemperatureTable"; - temperatureTable.getHeaderRowRange().values = [["Category", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]]; - temperatureTable.rows.add(null, [ - ["Avg High", 40, 38, 44, 45, 51, 56, 67, 72, 79, 59, 45, 41], - ["Avg Low", 34, 33, 38, 41, 45, 48, 51, 55, 54, 45, 41, 38], - ["Record High", 61, 69, 79, 83, 95, 97, 100, 101, 94, 87, 72, 66], - ["Record Low", 0, 2, 9, 24, 28, 32, 36, 39, 35, 21, 12, 4] - ]); - } - - function queueCommandsToCreateSalesTable(sheet: Excel.Worksheet) { - let salesTable = sheet.tables.add('A7:E7', true); - salesTable.name = "SalesTable"; - salesTable.getHeaderRowRange().values = [["Sales Team", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - salesTable.rows.add(null, [ - ["Asian Team 1", 500, 700, 654, 234], - ["Asian Team 2", 400, 323, 276, 345], - ["Asian Team 3", 1200, 876, 845, 456], - ["Euro Team 1", 600, 500, 854, 567], - ["Euro Team 2", 5001, 2232, 4763, 678], - ["Euro Team 3", 130, 776, 104, 789] - ]); - } - - function queueCommandsToCreateProjectTable(sheet: Excel.Worksheet) { - let projectTable = sheet.tables.add('A15:D15', true); - projectTable.name = "ProjectTable"; - projectTable.getHeaderRowRange().values = [["Project", "Alpha", "Beta", "Ship"]]; - projectTable.rows.add(null, [ - ["Project 1", "Complete", "Ongoing", "On Schedule"], - ["Project 2", "Complete", "Complete", "On Schedule"], - ["Project 3", "Ongoing", "Not Started", "Delayed"] - ]); - } - - function queueCommandsToCreateProfitLossTable(sheet: Excel.Worksheet) { - let profitLossTable = sheet.tables.add('A20:E20', true); - profitLossTable.name = "ProfitLossTable"; - profitLossTable.getHeaderRowRange().values = [["Company", "2013", "2014", "2015", "2016"]]; - profitLossTable.rows.add(null, [ - ["Contoso", 256.00, -55.31, 68.90, -82.13], - ["Fabrikam", 454.00, 75.29, -88.88, 781.87], - ["Northwind", -858.21, 35.33, 49.01, 112.68] - ]); - profitLossTable.getDataBodyRange().numberFormat = [["$#,##0.00"]]; - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to apply conditional formatting to ranges.

-
- -
-

Set up

- -
- -
-

Try it out

- - - - - - - - - - - - - - - - - - - -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml b/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml deleted file mode 100644 index 906c96685..000000000 --- a/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml +++ /dev/null @@ -1,159 +0,0 @@ -order: 1 -id: excel-custom-xml-parts-create-set-get-and-delete-custom-xml-parts -name: Using custom XML parts -description: 'Creates, sets, gets, and deletes a custom XML part.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.5' -script: - content: | - $("#create-custom-xml-part").click(() => tryCatch(createCustomXmlPart)); - $("#change-custom-xml-part").click(() => tryCatch(changeCustomXmlPart)); - $("#delete-custom-xml-part").click(() => tryCatch(deleteCustomXmlPart)); - - async function createCustomXmlPart() { - await Excel.run(async (context) => { - // You must have the xmlns attribute to populate the - // CustomXml.namespaceUri property. - const originalXml = "JuanHongSally"; - const customXmlPart = context.workbook.customXmlParts.add(originalXml); - customXmlPart.load("id"); - const xmlBlob = customXmlPart.getXml(); - - await context.sync(); - - const readableXml = addLineBreaksToXML(xmlBlob.value); - $("#display-xml").text(readableXml); - - // Store the XML part's ID in a setting. - const settings = context.workbook.settings; - settings.add("ContosoReviewXmlPartId", customXmlPart.id); - - await context.sync(); - }); - } - - async function changeCustomXmlPart() { - await Excel.run(async (context) => { - const settings = context.workbook.settings; - const xmlPartIDSetting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); - await context.sync(); - - if (xmlPartIDSetting.value) { - const customXmlPart = context.workbook.customXmlParts.getItem(xmlPartIDSetting.value); - - // The setXml method does a whole-for-whole replacement - // of the entire XML. - customXmlPart.setXml("JohnHitomi"); - const xmlBlob = customXmlPart.getXml(); - await context.sync(); - - const readableXml = addLineBreaksToXML(xmlBlob.value); - $("#display-xml").text(readableXml); - await context.sync(); - } - }); - } - - async function deleteCustomXmlPart() { - await Excel.run(async (context) => { - const settings = context.workbook.settings; - const xmlPartIDSetting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); - await context.sync(); - - if (xmlPartIDSetting.value) { - let customXmlPart = context.workbook.customXmlParts.getItem(xmlPartIDSetting.value); - const xmlBlob = customXmlPart.getXml(); - customXmlPart.delete(); - customXmlPart = context.workbook.customXmlParts.getItemOrNullObject(xmlPartIDSetting.value); - - await context.sync(); - - if (customXmlPart.isNullObject) { - $("#display-xml").text(`The XML part with the id ${xmlPartIDSetting.value} has been deleted.`); - - // Delete the unneeded setting too. - xmlPartIDSetting.delete(); - } else { - const readableXml = addLineBreaksToXML(xmlBlob.value); - const strangeMessage = `This is strange. The XML part with the id ${xmlPartIDSetting.value} has not been deleted:\n${readableXml}` - $("#display-xml").text(strangeMessage); - } - - await context.sync(); - } - }); - } - - function addLineBreaksToXML(xmlBlob: string) : string { - const replaceValue = new RegExp(">"); - return xmlBlob.replace(/> <"); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |+ -
-

This sample shows how to create, set, get, and delete custom XML parts in the file.

-
- -
-

Try it out

-

Press the button to create and display Contoso's Reviewer metadata.

- -

Press the button to change the reviewers and display the new XML.

- -

Press the button to delete the XML part.

- -
- - -
-

XML part display

-
-
-
- - language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml b/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml deleted file mode 100644 index c42b996bd..000000000 --- a/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml +++ /dev/null @@ -1,145 +0,0 @@ -order: 2 -id: excel-custom-xml-parts-test-xml-for-unique-namespace -name: Unique namespaces in custom XML -description: Tests to see if there is only one XML part for a specified namespace. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.5' -script: - content: | - $("#create-custom-xml-part").click(() => tryCatch(createCustomXmlPart)); - $("#test-for-unique-namespace").click(() => tryCatch(testForUniqueNamespace)); - $("#delete-all-custom-xml-parts").click(() => tryCatch(deleteAllCustomXmlParts)); - - async function createCustomXmlPart() { - await Excel.run(async (context) => { - $("#display-xml").text(""); - - // You must have the xmlns attribute to populate the - // CustomXml.namespaceUri property. - const originalXml = "JuanHongSally"; - const customXmlPart = context.workbook.customXmlParts.add(originalXml); - const xmlBlob = customXmlPart.getXml(); - - await context.sync(); - - // Make it a bit more readable. - const readableXml = xmlBlob.value.replace(/>\n<"); - $("#display-xml").text(readableXml); - - await context.sync(); - }); - } - - async function testForUniqueNamespace() { - await Excel.run(async (context) => { - $("#display-xml").text(""); - const contosoNamespace = "http://schemas.contoso.com/review/1.0"; - const customXmlParts = context.workbook.customXmlParts; - const filteredXmlParts = customXmlParts.getByNamespace(contosoNamespace); - const numberOfPartsInNamespace = filteredXmlParts.getCount(); - - await context.sync(); - - if (numberOfPartsInNamespace.value == 1) { - const onlyXmlPartInNamespace = filteredXmlParts.getOnlyItem(); - const xmlBlob = onlyXmlPartInNamespace.getXml(); - - await context.sync(); - - // Make it a bit more readable. - const readableXml = xmlBlob.value.replace(/>\n<"); - - $("#display-xml").text(`The only XML part in the namespace ${contosoNamespace} is: - ${readableXml}`); - - } else { - console.log(`There are ${numberOfPartsInNamespace.value} XML parts with namespace ${contosoNamespace}. There should be exactly 1.`); - } - - await context.sync(); - }); - } - - async function deleteAllCustomXmlParts() { - await Excel.run(async (context) => { - $("#display-xml").text(""); - const customXmlParts = context.workbook.customXmlParts; - customXmlParts.load("items"); - - await context.sync(); - - for (let i = 0; i < customXmlParts.items.length; i++) { - customXmlParts.items[i].delete(); - } - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |+ -
-

This sample shows how to determine if there is just one XML part for a specified namespace.

-
- -
-

Try it out

-

Press the "Create XML part" button to create and display Contoso's Reviewer metadata. Press it more than once if you want to set up an error situation.

- -

Press the "Test for unique namespace" button to see if there is more than one XML part with the Contoso namespace. If there is more than one, an error is thrown.

- -

To start over, press "Delete all XML parts".

- -
- -
-

XML part display

-
-
-
- - language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/20-data-types/data-types-entity-attribution.yaml b/samples/excel/20-data-types/data-types-entity-attribution.yaml deleted file mode 100644 index 953eaee8f..000000000 --- a/samples/excel/20-data-types/data-types-entity-attribution.yaml +++ /dev/null @@ -1,234 +0,0 @@ -order: 6 -id: excel-data-types-entity-attribution -name: 'Data types: Entity value attribution properties' -description: This sample shows how to set data provider attributions on entity values in the card layout. -host: EXCEL -api_set: - ExcelApi: '1.16' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#add-entities-to-table").click(() => tryCatch(addEntitiesToTable)); - - async function addEntitiesToTable() { - // This function retrieves data for each of the existing products in the table, - // creates entity values for each of those products, and adds the entities - // to the table. - await Excel.run(async (context) => { - const productsTable = context.workbook.tables.getItem("ProductsTable"); - - // Add a new column to the table for the entity values. - productsTable.columns.getItemOrNullObject("Product").delete(); - const productColumn = productsTable.columns.add(0, null, "Product"); - - // Get product data from the table. - const dataRange = productsTable.getDataBodyRange(); - dataRange.load("values"); - - await context.sync(); - - // Set up the entities by mapping the product names to - // the sample JSON product data. - const entities = dataRange.values.map((rowValues) => { - // Get products and product properties. - const product = getProduct(rowValues[1]); - - // Create entities by combining Products Table data and JSON data. - return [makeProductEntity(rowValues[1], rowValues[2], product)]; - }); - - // Add the complete entities to the Products Table. - productColumn.getDataBodyRange().valuesAsJson = entities; - - productColumn.getRange().format.autofitColumns(); - await context.sync(); - }); - } - - // Create entities with card layout and data provider fields. - function makeProductEntity(productID: number, productName: string, product?: any) { - const entity: Excel.EntityCellValue = { - type: Excel.CellValueType.entity, - text: productName, - properties: { - "Product ID": { - type: Excel.CellValueType.string, - basicValue: productID.toString() || "" - }, - "Product Name": { - type: Excel.CellValueType.string, - basicValue: productName || "" - }, - "Quantity Per Unit": { - type: Excel.CellValueType.string, - basicValue: product.quantityPerUnit || "" - }, - // Add Unit Price as a formatted number. - "Unit Price": { - type: Excel.CellValueType.formattedNumber, - basicValue: product.unitPrice, - numberFormat: "$* #,##0.00" - } - }, - layouts: { - card: { - title: { property: "Product Name" }, - sections: [ - { - layout: "List", - properties: ["Product ID"] - }, - { - layout: "List", - title: "Quantity and price", - collapsible: true, - collapsed: false, - properties: ["Quantity Per Unit", "Unit Price"] - } - ] - } - }, - provider: { - description: product.providerName, // Name of the data provider. Displays as a tooltip when hovering over the logo. Also displays as a fallback if the source address for the image is broken. - logoSourceAddress: product.sourceAddress, // Source URL of the logo to display. - logoTargetAddress: product.targetAddress // Destination URL that the logo navigates to when clicked. - } - }; - - return entity; - } - - // Get products and product properties. - function getProduct(productID: number): any { - return products.find((p) => p.productID == productID); - } - - /** Set up Sample worksheet. */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const productsTable = sheet.tables.add("A1:C1", true /*hasHeaders*/); - productsTable.name = "ProductsTable"; - - productsTable.getHeaderRowRange().values = [["Product", "ProductID", "ProductName"]]; - - productsTable.rows.add( - null /*add at the end*/, - products.map((p) => [null, p.productID, p.productName]) - ); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - - /** Sample JSON product data. */ - const products = [ - { - productID: 1, - productName: "Chai", - quantityPerUnit: "10 boxes x 20 bags", - unitPrice: 18, - providerName: "Microsoft", - sourceAddress: "https://github.com/OfficeDev/office-js-snippets/blob/main/.github/images/microsoft-logo.png?raw=true", - targetAddress: "http://microsoft.com/" - }, - { - productID: 2, - productName: "Chang", - quantityPerUnit: "24 - 12 oz bottles", - unitPrice: 19, - providerName: "MSN", - sourceAddress: "https://github.com/OfficeDev/office-js-snippets/blob/main/.github/images/msn-logo.png?raw=true", - targetAddress: "http://msn.com/" - }, - { - productID: 3, - productName: "Aniseed Syrup", - quantityPerUnit: "12 - 550 ml bottles", - unitPrice: 10, - providerName: "Xbox", - sourceAddress: "https://github.com/OfficeDev/office-js-snippets/blob/main/.github/images/xbox-logo.png?raw=true", - targetAddress: "http://xbox.com/" - }, - { - productID: 4, - productName: "Chef Anton's Cajun Seasoning", - quantityPerUnit: "48 - 6 oz jars", - unitPrice: 22, - providerName: "Microsoft", - sourceAddress: "https://github.com/OfficeDev/office-js-snippets/blob/main/.github/images/microsoft-logo.png?raw=true", - targetAddress: "http://microsoft.com/" - }, - { - productID: 5, - productName: "Chef Anton's Gumbo Mix", - quantityPerUnit: "36 boxes", - unitPrice: 21.35, - providerName: "MSN", - sourceAddress: "https://github.com/OfficeDev/office-js-snippets/blob/main/.github/images/msn-logo.png?raw=true", - targetAddress: "http://msn.com/" - }, - ]; - language: typescript -template: - content: |- -
-

This sample shows how to set data provider attributions on entity values in the card layout. The data is aggregated from three different data providers, and three attributions are displayed.

-
-
-

Set up

- -
-
-

Try it out

- -

To see the entity value's data attribution, click the icon to the left of the title in the Product column after selecting Add entity values.

-

The data attribution appears as a logo in the bottom left corner of the entity card. Hover over the logo to see the name of the data provider. Click on the logo to visit the data provider's URL.

-
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/20-data-types/data-types-entity-icons.yaml b/samples/excel/20-data-types/data-types-entity-icons.yaml deleted file mode 100644 index 335f1e75d..000000000 --- a/samples/excel/20-data-types/data-types-entity-icons.yaml +++ /dev/null @@ -1,120 +0,0 @@ -order: 5 -id: excel-data-types-icons -name: 'Data types: Create entity icons' -description: Display all the icons available for entity data types. -host: EXCEL -api_set: - ExcelApi: '1.16' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#create-icons").click(() => tryCatch(createIcons)); - - // Retrieve the entity card icons enum. - const iconNames = Excel.EntityCompactLayoutIcons; - let icons; - - function createEntitiesWithIcons(icons): Excel.EntityCellValue[][] { - /* This method creates an entity data type for each - * icon in the `EntityCompactLayoutIcons` enum, - * and then displays the icon name with its icon. - */ - let entities = []; - icons.forEach(function(iconName, index, array) { - let icon = iconNames[iconName]; - entities.push([ - { - type: "Entity", - text: iconName, - properties: {}, - layouts: { - compact: { - icon - } - } - } - ]); - }); - return entities; - } - - async function createIcons() { - await Excel.run(async (context) => { - /* This method populates Column A in the worksheet - * with all of the entities and icons created by the - * `createEntitiesWithIcons` method. - */ - const sheet = context.workbook.worksheets.getItemOrNullObject("Sample"); - const rangeString = "A1:A" + Object.keys(iconNames).length; - const range = sheet.getRange(rangeString ); - - range.valuesAsJson = createEntitiesWithIcons(Object.keys(iconNames)); - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - // Create a new worksheet called "Sample" and activate it. - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to display all the icons available for entity data types, along with the name of each icon.

-

After creating the icons, select an icon to open the entity card for that data type. The entity cards in this sample display only the icon names.

-
-
-

Set up

- -
-
-

Run sample

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/20-data-types/data-types-entity-values.yaml b/samples/excel/20-data-types/data-types-entity-values.yaml deleted file mode 100644 index 08ea49176..000000000 --- a/samples/excel/20-data-types/data-types-entity-values.yaml +++ /dev/null @@ -1,614 +0,0 @@ -order: 3 -id: excel-data-types-entity-values -name: 'Data types: Create entity cards from data in a table' -description: 'This sample shows how to create entity cards for each row in a table. An entity is a container for data types, similar to an object in object-oriented programming.' -host: EXCEL -api_set: - ExcelApi: '1.16' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - $("#addEntitiesToTable").click(() => tryCatch(addEntitiesToTable)); - - async function addEntitiesToTable() { - // This function retrieves data for each of the existing products in the table, - // creates entity values for each of those products, and adds the entities - // to the table. - await Excel.run(async (context) => { - const productsTable = context.workbook.tables.getItem("ProductsTable"); - - // Add a new column to the table for the entity values. - productsTable.columns.getItemOrNullObject("Product").delete(); - const productColumn = productsTable.columns.add(0, null, "Product"); - - // Get product data from the table. - const dataRange = productsTable.getDataBodyRange(); - dataRange.load("values"); - - await context.sync(); - - // Set up the entities by mapping the product names to - // the sample JSON product data. - const entities = dataRange.values.map((rowValues) => { - // Get products and product properties. - const product = getProduct(rowValues[1]); - - // Get product categories and category properties. - const category = product ? getCategory(product.categoryID) : null; - - // Get product suppliers and supplier properties. - const supplier = product ? getSupplier(product.supplierID) : null; - - // Create entities by combining product, category, and supplier properties. - return [makeProductEntity(rowValues[1], rowValues[2], product, category, supplier)]; - }); - - // Add the complete entities to the Products Table. - productColumn.getDataBodyRange().valuesAsJson = entities; - - productColumn.getRange().format.autofitColumns(); - await context.sync(); - }); - } - - // Create entities from product properties. - function makeProductEntity( - productID: number, - productName: string, - product?: any, - category?: any, - supplier?: any) { - const entity: Excel.EntityCellValue = { - type: Excel.CellValueType.entity, - text: productName, - properties: { - "Product ID": { - type: Excel.CellValueType.string, - basicValue: productID.toString() || "" - }, - "Product Name": { - type: Excel.CellValueType.string, - basicValue: productName || "" - }, - "Quantity Per Unit": { - type: Excel.CellValueType.string, - basicValue: product.quantityPerUnit || "" - }, - // Add Unit Price as a formatted number. - "Unit Price": { - type: Excel.CellValueType.formattedNumber, - basicValue: product.unitPrice, - numberFormat: "$* #,##0.00" - }, - Discontinued: { - type: Excel.CellValueType.boolean, - basicValue: product.discontinued || false - } - }, - layouts: { - compact: { - icon: Excel.EntityCompactLayoutIcons.shoppingBag - }, - card: { - title: { property: "Product Name" }, - sections: [ - { - layout: "List", - properties: ["Product ID"] - }, - { - layout: "List", - title: "Quantity and price", - collapsible: true, - collapsed: false, - properties: ["Quantity Per Unit", "Unit Price"] - }, - { - layout: "List", - title: "Additional information", - collapsed: true, - properties: ["Discontinued"] - } - ] - } - } - }; - - // Add image property to the entity and then add it to the card layout. - if (product.productImage) { - entity.properties["Image"] = { - type: Excel.CellValueType.webImage, - address: product.productImage || "" - }; - entity.layouts.card.mainImage = { property: "Image" }; - } - - // Add a nested entity for the product category. - if (category) { - entity.properties["Category"] = { - type: Excel.CellValueType.entity, - text: category.categoryName, - properties: { - "Category ID": { - type: Excel.CellValueType.double, - basicValue: category.categoryID, - propertyMetadata: { - // Exclude the category ID property from the card view and auto complete. - excludeFrom: { - cardView: true, - autoComplete: true - } - } - }, - "Category Name": { - type: Excel.CellValueType.string, - basicValue: category.categoryName || "" - }, - "Description": { - type: Excel.CellValueType.string, - basicValue: category.description || "" - } - }, - layouts: { - compact: { - icon: Excel.EntityCompactLayoutIcons.branch - }, - } - }; - - // Add nested product category to the card layout. - entity.layouts.card.sections[0].properties.push("Category"); - } - - // Add a nested entity for the supplier. - if (supplier) { - entity.properties["Supplier"] = { - type: Excel.CellValueType.entity, - text: supplier.companyName, - properties: { - "Supplier ID": { - type: Excel.CellValueType.double, - basicValue: supplier.supplierID, - }, - "Company Name": { - type: Excel.CellValueType.string, - basicValue: supplier.companyName || "" - }, - "Contact Name": { - type: Excel.CellValueType.string, - basicValue: supplier.contactName || "" - }, - "Contact Title": { - type: Excel.CellValueType.string, - basicValue: supplier.contactTitle || "" - }, - }, - layouts: { - compact: { - icon: Excel.EntityCompactLayoutIcons.boxMultiple - }, - card: { - title: { property: "Company Name" }, - sections: [ - { - layout: "List", - properties: [ - "Supplier ID", - "Company Name", - "Contact Name", - "Contact Title" - ] - }, - ] - } - } - }; - - // Add nested product supplier to the card layout. - entity.layouts.card.sections[2].properties.push("Supplier"); - } - return entity; - } - - // Get products and product properties. - function getProduct(productID: number): any { - return products.find((p) => p.productID == productID); - } - - // Get product categories and category properties. - function getCategory(categoryID: number): any { - return categories.find((c) => c.categoryID == categoryID); - } - - // Get product suppliers and supplier properties. - function getSupplier(supplierID: number): any { - return suppliers.find((s) => s.supplierID == supplierID); - } - - /** Set up Sample worksheet. */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const productsTable = sheet.tables.add("A1:C1", true /*hasHeaders*/); - productsTable.name = "ProductsTable"; - - productsTable.getHeaderRowRange().values = [["Product", "ProductID", "ProductName"]]; - - productsTable.rows.add( - null /*add at the end*/, - products.map((p) => [null, p.productID, p.productName]) - ); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - - /** Sample JSON product data. */ - const products = [ - { - productID: 1, - productName: "Chai", - supplierID: 1, - categoryID: 1, - quantityPerUnit: "10 boxes x 20 bags", - unitPrice: 18, - discontinued: false, - productImage: "https://upload.wikimedia.org/wikipedia/commons/thumb/0/04/Masala_Chai.JPG/320px-Masala_Chai.JPG" - }, - { - productID: 2, - productName: "Chang", - supplierID: 1, - categoryID: 1, - quantityPerUnit: "24 - 12 oz bottles", - unitPrice: 19, - discontinued: false, - productImage: "" - }, - { - productID: 3, - productName: "Aniseed Syrup", - supplierID: 1, - categoryID: 2, - quantityPerUnit: "12 - 550 ml bottles", - unitPrice: 10, - discontinued: false, - productImage: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/81/Maltose_syrup.jpg/185px-Maltose_syrup.jpg" - }, - { - productID: 4, - productName: "Chef Anton's Cajun Seasoning", - supplierID: 2, - categoryID: 2, - quantityPerUnit: "48 - 6 oz jars", - unitPrice: 22, - discontinued: false, - productImage: - "https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Kruidenmengeling-spice.jpg/193px-Kruidenmengeling-spice.jpg" - }, - { - productID: 5, - productName: "Chef Anton's Gumbo Mix", - supplierID: 2, - categoryID: 2, - quantityPerUnit: "36 boxes", - unitPrice: 21.35, - discontinued: true, - productImage: - "https://upload.wikimedia.org/wikipedia/commons/thumb/4/45/Okra_in_a_Bowl_%28Unsplash%29.jpg/180px-Okra_in_a_Bowl_%28Unsplash%29.jpg" - }, - { - productID: 6, - productName: "Grandma's Boysenberry Spread", - supplierID: 3, - categoryID: 2, - quantityPerUnit: "12 - 8 oz jars", - unitPrice: 25, - discontinued: false, - productImage: - "https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Making_cranberry_sauce_-_in_the_jar.jpg/90px-Making_cranberry_sauce_-_in_the_jar.jpg" - }, - { - productID: 7, - productName: "Uncle Bob's Organic Dried Pears", - supplierID: 3, - categoryID: 7, - quantityPerUnit: "12 - 1 lb pkgs.", - unitPrice: 30, - discontinued: false, - productImage: "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fd/DriedPears.JPG/120px-DriedPears.JPG" - }, - { - productID: 8, - productName: "Northwoods Cranberry Sauce", - supplierID: 3, - categoryID: 2, - quantityPerUnit: "12 - 12 oz jars", - unitPrice: 40, - discontinued: false, - productImage: - "https://upload.wikimedia.org/wikipedia/commons/thumb/0/07/Making_cranberry_sauce_-_stovetop.jpg/90px-Making_cranberry_sauce_-_stovetop.jpg" - }, - { - productID: 9, - productName: "Mishi Kobe Niku", - supplierID: 4, - categoryID: 6, - quantityPerUnit: "18 - 500 g pkgs.", - unitPrice: 97, - discontinued: true, - productImage: "" - }, - { - productID: 10, - productName: "Ikura", - supplierID: 4, - categoryID: 8, - quantityPerUnit: "12 - 200 ml jars", - unitPrice: 31, - discontinued: false, - productImage: "" - }, - { - productID: 11, - productName: "Queso Cabrales", - supplierID: 5, - categoryID: 4, - quantityPerUnit: "1 kg pkg.", - unitPrice: 21, - discontinued: false, - productImage: "https://upload.wikimedia.org/wikipedia/commons/thumb/9/96/Tilsit_cheese.jpg/190px-Tilsit_cheese.jpg" - }, - { - productID: 12, - productName: "Queso Manchego La Pastora", - supplierID: 5, - categoryID: 4, - quantityPerUnit: "10 - 500 g pkgs.", - unitPrice: 38, - discontinued: false, - productImage: "https://upload.wikimedia.org/wikipedia/commons/thumb/5/59/Manchego.jpg/177px-Manchego.jpg" - }, - { - productID: 13, - productName: "Konbu", - supplierID: 6, - categoryID: 8, - quantityPerUnit: "2 kg box", - unitPrice: 6, - discontinued: false, - productImage: "" - }, - { - productID: 14, - productName: "Tofu", - supplierID: 6, - categoryID: 7, - quantityPerUnit: "40 - 100 g pkgs.", - unitPrice: 23.25, - discontinued: false, - productImage: - "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Korean.food-Dubu.gui-01.jpg/120px-Korean.food-Dubu.gui-01.jpg" - }, - { - productID: 15, - productName: "Genen Shouyu", - supplierID: 6, - categoryID: 2, - quantityPerUnit: "24 - 250 ml bottles", - unitPrice: 15.5, - discontinued: false, - productImage: "" - }, - { - productID: 16, - productName: "Pavlova", - supplierID: 7, - categoryID: 3, - quantityPerUnit: "32 - 500 g boxes", - unitPrice: 17.45, - discontinued: false, - productImage: "" - }, - { - productID: 17, - productName: "Alice Mutton", - supplierID: 7, - categoryID: 6, - quantityPerUnit: "20 - 1 kg tins", - unitPrice: 39, - discontinued: true, - productImage: "" - }, - { - productID: 18, - productName: "Carnarvon Tigers", - supplierID: 7, - categoryID: 8, - quantityPerUnit: "16 kg pkg.", - unitPrice: 62.5, - discontinued: false, - productImage: "" - }, - { - productID: 19, - productName: "Teatime Chocolate Biscuits", - supplierID: 8, - categoryID: 3, - quantityPerUnit: "10 boxes x 12 pieces", - unitPrice: 9.2, - discontinued: false, - productImage: - "https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Macau_Koi_Kei_Bakery_Almond_Biscuits_2.JPG/120px-Macau_Koi_Kei_Bakery_Almond_Biscuits_2.JPG" - }, - { - productID: 20, - productName: "Sir Rodney's Marmalade", - supplierID: 8, - categoryID: 3, - quantityPerUnit: "30 gift boxes", - unitPrice: 81, - discontinued: false, - productImage: - "https://upload.wikimedia.org/wikipedia/commons/thumb/3/30/Homemade_marmalade%2C_England.jpg/135px-Homemade_marmalade%2C_England.jpg" - } - ]; - - const categories = [ - { - categoryID: 1, - categoryName: "Beverages", - description: "Soft drinks, coffees, teas, beers, and ales" - }, - { - categoryID: 2, - categoryName: "Condiments", - description: "Sweet and savory sauces, relishes, spreads, and seasonings" - }, - { - categoryID: 3, - categoryName: "Confections", - description: "Desserts, candies, and sweet breads" - }, - { - categoryID: 4, - categoryName: "Dairy Products", - description: "Cheeses" - }, - { - categoryID: 5, - categoryName: "Grains/Cereals", - description: "Breads, crackers, pasta, and cereal" - }, - { - categoryID: 6, - categoryName: "Meat/Poultry", - description: "Prepared meats" - }, - { - categoryID: 7, - categoryName: "Produce", - description: "Dried fruit and bean curd" - }, - { - categoryID: 8, - categoryName: "Seafood", - description: "Seaweed and fish" - } - ]; - - const suppliers = [ - { - "supplierID": 1, - "companyName": "Exotic Liquids", - "contactName": "Charlotte Cooper", - "contactTitle": "Purchasing Manager", - }, - { - "supplierID": 2, - "companyName": "New Orleans Cajun Delights", - "contactName": "Shelley Burke", - "contactTitle": "Order Administrator", - }, - { - "supplierID": 3, - "companyName": "Grandma Kelly's Homestead", - "contactName": "Regina Murphy", - "contactTitle": "Sales Representative", - }, - { - "supplierID": 4, - "companyName": "Tokyo Traders", - "contactName": "Yoshi Nagase", - "contactTitle": "Marketing Manager", - "address": "9-8 Sekimai Musashino-shi", - }, - { - "supplierID": 5, - "companyName": "Cooperativa de Quesos 'Las Cabras'", - "contactName": "Antonio del Valle Saavedra", - "contactTitle": "Export Administrator", - }, - { - "supplierID": 6, - "companyName": "Mayumi's", - "contactName": "Mayumi Ohno", - "contactTitle": "Marketing Representative", - }, - { - "supplierID": 7, - "companyName": "Pavlova, Ltd.", - "contactName": "Ian Devling", - "contactTitle": "Marketing Manager", - }, - { - "supplierID": 8, - "companyName": "Specialty Biscuits, Ltd.", - "contactName": "Peter Wilson", - "contactTitle": "Sales Representative", - } - ]; - language: typescript -template: - content: |- -
-

This sample shows how to create entity values for each row in a table. An entity value is a container for data types, similar to an object in object-oriented programming.

-

In particular, this sample highlights the card layout options of an entity value, including the title, an image, collapsible sections, and nested entity values.

-
-
-

Set up

- -
-
-

Try it out

- -

To see the entity value, click the icon to the left of the title in the Product column after selecting Add entity values.

-

Note: In Excel on Mac, nested icons (such as the icons that display inside an entity card) always display as the default icon, even when another icon is selected with the API. This is a known bug.

-
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/20-data-types/data-types-error-values.yaml b/samples/excel/20-data-types/data-types-error-values.yaml deleted file mode 100644 index 898a52073..000000000 --- a/samples/excel/20-data-types/data-types-error-values.yaml +++ /dev/null @@ -1,93 +0,0 @@ -order: 4 -id: excel-data-types-error-values -name: 'Data types: Set error values' -description: This sample shows how to set a cell value to an error data type. -host: EXCEL -api_set: - ExcelApi: '1.16' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#setBusyError").click(() => tryCatch(setBusyError)); - - async function setBusyError() { - // This function sets the value of cell A1 to a #BUSY! error using data types. - await Excel.run(async (context) => { - // Retrieve the Sample worksheet and cell A1 on that sheet. - const sheet = context.workbook.worksheets.getItemOrNullObject("Sample"); - const range = sheet.getRange("A1"); - - // Get the error data type and set its type to `busy`. - const error: Excel.ErrorCellValue = { - type: Excel.CellValueType.error, - errorType: Excel.ErrorCellValueType.busy - }; - - // Set cell A1 as the busy error. - range.valuesAsJson = [[error]]; - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - // Create a new worksheet called "Sample" and activate it. - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to set the value of cell A1 to the #BUSY! error data type.

-
-
-

Set up

- -

Try it out

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/20-data-types/data-types-formatted-number.yaml b/samples/excel/20-data-types/data-types-formatted-number.yaml deleted file mode 100644 index e534b3226..000000000 --- a/samples/excel/20-data-types/data-types-formatted-number.yaml +++ /dev/null @@ -1,157 +0,0 @@ -order: 1 -id: excel-data-types-formatted-number -name: 'Data types: Formatted numbers' -description: This sample shows how to set and get data types using the formatted number properties. -host: EXCEL -api_set: - ExcelApi: '1.16' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#set-formatted-number-date").click(() => tryCatch(setFormattedNumberDate)); - $("#set-formatted-number-currency").click(() => tryCatch(setFormattedNumberCurrency)); - $("#get-formatted-number").click(() => tryCatch(getFormattedNumber)); - - async function setFormattedNumberDate() { - // This function creates a formatted number data type, - // and sets the format of this data type as a date. - await Excel.run(async (context) => { - // Get the Sample worksheet and a range on that sheet. - const sheet = context.workbook.worksheets.getItemOrNullObject("Sample"); - const dateRange = sheet.getRange("A1"); - - // Write a number formatted as a date to cell A1. - dateRange.valuesAsJson = [ - [ - { - type: Excel.CellValueType.formattedNumber, - basicValue: 32889.0, - numberFormat: "m/d/yyyy" - } - ] - ]; - await context.sync(); - }); - } - - async function setFormattedNumberCurrency() { - // This function creates a formatted number data type, - // and sets the format of this data type as a currency. - await Excel.run(async (context) => { - // Get the Sample worksheet and a range on that sheet. - const sheet = context.workbook.worksheets.getItemOrNullObject("Sample"); - const currencyRange = sheet.getRange("A2"); - - // Write a number formatted as currency to cell A2. - currencyRange.valuesAsJson = [ - [ - { - type: Excel.CellValueType.formattedNumber, - basicValue: 12.34, - numberFormat: "$* #,##0.00" - } - ] - ]; - - await context.sync(); - }); - } - - async function getFormattedNumber() { - // This function prints information about data types - // in cells A1 and A2 to the console. - await Excel.run(async (context) => { - // Get the Sample worksheet and two ranges on that sheet. - const sheet = context.workbook.worksheets.getItemOrNullObject("Sample"); - const currencyRange = sheet.getRange("A2"); - const dateRange = sheet.getRange("A1"); - - // Load the data type property of the ranges. - currencyRange.load("valuesAsJson"); - dateRange.load("valuesAsJson"); - await context.sync(); - - const currencyValues = currencyRange.valuesAsJson[0][0]; - const dateValues = dateRange.valuesAsJson[0][0]; - - // Print information about the data types to the console. - console.log("Date"); - console.log(" Type: " + dateValues.type); - console.log(" Basic value: " + dateValues.basicValue); - console.log(" Basic type: " + dateValues.basicType); - console.log(" Number format: " + (dateValues as Excel.FormattedNumberCellValue).numberFormat); - - console.log("Currency"); - console.log(" Type: " + currencyValues.type); - console.log(" Basic value: " + currencyValues.basicValue); - console.log(" Basic type: " + currencyValues.basicType); - console.log(" Number format: " + (currencyValues as Excel.FormattedNumberCellValue).numberFormat); - }); - } - - async function setup() { - await Excel.run(async (context) => { - // Create a new worksheet called "Sample" and activate it. - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to work with the formatted number data type.

-
-
-

Set up

- -

Try it out

- - - -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/20-data-types/data-types-references.yaml b/samples/excel/20-data-types/data-types-references.yaml deleted file mode 100644 index af9070c87..000000000 --- a/samples/excel/20-data-types/data-types-references.yaml +++ /dev/null @@ -1,345 +0,0 @@ -order: 7 -id: excel-data-types-references -name: 'Data types: Entity values with references' -description: 'This sample shows how to create entity values with references to other entity values. An entity value is a container for data, and this container can reference (or contain) other entities within the original entity. One entity can contain multiple additional entities.' -host: EXCEL -api_set: - ExcelApi: '1.16' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#add-entities-to-table").click(() => tryCatch(addEntitiesToTable)); - - async function addEntitiesToTable() { - // This function creates entity values with references to other entity values. - // It retrieves data for each of the employees in the table on the worksheet, - // creates entity values for each of those employees, and adds the entities - // to the table. Each employee entity references (or contains) other - // employee entities. In this scenario, the purpose of one employee - // referencing another is to show a managerial hierarchy. - await Excel.run(async (context) => { - const employeesTable = context.workbook.tables.getItem("EmployeesTable"); - - // Refresh the table column with the entity values. - employeesTable.columns.getItemOrNullObject("Employee").delete(); - const employeeColumn = employeesTable.columns.add(0, null, "Employee"); - - // Get employee data from the table. - const dataRange = employeesTable.getDataBodyRange(); - dataRange.load("values"); - await context.sync(); - - // Create the entities by mapping the employee IDs in table to the sample - // JSON employee data. - const entities = dataRange.values.map((rowValues) => { - // Get employee properties. - const employee = getEmployee(rowValues[1] /* Employee ID */); - - // Collect all the references that are needed to make the employee entity. - const references = collectReferences(employee); - - // Create employee entity from employee properties. - const employeeEntity = makeEmployeeEntity( - rowValues[2], /* Last name */ - rowValues[3], /* First name */ - employee, - references - ); - - // Collect reference values for the employee entity. - const referencedValues: any[] = [{ type: "Root" }]; - references.slice(1).forEach((id) => { - const referencedEmployee = getEmployee(id); - referencedValues.push( - makeEmployeeEntity(referencedEmployee.lastName, referencedEmployee.firstName, referencedEmployee, references) - ); - }); - employeeEntity.referencedValues = referencedValues; - - return [employeeEntity]; - }); - - // Add the complete entities to the Employees Table. - employeeColumn.getDataBodyRange().valuesAsJson = entities; - employeeColumn.getRange().format.autofitColumns(); - await context.sync(); - }); - } - - // Helper function to collect all the references for the employee entity. - // A reference means one entity contains another entity. - function collectReferences(employee) { - const references: number[] = []; - collectManagerReferences(employee, references); - return references; - } - - // Helper function to collect manager and direct report references for each employee entity. - function collectManagerReferences(employee, references: number[]) { - // Confirm references haven't already been collected for this employee. - if (references.indexOf(employee.employeeID) >= 0) { - return; - } - - // Record the reference for the employee. - ensureReferenceExist(references, employee.employeeID); - - // Record the reference for the manager, if the employee has a manager. - if (employee.reportsTo != null) { - // Get the manager. - const manager = getEmployee(employee.reportsTo); - // Collect references for the manager. - collectManagerReferences(manager, references); - } - - // Collect references for each of the direct reports of the employee, if any. - const directReports = employee.directReports || getDirectReports(employee.employeeID); - if (directReports.length > 0) { - directReports.forEach((direct) => collectManagerReferences(direct, references)); - } - } - - // Helper function to check whether a specific reference ID exists in a list of IDs. - // If the ID doesn't exist, add it to the list. - function ensureReferenceExist(list: number[], id: number) { - if (list.indexOf(id) < 0) { - list.push(id); - } - } - - // Create entities from employee properties. - function makeEmployeeEntity(lastName: string, firstName: string, employee: any, references: number[]): Excel.EntityCellValue { - const entity: Excel.EntityCellValue = { - type: Excel.CellValueType.entity, - text: `${firstName} ${lastName}`, - properties: { - "Employee ID": { - type: Excel.CellValueType.string, - basicValue: employee.employeeID.toString() - }, - "Last Name": { - type: Excel.CellValueType.string, - basicValue: lastName - }, - "First Name": { - type: Excel.CellValueType.string, - basicValue: firstName - }, - Name: { - type: Excel.CellValueType.string, - basicValue: `${firstName} ${lastName}` - }, - Title: { - type: Excel.CellValueType.string, - basicValue: employee.title - } - }, - layouts: { - card: { - title: { property: "Name" }, - sections: [ - { - layout: "List", - properties: ["Employee ID", "First Name", "Last Name", "Title"] - } - ] - } - } - }; - - // Add manager reference, if the employee has a manager. - if (employee.reportsTo != null) { - entity.properties["Manager"] = { - type: "Reference", - reference: references.indexOf(employee.reportsTo) - }; - entity.layouts.card.sections[0].properties.push("Manager"); - } - - // Add references for direct reports, if any. - if (employee.directReports.length > 0) { - entity.properties["Direct Reports"] = { - type: Excel.CellValueType.array, - elements: employee.directReports.map((direct) => { - return [ - { - type: "Reference", - reference: references.indexOf(direct.employeeID) - } - ]; - }), - }; - entity.layouts.card.sections[0].properties.push("Direct Reports"); - } - - return entity; - } - - // Get employee properties. - function getEmployee(employeeID: number): any { - // Find the employee in the sample data. - const employee = employees.find((e) => e.employeeID === employeeID); - - // Add direct reports for the employee. - employee["directReports"] = getDirectReports(employeeID); - return employee; - } - - // Get direct reports of employee. - function getDirectReports(employeeID: number): any { - return employees.filter((e) => e.reportsTo === employeeID); - } - - /** Set up Sample worksheet with a table of employee data. */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const employeesTable = sheet.tables.add("A1:D1", true /* hasHeaders */); - employeesTable.name = "EmployeesTable"; - - employeesTable.getHeaderRowRange().values = [["Employee", "EmployeeID", "LastName", "FirstName"]]; - - employeesTable.rows.add( - null /* Add at the end. */, - employees.map((e) => [null, e.employeeID, e.lastName, e.firstName]) - ); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - - /** Sample JSON employee data. */ - const employees = [ - { - employeeID: 1, - lastName: "Davolio", - firstName: "Nancy", - title: "Vice President, Sales", - reportsTo: null - }, - { - employeeID: 2, - lastName: "Fuller", - firstName: "Andrew", - title: "Sales Representative", - reportsTo: 1 - }, - { - employeeID: 3, - lastName: "Leverling", - firstName: "Janet", - title: "Sales Representative", - reportsTo: 4 - }, - { - employeeID: 4, - lastName: "Peacock", - firstName: "Margaret", - title: "Sales Manager", - reportsTo: 1 - }, - { - employeeID: 5, - lastName: "Buchanan", - firstName: "Steven", - title: "Sales Representative", - reportsTo: 4 - }, - { - employeeID: 6, - lastName: "Suyama", - firstName: "Michael", - title: "Sales Representative", - reportsTo: 4 - }, - { - employeeID: 7, - lastName: "King", - firstName: "Robert", - title: "Sales Representative", - reportsTo: 4 - }, - { - employeeID: 8, - lastName: "Callahan", - firstName: "Laura", - title: "Inside Sales Coordinator", - reportsTo: 1 - }, - { - employeeID: 9, - lastName: "Dodsworth", - firstName: "Anne", - title: "Sales Representative", - reportsTo: 4 - } - ]; - language: typescript -template: - content: | -
-

This sample shows how to create entity values with references to other entity values. An entity value is a container for data, and this container can reference (or contain) other entities within the original entity. One entity can contain multiple additional entities.

-
-
-

Set up

- -
-
-

Try it out

-

To see referenced entities within an entity, take the following steps.

-
    -
  1. Select Add entity values to add entity values to the table. -

  2. -
  3. Open the Andrew Fuller entity card by selecting the icon to the left of this name in the Employee column.
  4. -
  5. In the Andrew Fuller entity card, select the Manager field. This opens the referenced entity for Nancy Davolio.
  6. -
  7. The referenced Nancy Davolio entity itself contains multiple referenced entities in the Direct Reports field. Select the Direct Reports field to explore the referenced entities for all the employees that report to Nancy Davolio.
  8. -
  9. To navigate back to the original Andrew Fuller entity, select the Back arrow in the top left corner of the entity card.
  10. -
-

You can also use the Extract to grid button in the card modal window, to the right of the Manager or Direct Reports fields, to add the referenced entities to the table in new columns.

-
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/20-data-types/data-types-web-image.yaml b/samples/excel/20-data-types/data-types-web-image.yaml deleted file mode 100644 index 5cdf97001..000000000 --- a/samples/excel/20-data-types/data-types-web-image.yaml +++ /dev/null @@ -1,200 +0,0 @@ -order: 2 -id: excel-data-types-web-image -name: 'Data types: Web images' -description: This sample shows how to set and get web images in a worksheet using data types. -host: EXCEL -api_set: - ExcelApi: '1.16' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#insert-image").click(() => tryCatch(insertImage)); - $("#retrieve-image-info").click(() => tryCatch(retrieveImageInfo)); - $("#open-image").click(() => tryCatch(openImage)); - $("#clear-form").click(() => tryCatch(clearForm)); - - async function insertImage() { - // This function inserts a web image into the currently selected cell. - await Excel.run(async (context) => { - // Retrieve image data from the task pane and then clear the input fields. - const imageUrl = $("#url").val() as string; - const imageAltText = $("#alt-text").val() as string; - clearForm(); - - // Load the active cell. - const activeCell = context.workbook.getActiveCell(); - activeCell.load(); - await context.sync(); - - if (!imageUrl) { - console.log("Please enter an image URL."); - return; - } - - // Create a web image object and assign the image details. - const webImage: Excel.WebImageCellValue = { - type: "WebImage", /* The string equivalent of `Excel.CellValueType.webImage`. */ - address: imageUrl, - altText: imageAltText - }; - - // Insert web image into the active cell. - activeCell.valuesAsJson = [[webImage]]; - - await context.sync(); - }); - } - - async function retrieveImageInfo() { - // This function retrieves image data from a selected cell and displays it in the existing input fields in the task pane. - await Excel.run(async (context) => { - // Load the active cell information. - const activeCell = context.workbook.getActiveCell(); - activeCell.load("valuesAsJson"); - await context.sync(); - - // Get image data from the active cell. - const values = activeCell.valuesAsJson; - const webImageData = values[0][0] as Excel.WebImageCellValue; - const webImageUrl = webImageData.address; - const webImageAltText = webImageData.altText; - - if (!webImageUrl) { - console.log("The selected cell is missing an image URL. Make sure to select a cell that contains an image."); - return; - } - - // Assign image data to corresponding input fields in the task pane. - $("#url").val(webImageUrl); - $("#alt-text").val(webImageAltText); - }); - } - - async function openImage() { - // This function retrieves the image URL from the selected cell and opens that image in a new browser tab. - await Excel.run(async (context) => { - // Load the active cell information. - const activeCell = context.workbook.getActiveCell(); - activeCell.load("valuesAsJson"); - await context.sync(); - - // Get image URL from the active cell. - const values = activeCell.valuesAsJson; - const webImageData = values[0][0] as Excel.WebImageCellValue; - const webImageUrl = webImageData.address; - - if (!webImageUrl) { - console.log("The selected cell is missing an image URL. Select a cell that contains an image."); - return; - } - - // Open the image URL in a new browser tab. - const tab = window.open(webImageData.address, "_blank"); - }); - } - - async function clearForm() { - // Clear the input fields in the task pane. - $("#url").val(""); - $("#alt-text").val(""); - } - - async function setup() { - await Excel.run(async (context) => { - // Create a new worksheet called "Sample" and activate it. - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to work with the web image data type. Insert an image into the selected cell and then - retrieve information about that image.

-
- -
-

Set up

-

Add a new worksheet and then enter the URL and alt text for an image of your choice.

- - -
- - -
- -
-

Try it out

-

Select the cell you want to insert the web image into, and then select the Insert image button.

- - -

Select the cell containing the web image that you want to view the details of, and then select the Retrieve image details button. The image details will display here in the task pane, in the preceding Image URL and Alt text fields.

- - -

Select the cell with the image you want to view and then select the Open image in browser button. The image will open in a new web browser tab.

- - -

Clear the Image URL and Alt text fields in the task pane.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - - label { - display: inline-block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - - input { - display: inline-block; - padding: 5px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/22-data-validation/data-validation.yaml b/samples/excel/22-data-validation/data-validation.yaml deleted file mode 100644 index cabcc1092..000000000 --- a/samples/excel/22-data-validation/data-validation.yaml +++ /dev/null @@ -1,192 +0,0 @@ -order: 1 -id: excel-data-validation -name: Data validation -description: 'Sets data validation rules on ranges, prompts users to enter valid data, and displays messages when invalid data is entered.' -host: EXCEL -api_set: - ExcelApi: '1.8' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#positive-number").click(() => tryCatch(addPositiveNumberRequirement)); - $("#require-approved-location").click(() => tryCatch(requireApprovedName)); - $("#comment-redundancy").click(() => tryCatch(warnAboutCommentRedundancy)); - - async function addPositiveNumberRequirement() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Decision"); - const rankingRange = sheet.tables.getItem("NameOptionsTable").columns.getItem("Ranking").getDataBodyRange(); - - // When you are developing, it is a good practice to - // clear the dataValidation object with each run of your code. - rankingRange.dataValidation.clear(); - - let greaterThanZeroRule = { - wholeNumber: { - formula1: 0, - operator: Excel.DataValidationOperator.greaterThan - } - }; - rankingRange.dataValidation.rule = greaterThanZeroRule; - - rankingRange.dataValidation.prompt = { - message: "Please enter a positive number.", - showPrompt: true, - title: "Positive numbers only." - }; - - rankingRange.dataValidation.errorAlert = { - message: "Sorry, only positive numbers are allowed", - showAlert: true, - style: "Stop", - title: "Negative Number Entered" - }; - - await context.sync(); - }); - } - - async function requireApprovedName() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Decision"); - const nameRange = - sheet.tables.getItem("NameOptionsTable").columns.getItem("Baby Name").getDataBodyRange(); - - // When you are developing, it is a good practice to - // clear the dataValidation object with each run of your code. - nameRange.dataValidation.clear(); - - const nameSourceRange = context.workbook.worksheets.getItem("Names").getRange("A1:A3"); - - let approvedListRule = { - list: { - inCellDropDown: true, - source: nameSourceRange - } - }; - nameRange.dataValidation.rule = approvedListRule; - - await context.sync(); - }); - } - - async function warnAboutCommentRedundancy() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Decision"); - const commentsRange = - sheet.tables.getItem("NameOptionsTable").columns.getItem("Comments").getDataBodyRange(); - - // When you are developing, it is a good practice to - // clear the dataValidation object with each run of your code. - commentsRange.dataValidation.clear(); - - // If the value of A2 is contained in the value of C2, then - // SEARCH(A2,C2) returns the number where it begins. Otherwise, - // it does not return a number. - let redundantStringRule = { - custom: { - formula: "=NOT(ISNUMBER(SEARCH(A2,C2)))" - } - }; - commentsRange.dataValidation.rule = redundantStringRule; - commentsRange.dataValidation.errorAlert = { - message: "It is redundant to include the baby name in the comment.", - showAlert: true, - style: "Information", - title: "Baby Name in Comment" - }; - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Decision").delete(); - const decisionSheet = context.workbook.worksheets.add("Decision"); - - const optionsTable = decisionSheet.tables.add("A1:C4", true /*hasHeaders*/); - optionsTable.name = "NameOptionsTable"; - optionsTable.showBandedRows = false; - - optionsTable.getHeaderRowRange().values = [["Baby Name", "Ranking", "Comments"]]; - - decisionSheet.getUsedRange().format.autofitColumns(); - decisionSheet.getUsedRange().format.autofitRows(); - - // The names that will be allowed in the Baby Name column are - // listed in a range on the Names sheet. - context.workbook.worksheets.getItemOrNullObject("Names").delete(); - const namesSheet = context.workbook.worksheets.add("Names"); - - namesSheet.getRange("A1:A3").values = [["Sue"], ["Ricky"], ["Liz"]]; - decisionSheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to apply data validation to cells.

-
- -
-

Set up

- -
- -
-

Try it out

-

Press Require approved name and then click on a cell in the Baby Name column and use the drop down to enter an approved value.

- -

Press Require positive numbers and then click on a cell in the Ranking column. Note the prompt. Try to set the value to a negative number and note the error message.

- -

Press Warn about comment redundancy and then click on a cell in the Comments column and enter a comment that includes the baby name for the same row. Note the informational message that pops up.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/26-document/custom-properties.yaml b/samples/excel/26-document/custom-properties.yaml deleted file mode 100644 index a18cec122..000000000 --- a/samples/excel/26-document/custom-properties.yaml +++ /dev/null @@ -1,141 +0,0 @@ -order: 3 -id: excel-document-custom-properties -name: Custom properties -description: Gets and sets custom properties at the document and worksheet levels. -host: EXCEL -api_set: - ExcelAPI: '1.12' -script: - content: | - $("#set-custom-doc-property").click(() => tryCatch(setCustomDocProperty)); $("#get-custom-doc-properties").click(() => tryCatch(getCustomDocProperties)); $("#set-custom-worksheet-property").click(() => tryCatch(setCustomWorksheetProperty)); $("#get-custom-worksheet-properties").click(() => tryCatch(getCustomWorksheetProperties)); - - /* To learn how to view document properties in the UI, - * see https://support.office.com/article/View-or-change-the-properties-for-an-Office-file-21D604C2-481E-4379-8E54-1DD4622C6B75 - */ - - async function setCustomDocProperty() { - await Excel.run(async (context) => { - // Get the key/value pair from the task pane. - const userKey = $("#key").text(); - const userValue = $("#value").text(); - - // Add the custom property. - const customDocProperties = context.workbook.properties.custom; - customDocProperties.add(userKey, userValue); - - await context.sync(); - - console.log(`Successfully set custom document property ${userKey}:${userValue}.`); - }); - } - - async function getCustomDocProperties() { - await Excel.run(async (context) => { - // Load the keys and values of all custom properties. - const customDocProperties = context.workbook.properties.custom; - customDocProperties.load(["key", "value"]); - await context.sync(); - - // Log each custom property to the console. - // Note that your document may have more properties than those you have set using this snippet. - customDocProperties.items.forEach((property) => { - console.log(`${property.key}:${property.value}`); - }); - }); - } - - async function setCustomWorksheetProperty() { - await Excel.run(async (context) => { - // Get the key/value pair from the task pane. - const userKey = $("#key").text(); - const userValue = $("#value").text(); - - // Add the custom property. - const customWorksheetProperties = context.workbook.worksheets.getActiveWorksheet().customProperties; - customWorksheetProperties.add(userKey, userValue); - - await context.sync(); - - console.log(`Successfully set custom worksheet property ${userKey}:${userValue}.`); - }); - } - - async function getCustomWorksheetProperties() { - await Excel.run(async (context) => { - // Load the keys and values of all custom properties in the current worksheet. - const customWorksheetProperties = context.workbook.worksheets.getActiveWorksheet().customProperties; - customWorksheetProperties.load(["key", "value"]); - await context.sync(); - - // Log each custom property to the console. - // Note that your document may have more properties than those you have set using this snippet. - customWorksheetProperties.items.forEach((property) => { - console.log(`${property.key}:${property.value}`); - }); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to set and get custom properties at both the document level and the worksheet level.

-
- -
-

Enter the key/value pairs for your custom properties.

-

Key:

-

Value:

- -

- -

- -

- -

- -

- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/26-document/get-file-in-slices-async.yaml b/samples/excel/26-document/get-file-in-slices-async.yaml deleted file mode 100644 index 514a925c5..000000000 --- a/samples/excel/26-document/get-file-in-slices-async.yaml +++ /dev/null @@ -1,218 +0,0 @@ -order: 1 -id: excel-document-get-file-in-slices-async -name: Get file using slicing -description: Uses slicing to get the byte array and Base64-encoded string that represent the current document. -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - $("#get-file").click(() => tryCatch(getCurrentFile)); - $("#new-workbook-from-file").click(() => tryCatch(newWorkbookFromFile)); - - function getCurrentFile() { - const sliceSize = 4096; /*Bytes*/ - - // This snippet specifies a small slice size to show how the getFileAsync() method uses slices. - Office.context.document.getFileAsync(Office.FileType.Compressed, { sliceSize: sliceSize }, - function (result) { - if (result.status === Office.AsyncResultStatus.Failed) { - return onError(result.error); - } - - // Result.value is the File object. - getFileContents(result.value, onSuccess, onError); - }); - - function onError(error: Office.Error): void { - console.error(error); - } - - function onSuccess(byteArray: number[]) { - // Now that all of the file content is stored in the "data" parameter, - // you can do something with it, such as print the file, store the file in a database, etc. - console.log("Received the full contents of the file."); - - let base64string = base64js.fromByteArray(byteArray); - $('#file-contents').val(base64string).show(); - - console.log("The Base64-encoded string that represents the current document has been written to the text box. To validate the string, use the \"Create workbook from string\" button."); - } - } - - function getFileContents( - file: Office.File, - onSuccess: (byteArray: number[]) => void, - onError: (error: Office.Error) => void - ) { - let expectedSliceCount = file.sliceCount; - let fileSlices: Array> = []; - - console.log("Current file size in bytes: " + file.size); - console.log("Number of file slices: " + file.sliceCount); - - getFileContentsHelper(); - - function getFileContentsHelper() { - file.getSliceAsync(fileSlices.length, function (result) { - if (result.status === Office.AsyncResultStatus.Failed) { - file.closeAsync(); - return onError(result.error); - } - - // Got one slice, store it in a temporary array. - fileSlices.push(result.value.data); - - if (fileSlices.length == expectedSliceCount) { - console.log("All slices have been received."); - file.closeAsync(); - - let array = []; - fileSlices.forEach(slice => { - array = array.concat(slice); - }); - - onSuccess(array); - } else { - getFileContentsHelper(); - } - }); - } - } - - async function newWorkbookFromFile() { - await Excel.createWorkbook($('#file-contents').text()).catch(function (error) { - console.error(error); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add('A1:E1', true); - expensesTable.name = "SalesTable"; - - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - createChart(context); - sheet.activate(); - - await context.sync(); - }); - } - - async function createChart(context: Excel.RequestContext) { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add("ColumnClustered", dataRange, Excel.ChartSeriesBy.columns); - - chart.setPosition("A15", "F30"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Right" - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - let points = chart.series.getItemAt(0).points; - points.getItemAt(0).format.fill.setSolidColor("pink"); - points.getItemAt(1).format.fill.setSolidColor("indigo"); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - - declare namespace base64js { - /** Takes a byte array and returns a Base64 string - * Imported from https://www.npmjs.com/package/base64-js package. */ - function fromByteArray(array: number[]): string; - } - language: typescript -template: - content: | -
-

This sample shows how to get the Base64-encoded string that represents the current document. It uses the getFileAsync() method to read the file in slices and then joins all slices back together to form the complete file.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- -
- -
-

Create a new workbook

- -
-
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - - #file-contents { - display: none; - width: 100%; - height: 10em; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 - - https://unpkg.com/base64-js@1.2.1/base64js.min.js diff --git a/samples/excel/26-document/properties.yaml b/samples/excel/26-document/properties.yaml deleted file mode 100644 index 3e34550fb..000000000 --- a/samples/excel/26-document/properties.yaml +++ /dev/null @@ -1,187 +0,0 @@ -order: 2 -id: excel-document-properties -name: Properties -description: Gets and sets document properties. -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#set-doc-properties").click(() => tryCatch(setDocProperties)); - $("#get-doc-properties").click(() => tryCatch(getDocProperties)); - $("#set-custom-doc-properties").click(() => tryCatch(setCustomDocProperties)); - $("#get-custom-doc-properties").click(() => tryCatch(getCustomDocProperties)); - $("#get-count-custom-doc-properties").click(() => tryCatch(getCountCustomDocProperties)); - - async function setDocProperties() { - await Excel.run(async (context) => { - let titleValue = "Excel document properties API"; - let subjectValue = "Set and get document properties"; - let keywordsValue = "Set and get operations"; - let commentsValue = "This is an Excel document properties API code sample"; - let categoryValue = "Office Add-ins"; - let managerValue = "John"; - let companyValue = "Microsoft"; - - let docProperties = context.workbook.properties; - - // Set the writeable document properties. - docProperties.title = titleValue; - docProperties.subject = subjectValue; - docProperties.keywords = keywordsValue; - docProperties.comments = commentsValue; - docProperties.category = categoryValue; - docProperties.manager = managerValue; - docProperties.company = companyValue; - - await context.sync(); - - console.log("Set the following document properties: title, subject, keywords, comments, category, manager, company."); - }); - } - - async function getDocProperties() { - await Excel.run(async (context) => { - let docProperties = context.workbook.properties; - - // Load a combination of read-only - // and writeable document properties. - docProperties.load("author, lastAuthor, revisionNumber, title, subject, keywords, comments, category, manager, company, creationDate"); - - await context.sync(); - - // Write the document properties to the console. - // To learn how to view document properties in the UI, - // see https://support.office.com/article/View-or-change-the-properties-for-an-Office-file-21D604C2-481E-4379-8E54-1DD4622C6B75 - console.log("Author: " + docProperties.author); - console.log("Last author : " + docProperties.lastAuthor); - console.log("Revision number: " + docProperties.revisionNumber); - console.log("Title: " + docProperties.title); - console.log("Subject: " + docProperties.subject); - console.log("Keywords: " + docProperties.keywords); - console.log("Comments: " + docProperties.comments); - console.log("Category: " + docProperties.category); - console.log("Manager: " + docProperties.manager); - console.log("Company: " + docProperties.company); - console.log("Workbook creation date: " + docProperties.creationDate.toDateString()); - }); - } - - async function setCustomDocProperties() { - await Excel.run(async (context) => { - let customDocProperties = context.workbook.properties.custom; - - // Add custom document properties. - customDocProperties.add("Introduction", "Hello"); - customDocProperties.add("Integer", "12"); - - await context.sync(); - - console.log("Successfully set custom document properties."); - }); - } - - async function getCustomDocProperties() { - await Excel.run(async (context) => { - let customDocProperties = context.workbook.properties.custom; - let customProperty = customDocProperties.getItem("Introduction"); - customProperty.load("key, value"); - - await context.sync(); - - // Write the custom document properties to the console. - // To learn how to view document properties in the UI, - // see https://support.office.com/article/View-or-change-the-properties-for-an-Office-file-21D604C2-481E-4379-8E54-1DD4622C6B75 - console.log("Custom key : " + customProperty.key); - console.log("Custom value : " + customProperty.value); - - }); - } - - async function getCountCustomDocProperties() { - await Excel.run(async (context) => { - - let customDocProperties = context.workbook.properties.custom; - - let count = customDocProperties.getCount(); - - await context.sync(); - - console.log("Count of custom document properties :" + count.value); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |+ -
-

This sample shows how to set and get document properties.

-
- -
-

Try it out

- -
- -
- -
- -
- -
- -
- -
- -
- -
- - language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/30-events/data-change-event-details.yaml b/samples/excel/30-events/data-change-event-details.yaml deleted file mode 100644 index b85591d2d..000000000 --- a/samples/excel/30-events/data-change-event-details.yaml +++ /dev/null @@ -1,116 +0,0 @@ -order: 6 -id: excel-data-change-event-details -name: Data changed event details -description: Uses the onChanged event of a table to determine the specifics of changes. -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#register-handler").click(() => tryCatch(registerChangeEventHandler)); - - async function registerChangeEventHandler() { - await Excel.run(async (context) => { - const expensesTable = context.workbook.worksheets.getActiveWorksheet().tables.getItem("ExpensesTable"); - - // This event fires when a user edits a cell in the table. - expensesTable.onChanged.add(onTableChanged); - await context.sync(); - - console.log("Added onChanged handler"); - }); - } - - async function onTableChanged(eventArgs: Excel.TableChangedEventArgs) { - await Excel.run(async (context) => { - const details = eventArgs.details; - const address = eventArgs.address; - - console.log(`Change at ${address}: was ${details.valueBefore}(${details.valueTypeBefore}),` - + ` now is ${details.valueAfter}(${details.valueTypeAfter})`); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const expensesTable = sheet.tables.add("A1:D1", true /*hasHeaders*/); - expensesTable.name = "ExpensesTable"; - - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - - expensesTable.rows.add(null /*add at the end*/, [ - ["4/1/2017", "The Phone Company", "Communications", "$120"], - ["4/2/2017", "Northwind Electric Cars", "Transportation", "$142"], - ["4/5/2017", "Best For You Organics Company", "Groceries", "$27"], - ["4/10/2017", "Coho Vineyard", "Restaurant", "$33"], - ["4/11/2017", "Bellows College", "Education", "$350"], - ["4/15/2017", "Trey Research", "Other", "$135"], - ["4/15/2017", "Best For You Organics Company", "Groceries", "$97"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to use table changed events.

-
- -
-

Setup

- -
-
-

Try it out

- -

-

Edit individual cells in the table to trigger the event and see the console output.

-
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/30-events/data-changed.yaml b/samples/excel/30-events/data-changed.yaml deleted file mode 100644 index f70d88e7a..000000000 --- a/samples/excel/30-events/data-changed.yaml +++ /dev/null @@ -1,120 +0,0 @@ -order: 5 -id: excel-events-data-changed -name: Data changed event -description: Registers an event handler that runs when data is changed. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#register-data-changed-handler").click(() => tryCatch(registerDataChangedHandler)); - - async function registerDataChangedHandler() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const salesByQuarterBinding = context.workbook.bindings.add(salesTable.getRange(), "Table", "SalesByQuarter"); - salesByQuarterBinding.onDataChanged.add(onSalesDataChanged); - - console.log("The data changed handler is registered."); - - await context.sync(); - }); - } - - async function onSalesDataChanged(eventArgs: Excel.BindingDataChangedEventArgs) { - await Excel.run(async (context) => { - console.log("Data was changed with binding " + eventArgs.binding.id); - - // Get the name of the table that's changed. - const table: Excel.Table = context.workbook.bindings.getItem(eventArgs.binding.id).getTable(); - table.load("name"); - - await context.sync(); - console.log("Name of the changed table: " + table.name); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let salesTable = sheet.tables.add('A1:E1', true); - salesTable.name = "SalesTable"; - salesTable.getHeaderRowRange().values = [["Sales Team", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - salesTable.rows.add(null, [ - ["London", 500, 700, 654, null ], - ["Hong Kong", 400, 323, 276, null ], - ["New York", 1200, 876, 845, null ], - ["Port-of-Spain", 600, 500, 854, null ], - ["Nairobi", 5001, 2232, 4763, null ] - ]); - - salesTable.getRange().format.autofitColumns(); - salesTable.getRange().format.autofitRows(); - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to register and use a handler for the data-changed event.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/30-events/event-column-and-row-sort.yaml b/samples/excel/30-events/event-column-and-row-sort.yaml deleted file mode 100644 index bc2f39981..000000000 --- a/samples/excel/30-events/event-column-and-row-sort.yaml +++ /dev/null @@ -1,201 +0,0 @@ -order: 3 -id: excel-event-column-and-row-sort -name: Column and row sort events -description: Registers event handlers that run when column or row sorting events occur in the current worksheet. -host: EXCEL -api_set: - ExcelApi: '1.10' -script: - content: | - $("#setup").click(() => tryCatch(setup)); $("#register-sort-handlers").click(() => tryCatch(registerSortHandlers)); $("#register-row-sort-handler").click(() => tryCatch(registerRowSortHandler)); $("#register-column-sort-handler").click(() => tryCatch(registerColumnSortHandler)); $("#sort-q1").click(() => tryCatch(sortTopToBottom, "Q1")); $("#sort-q3").click(() => tryCatch(sortTopToBottom, "Q3")); $("#sort-apples").click(() => tryCatch(sortLeftToRight, "Apples")); $("#sort-quinces").click(() => tryCatch(sortLeftToRight, "Quinces")); - async function registerSortHandlers() { - registerRowSortHandler(); - registerColumnSortHandler(); - } - async function registerRowSortHandler() { - await Excel.run(async (context) => { - console.log("Adding row handler"); - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // This will fire whenever a row has been moved as the result of a sort action. - sheet.onRowSorted.add((event) => { - return Excel.run((context) => { - console.log("Row sorted: " + event.address); - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // Clear formatting for section, then highlight the sorted area. - sheet.getRange("A1:E5").format.fill.clear(); - if (event.address !== "") { - sheet.getRanges(event.address).format.fill.color = "yellow"; - } - - return context.sync(); - }); - }); - }); - } - - async function registerColumnSortHandler() { - await Excel.run(async (context) => { - console.log("Adding column handler"); - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // This will fire whenever a column has been moved as the result of a sort action. - sheet.onColumnSorted.add((event) => { - return Excel.run((context) => { - console.log("Column sorted: " + event.address); - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // Clear formatting for section, then highlight the sorted area. - sheet.getRange("A1:E5").format.fill.clear(); - if (event.address !== "") { - sheet.getRanges(event.address).format.fill.color = "yellow"; - } - - return context.sync(); - }); - }); - }); - } - - async function sortTopToBottom(criteria: string) { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const range = sheet.getRange("A1:E5"); - - // Find the column header that provides the sort criteria. - const header = range.find(criteria, {}); - header.load("columnIndex"); - await context.sync(); - - range.sort.apply( - [ - { - key: header.columnIndex, - sortOn: Excel.SortOn.value - } - ], - false /*matchCase*/, - true /*hasHeaders*/, - Excel.SortOrientation.rows - ); - await context.sync(); - }); - } - - async function sortLeftToRight(criteria: string) { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const range = sheet.getRange("A1:E5"); - - // Find the row header that provides the sort criteria. - const header = range.find(criteria, {}); - header.load("rowIndex"); - await context.sync(); - - range.sort.apply( - [ - { - key: header.rowIndex, - sortOn: Excel.SortOn.value - } - ], - false /*matchCase*/, - true /*hasHeaders*/, - Excel.SortOrientation.columns - ); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Fruit Sales", "Q1", "Q2", "Q3", "Q4"], - ["Apples", 5000, 2000, 1000, 7500], - ["Pears", 2000, 900, 550, 1800], - ["Quinces", 500, 800, 400, 100], - ["Plums", 600, 700, 8000, 900] - ]; - - sheet.getRanges("A1:E1,A2:A5").format.font.bold = true; - const range = sheet.getRange("A1:E5"); - range.values = data; - range.format.autofitColumns(); - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback, option?) { - try { - await callback(option); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to register and use handlers for the column and row sorting events.

-
- -
-

Set up

- -
- -
-

Try it out

- -

The event handlers will highlight any rows or columns moved as part of a sorting operation.

- - - - -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/30-events/event-worksheet-single-click.yaml b/samples/excel/30-events/event-worksheet-single-click.yaml deleted file mode 100644 index 6e13acac6..000000000 --- a/samples/excel/30-events/event-worksheet-single-click.yaml +++ /dev/null @@ -1,77 +0,0 @@ -order: 11 -id: excel-event-worksheet-single-click -name: Single click event -description: Registers an event handler that runs when a single-click event occurs in the current worksheet. -host: EXCEL -api_set: - ExcelApi: '1.10' -script: - content: |- - $("#register-click-handler").click(() => tryCatch(registerClickHandler)); - - async function registerClickHandler() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - sheet.onSingleClicked.add((event) => { - return Excel.run((context) => { - console.log(`Click detected at ${event.address} (pixel offset from upper-left cell corner: ${event.offsetX}, ${event.offsetY})`); - return context.sync(); - }); - }); - - console.log("The worksheet click handler is registered."); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to register and use a handler for the single-click event.

-
- -
-

Try it out

-

Use the button below to register the event handler. Then, left-click around the worksheet and check the console. -

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/30-events/events-chart-activated.yaml b/samples/excel/30-events/events-chart-activated.yaml deleted file mode 100644 index 3bd976194..000000000 --- a/samples/excel/30-events/events-chart-activated.yaml +++ /dev/null @@ -1,182 +0,0 @@ -order: 2 -id: excel-events-chart-activated -name: Chart events -description: Registers event handlers on an individual chart that run when the chart is activated or deactivated. -host: EXCEL -api_set: - ExcelApi: '1.8' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - $("#register-onactivated-deactivated-handlers").click(() => tryCatch(registerActivationHandlers)); - $("#create-pie-chart").click(() => tryCatch(createPieChart)); - $("#create-cylinder-chart").click(() => tryCatch(createCylinderChart)); - - async function registerActivationHandlers() { - await Excel.run(async (context) => { - - const pieChart = context.workbook.worksheets.getActiveWorksheet().charts.getItem("Pie"); - - // Register the onActivated and onDeactivated event handlers. - pieChart.onActivated.add(chartActivated); - pieChart.onDeactivated.add(chartDeactivated); - - await context.sync(); - - console.log("Added handlers for Chart onActivated and onDeactivated events."); - }); - } - - async function chartActivated(event) { - await Excel.run(async (context) => { - // Retrieve the worksheet. - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // Retrieve the activated chart by ID and load the name of the chart. - const activatedChart = sheet.charts.getItem(event.chartId); - activatedChart.load(["name"]); - await context.sync(); - - // Print out the activated chart's data. - console.log(`A chart was activated. ID: ${event.chartId}. Chart name: ${activatedChart.name}.`); - }); - } - - async function chartDeactivated(event) { - await Excel.run(async (context) => { - // Callback function for when the chart is deactivated. - console.log("The pie chart is NOT active."); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add('A1:E1', true); - expensesTable.name = "SalesTable"; - - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - createPieChart(); - createCylinderChart(); - sheet.activate(); - - await context.sync(); - }); - } - - async function createCylinderChart() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add("CylinderCol", dataRange, "Auto"); - - chart.name = "Cylinder"; - chart.setPosition("A27", "F40"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Bottom" - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - chart.series.getItemAt(0).name = "Q1"; - chart.series.getItemAt(1).name = "Q2"; - chart.series.getItemAt(2).name = "Q3"; - chart.series.getItemAt(3).name = "Q4"; - - await context.sync(); - }); - } - - async function createPieChart() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add("Pie", dataRange, "Auto"); - - chart.name = "Pie"; - chart.setPosition("A10", "F25"); - chart.title.text = "1st Quarter sales chart"; - chart.legend.position = "Bottom" - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to register and use handlers for the Chart onActivated and onDeactivated events.

-
- -
-

Set up

- -
- -
-

Try it out

-

Click the button to register handlers for the pie chart's activated and deactivated events. Then click the chart to activate it. Watch the console. Finally, click the cylinder chart to deactivate the pie chart.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/30-events/events-chartcollection-added-activated.yaml b/samples/excel/30-events/events-chartcollection-added-activated.yaml deleted file mode 100644 index f96ad0f9f..000000000 --- a/samples/excel/30-events/events-chartcollection-added-activated.yaml +++ /dev/null @@ -1,163 +0,0 @@ -order: 1 -id: excel-events-chartcollection-added-activated -name: Chart collection events -description: 'Registers event handlers on a worksheet''s chart collection that run when any chart within is activated or deactivated, as well as when charts are added to or deleted from the collection.' -host: EXCEL -api_set: - ExcelApi: '1.8' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - $("#register-chartcollection-handlers").click(() => tryCatch(registerChartCollectionHandlers)); - $("#add-chart").click(() => tryCatch(createPieChart)); - - async function registerChartCollectionHandlers() { - await Excel.run(async (context) => { - - context.workbook.worksheets.getActiveWorksheet().charts.onAdded.add(chartAdded); - context.workbook.worksheets.getActiveWorksheet().charts.onActivated.add(chartActivated); - context.workbook.worksheets.getActiveWorksheet().charts.onDeactivated.add(chartDeactivated); - context.workbook.worksheets.getActiveWorksheet().charts.onDeleted.add(chartDeleted); - - await context.sync(); - - console.log("Added handlers for ChartCollection onActivated,onAdded, onDeleted, and onDeactivated events."); - }); - } - - async function chartAdded(event) { - await Excel.run(async (context) => { - console.log("A chart has been added with ID: " + event.chartId); - }); - } - - async function chartActivated(event) { - await Excel.run(async (context) => { - console.log("The ID of the active chart is: " + event.chartId); - }); - } - - async function chartDeactivated(event) { - await Excel.run(async (context) => { - console.log("The chart with this ID was deactivated: " + event.chartId); - }); - } - - async function chartDeleted(event) { - await Excel.run(async (context) => { - console.log("The chart with this ID was deleted: " + event.chartId); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - - let expensesTable = sheet.tables.add('A1:E1', true); - expensesTable.name = "SalesTable"; - - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - async function createPieChart() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add("Pie", dataRange, "Auto"); - - chart.name = "Pie"; - chart.setPosition("A10", "F25"); - chart.title.text = "1st Quarter sales chart"; - chart.legend.position = "Bottom" - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to register and use handlers for the ChartCollection onAdded, onDeleted, onActivated, and onDeactivated events.

-
- -
-

Set up

- -
- -
-

Try it out

-

Click the button to register and use handlers for the worksheet's ChartCollection events.

- -

Click the second button to programmatically add a chart and see the onAdded event fire. Watch the console.

- -

Manually add another chart. You can use the same the table as a source. Watch the console.

-

Select one of the charts to see the onActivated event fire. Then select the other chart to see the onDeactivated event fire on one chart and onActivated for the other.

-

Delete one of the charts to see the onDeleted event fire.

-
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/30-events/events-comment-event-handler.yaml b/samples/excel/30-events/events-comment-event-handler.yaml deleted file mode 100644 index 76f7a5223..000000000 --- a/samples/excel/30-events/events-comment-event-handler.yaml +++ /dev/null @@ -1,181 +0,0 @@ -order: 4 -id: excel-events-comments -name: Comment events -description: 'Registers event handlers to listen for comment additions, changes, and deletions.' -host: EXCEL -api_set: - ExcelAPI: '1.12' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#register-event-handlers").click(() => tryCatch(registerEventHandlers)); - $("#add-comment").click(() => tryCatch(addComment)); - $("#edit-comment").click(() => tryCatch(editComment)); - $("#delete-comment").click(() => tryCatch(deleteComment)); - - async function registerEventHandlers() { - await Excel.run(async (context) => { - const comments = context.workbook.worksheets.getActiveWorksheet().comments; - - // Register the onAdded, onChanged, and onDeleted comment event handlers. - comments.onAdded.add(commentAdded); - comments.onChanged.add(commentChanged); - comments.onDeleted.add(commentDeleted); - - await context.sync(); - - console.log("Added event handlers for when comments are added, changed, or deleted."); - }); - } - - async function commentAdded(event: Excel.CommentAddedEventArgs) { - // Retrieve the added comment using the comment ID. - // Note: This function assumes only a single comment is added at a time. - await Excel.run(async (context) => { - const addedComment = context.workbook.comments.getItem(event.commentDetails[0].commentId); - - // Load the added comment's data. - addedComment.load(["content", "authorName", "creationDate"]); - - await context.sync(); - - // Print out the added comment's data. - console.log(`A comment was added:`); - console.log(` ID: ${event.commentDetails[0].commentId}`); - console.log(` Comment content:${addedComment.content}`); - console.log(` Comment author:${addedComment.authorName}`); - console.log(` Creation date:${addedComment.creationDate}`); - }); - } - - async function commentChanged(event: Excel.CommentChangedEventArgs) { - // Retrieve the changed comment using the comment ID. - // Note: This function assumes only a single comment is changed at a time. - await Excel.run(async (context) => { - const changedComment = context.workbook.comments.getItem(event.commentDetails[0].commentId); - - // Load the changed comment's data. - changedComment.load(["content", "authorName", "creationDate"]); - - await context.sync(); - - // Print out the changed comment's data. - console.log(`A comment was changed:`); - console.log(` ID: ${event.commentDetails[0].commentId}`); - console.log(` Updated comment content: ${changedComment.content}`); - console.log(` Comment author: ${changedComment.authorName}`); - console.log(` Creation date: ${changedComment.creationDate}`); - }); - } - - async function commentDeleted(event: Excel.CommentDeletedEventArgs) { - // Print out the deleted comment's ID. - // Note: This function assumes only a single comment is deleted at a time. - await Excel.run(async (context) => { - console.log(`A comment was deleted:`); - console.log(` ID: ${event.commentDetails[0].commentId}`); - }); - } - - async function addComment() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Comments"); - - // Note that an InvalidArgument error will be thrown if multiple cells are passed to `comment.add`. - sheet.comments.add("A1", "To do: add data."); - await context.sync(); - }); - } - - async function editComment() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Comments"); - const comment = sheet.comments.getItemAt(0); - comment.content = "Please add headers here."; - await context.sync(); - }); - } - - async function deleteComment() { - await Excel.run(async (context) => { - context.workbook.comments.getItemByCell("Comments!A1").delete(); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Comments").delete(); - const sheet = context.workbook.worksheets.add("Comments"); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to register event handlers to listen for comment additions, changes, and deletions.

-
-
-

Setup

- -

- -
-
-

Try it out

-

In addition to hovering over a cell, you can view comment changes in the Comments pane by selecting Show Comments from the Review tab.

- -

- -

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/30-events/events-disable-events.yaml b/samples/excel/30-events/events-disable-events.yaml deleted file mode 100644 index b97d09ca1..000000000 --- a/samples/excel/30-events/events-disable-events.yaml +++ /dev/null @@ -1,187 +0,0 @@ -order: 7 -id: excel-events-disable-events -name: Enable and disable events -description: Toggles event firing on and off. -host: EXCEL -api_set: - ExcelApi: '1.8' -script: - content: | - $("#toggleEvents").click(() => tryCatch(toggleEvents)); - $("#setup").click(() => tryCatch(setup)); - $("#refreshData").click(() => tryCatch(addOrRefreshData)); - $("#registerSumChangedHandlers").click(() => tryCatch(registerSumChangedHandlers)); - - async function toggleEvents() { - await Excel.run(async (context) => { - context.runtime.load("enableEvents"); - await context.sync(); - - // check if events are enabled and toggle accordingly - const eventBoolean = !context.runtime.enableEvents - context.runtime.enableEvents = eventBoolean; - if (eventBoolean) { - console.log("Events are currently on."); - } else { - console.log("Events are currently off."); - } - - await context.sync(); - }); - } - - async function registerSumChangedHandlers() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const sumRange = sheet.getRange("B20:P20"); - sumRange.load("columnCount"); - await context.sync(); - - // add an event handler to each cell in the sum range - for (let i = 0; i < sumRange.columnCount; i++) { - let sumBinding = context.workbook.bindings.add(sumRange.getCell(0,i), Excel.BindingType.range, "SumBinding" + i); - sumBinding.onDataChanged.add(onSumChanged); - } - await context.sync(); - }); - } - - async function onSumChanged(eventArgs: Excel.BindingDataChangedEventArgs) { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const cell = sheet.getRange("P21"); - - // get the grand total of the whole sum range - // note that we are having this program perform the sum instead of giving the Excel cell a function, - // this gives us updating control - let x = context.workbook.functions.sum(sheet.getRange("B20:P20")); - x.load("value"); - await context.sync(); - - cell.values = [[x.value]]; - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let infoRange = sheet.getRange("A20:A21"); - infoRange.values = [["Sums"], ["Grand Total"]] - infoRange.format.autofitColumns(); - infoRange.format.font.bold = true; - addOrRefreshData(); - addSumRow(); - sheet.activate(); - await context.sync(); - }); - } - - async function addOrRefreshData() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const dataRange = sheet.getRange("B1:P19"); - dataRange.load(["rowCount", "columnCount"]); - await context.sync(); - - // fill the range with random numbers - for (let i = 0; i < dataRange.rowCount; i++) { - for (let j = 0; j < dataRange.columnCount; j++) { - dataRange.getCell(i, j).values = [[Math.round(Math.random() * 100)]]; - } - } - - await context.sync(); - }); - } - - async function addSumRow() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const dataRange = sheet.getRange("B1:P19"); - dataRange.load("rowCount"); - - // add a sum of each column to the top - const sumRange = sheet.getRange("B20:P20"); - sumRange.load(["columnCount"]); - await context.sync(); - - for (let i = 0; i < sumRange.columnCount; i++) { - const formulaCell = sumRange.getCell(0, i); - const startAddressCell = dataRange.getCell(0, i); - const endAddressCell = dataRange.getCell(dataRange.rowCount - 1, i); - startAddressCell.load("address"); - endAddressCell.load("address"); - await context.sync(); - formulaCell.formulas = [["=SUM(" + startAddressCell.address + ":" + endAddressCell.address + ")"]]; - formulaCell.format.font.bold = true; - } - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to turn events on and off.

-
-
-

Setup

-

- -

-
-

Try it out

-

The handlers update the "Grand Total" cell when events are fired (and enabled). Try editing the cells or refreshing the data with events enabled and disabled.

-

- -

Please wait until all the numbers are written to the range before pressing Refresh data again.

-
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/30-events/events-formula-changed.yaml b/samples/excel/30-events/events-formula-changed.yaml deleted file mode 100644 index b9bcd3c85..000000000 --- a/samples/excel/30-events/events-formula-changed.yaml +++ /dev/null @@ -1,131 +0,0 @@ -order: 8 -id: excel-events-formula-changed -name: Formula changed event -description: Registers an event handler to detect changes to formulas. -host: EXCEL -api_set: - ExcelAPI: '1.13' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#register-formula-change-handler").click(() => tryCatch(registerFormulaChangeHandler)); - $("#trigger-formula-change").click(() => tryCatch(triggerFormulaChange)); - - async function registerFormulaChangeHandler() { - await Excel.run(async (context) => { - // Retrieve the worksheet named "Sample". - let sheet = context.workbook.worksheets.getItem("Sample"); - - // Register the formula changed event handler for this worksheet. - sheet.onFormulaChanged.add(formulaChangeHandler); - await context.sync(); - - console.log("Registered a formula changed event handler for this worksheet."); - }); - } - - async function formulaChangeHandler(event: Excel.WorksheetFormulaChangedEventArgs) { - await Excel.run(async (context) => { - // Retrieve details about the formula change event. - const cellAddress = event.formulaDetails[0].cellAddress; - const previousFormula = event.formulaDetails[0].previousFormula; - const source = event.source; - - // Print out the change event details. - console.log( - `The formula in cell ${cellAddress} changed. - The previous formula was: ${previousFormula}. - The source of the change was: ${source}.` - ); - }); - } - - async function triggerFormulaChange() { - await Excel.run(async (context) => { - // Retrieve the worksheet and choose a range to edit. - let sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("D1"); - - // Change the formula in the chosen range. - range.formulas = [["=A1 * C1"]]; - await context.sync(); - - console.log(`The new formula is: ${range.formulas}`); - }); - } - - async function setup() { - await Excel.run(async (context) => { - // Delete "Sample" worksheet, if it already exists. - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - - // Add a worksheet named "Sample". - const sheet = context.workbook.worksheets.add("Sample"); - - // Retrieve the range. - const range = sheet.getRange("A1:D1"); - - // Add sample data to the range. - range.formulas = [["2", "4", "24", "=A1 * B1"]]; - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to register a formula changed event handler and detect details about the changed formula.

-
-
-

Try it out

-

Set up the worksheet.

- -

Register the formula changed event handler to this worksheet.

- -

Trigger a change to the formula in cell D1. Watch the console to see details about the change event.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/30-events/events-table-changed.yaml b/samples/excel/30-events/events-table-changed.yaml deleted file mode 100644 index c7d4caf33..000000000 --- a/samples/excel/30-events/events-table-changed.yaml +++ /dev/null @@ -1,177 +0,0 @@ -order: 12 -id: excel-events-table-changed -name: Table events -description: Registers event handlers that run when a table is changed or selected. -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: |+ - $("#setup").click(() => tryCatch(setup)); - $("#register-on-changed-handler").click(() => tryCatch(registerOnChangedHandler)); - $("#change-data").click(() => tryCatch(changeData)); - $("#register-on-selection-changed-handler").click(() => tryCatch(registerOnSelectionChangedHandler)); - $("#change-selection").click(() => tryCatch(changeSelection)); - - async function registerOnChangedHandler() { - await Excel.run(async (context) => { - let table = context.workbook.tables.getItemAt(0); - table.onChanged.add(onChange); - - await context.sync(); - console.log("A handler has been registered for the onChanged event"); - }); - } - - async function changeData() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - let range = sheet.getRange("B7"); - range.values = [[900]]; - range.format.autofitColumns(); - - await context.sync(); - console.log("B7 value has been changed."); - }); - } - - async function onChange(event) { - await Excel.run(async (context) => { - console.log("Handler for table onChanged event has been triggered. Data changed address: " + event.address); - }); - } - - async function registerOnSelectionChangedHandler() { - await Excel.run(async (context) => { - let table = context.workbook.tables.getItemAt(0); - table.onSelectionChanged.add(onSelectionChange); - - await context.sync(); - console.log("A handler has been registered for table onSelectionChanged event"); - }); - } - - async function changeSelection() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getActiveWorksheet(); - let range = sheet.getRange("B3:C3"); - range.select(); - - await context.sync(); - }); - } - - async function onSelectionChange(args) { - await Excel.run(async (context) => { - console.log("Handler for table onSelectionChanged event has been triggered. The new selection is: " + args.address); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let salesTable = sheet.tables.add('A1:E1', true); - salesTable.name = "SalesTable"; - - salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - salesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - - - - language: typescript -template: - content: |+ -
-

This sample shows how to register and use event handlers for table onChanged and onSelectionChanged events.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- -
-

Changing data in a table triggers the data changed event. You can change the data manually or programmatically.

- -
- -
- -
- -
-

Changing a range selection in a table triggers the table onSelectionChanged event. You can change selection manually or programmatically.

- -
- - - language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/30-events/events-tablecollection-changed.yaml b/samples/excel/30-events/events-tablecollection-changed.yaml deleted file mode 100644 index e0662c26e..000000000 --- a/samples/excel/30-events/events-tablecollection-changed.yaml +++ /dev/null @@ -1,170 +0,0 @@ -order: 10 -id: excel-events-tablecollection-changed -name: Table collection events -description: Registers an event handler that runs when a table collection is changed. -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: |+ - $("#setup").click(() => tryCatch(setup)); - $("#register-on-changed-handler").click(() => tryCatch(registerOnChangedHandler)); - $("#change-data").click(() => tryCatch(changeData)); - - async function registerOnChangedHandler() { - await Excel.run(async (context) => { - let tables = context.workbook.tables; - tables.onChanged.add(onChange); - - await context.sync(); - console.log("A handler has been registered for the table collection onChanged event"); - }); - } - - async function changeData() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - - // Change two values to trigger two table onChanged events for demonstration purposes. - // You can also change only one value by commenting out one of the ranges. - let range1 = sheet.getRange("B7"); - let range2 = sheet.getRange("C15"); - range1.values = [[900]]; - range2.values = [[20]]; - range1.format.autofitColumns(); - range2.format.autofitColumns(); - - await context.sync(); - }); - } - - async function onChange(event) { - await Excel.run(async (context) => { - let table = context.workbook.tables.getItem(event.tableId); - let worksheet = context.workbook.worksheets.getItem(event.worksheetId); - worksheet.load("name"); - - await context.sync(); - - console.log("Handler for table collection onChanged event has been triggered. Data changed address: " + event.address); - console.log("Table Id : " + event.tableId); - console.log("Worksheet Id : " + worksheet.name); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - createSalesTable(sheet); - createReturnsTable(sheet); - - let format = sheet.getRange().format; - format.autofitColumns(); - format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - function createSalesTable(sheet: Excel.Worksheet) { - let salesTable = sheet.tables.add('A1:E1', true); - salesTable.name = "SalesTable"; - - salesTable.getHeaderRowRange().values = [["Sales", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - salesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - } - - function createReturnsTable(sheet: Excel.Worksheet) { - let returnsTable = sheet.tables.add('A10:E10', true); - returnsTable.name = "ReturnsTable"; - - returnsTable.getHeaderRowRange().values = [["Returns", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - returnsTable.rows.add(null, [ - ["Frames", 50, 70, 65, 77], - ["Saddles", 20, 23, 16, 31], - ["Brake levers", 20, 87, 56, 81], - ["Chains", 15, 18, 32, 33], - ["Mirrors", 15, 60, 23, 54], - ["Spokes", 25, 35, 45, 65] - ]); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - - - - language: typescript -template: - content: |+ -
-

This sample shows how to register and use an event handler for table collection onChanged event.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- -
-

Changing data in tables triggers the data changed event. You can change the data manually or programmatically.

- -
- - language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/30-events/events-workbook-activated.yaml b/samples/excel/30-events/events-workbook-activated.yaml deleted file mode 100644 index 94979e2c8..000000000 --- a/samples/excel/30-events/events-workbook-activated.yaml +++ /dev/null @@ -1,80 +0,0 @@ -order: 13 -id: excel-events-workbook-activated -name: Workbook activated event -description: This sample shows how to register a workbook activated event handler. -host: EXCEL -api_set: - ExcelAPI: '1.13' -script: - content: | - $("#register-event-handler").click(() => tryCatch(registerEventHandler)); - - async function workbookActivated(event: Excel.WorkbookActivatedEventArgs) { - await Excel.run(async (context) => { - // Callback function for when the workbook is activated. - console.log("The workbook was activated."); - }); - } - - async function registerEventHandler() { - await Excel.run(async (context) => { - const workbook = context.workbook; - - // Register the workbook activated event handler. - workbook.onActivated.add(workbookActivated); - - await context.sync(); - console.log("Added event handler for workbook activated."); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to register a workbook activated event handler.

-

Once the event handler is registered, a notification prints to the console when the workbook is activated. Try - switching to another application and then switching back to Excel to see the console notification.

-
- -
-

Try it out

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml b/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml deleted file mode 100644 index 1e2661035..000000000 --- a/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml +++ /dev/null @@ -1,238 +0,0 @@ -order: 14 -id: excel-events-workbook-and-worksheet-collection -name: Workbook and worksheet collection events -description: 'Registers event handlers that run when a worksheet is added, activated, or deactivated, or when the settings of a workbook are changed.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: |- - $("#register-on-add-handler").click(() => tryCatch(registerOnAddHandler)); - $("#add-worksheet").click(() => tryCatch(addWorksheet)); - - $("#register-on-activate-handler").click(() => tryCatch(registerOnActivateHandler)); - $("#register-on-deactivate-handler").click(() => tryCatch(registerOnDeactivateHandler)); - $("#delete-worksheet").click(() => tryCatch(deleteWorksheet)); - - $("#create-setting").click(() => tryCatch(createSetting)); - $("#change-setting").click(() => tryCatch(changeSetting)); - $("#register-settings-changed-handler").click(() => tryCatch(registerSettingsChangedHandler)); - - async function registerOnAddHandler() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets; - sheet.onAdded.add(onWorksheetAdd); - - await context.sync(); - console.log("A handler has been registered for the OnAdded event."); - }); - } - - async function addWorksheet() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.add(); - sheet.load("name, position"); - - await context.sync(); - console.log('Added worksheet named "${sheet.name}" in position ${sheet.position}'); - }); - } - - async function onWorksheetAdd(event) { - await Excel.run(async (context) => { - console.log( - "Handler for worksheet onAdded event has been triggered. Newly added worksheet Id : " + - event.worksheetId - ); - }); - } - - async function registerOnActivateHandler() { - await Excel.run(async (context) => { - let sheets = context.workbook.worksheets; - sheets.onActivated.add(onActivate); - - await context.sync(); - console.log("A handler has been registered for the OnActivate event."); - }); - } - - async function onActivate(args) { - await Excel.run(async (context) => { - console.log("The activated worksheet Id : " + args.worksheetId); - }); - } - - async function registerOnDeactivateHandler() { - await Excel.run(async (context) => { - let sheets = context.workbook.worksheets; - sheets.onDeactivated.add(onDeactivate); - - await context.sync(); - console.log("A handler has been registered for the OnDeactivate event."); - }); - } - - async function onDeactivate(args) { - await Excel.run(async (context) => { - console.log("The deactivated worksheet Id : " + args.worksheetId); - }); - } - - async function deleteWorksheet() { - await Excel.run(async (context) => { - // Deleting the current worksheet triggers the deactivate event and - // the activate event for the preceding worksheet. - let sheets = context.workbook.worksheets; - sheets.load("items/name"); - - await context.sync(); - - if (sheets.items.length > 1) { - let lastSheet = sheets.items[sheets.items.length - 1]; - lastSheet.delete(); - console.log(`Deleted worksheet named "${lastSheet.name}"`); - } else { - console.log("Unable to delete worksheet."); - } - }); - } - - async function createSetting() { - await Excel.run(async (context) => { - const settings = context.workbook.settings; - settings.add("NeedsReview", true); - const needsReview = settings.getItem("NeedsReview"); - needsReview.load("value"); - - await context.sync(); - console.log("Setting value is: " + needsReview.value); - }); - } - - async function registerSettingsChangedHandler() { - await Excel.run(async (context) => { - const settings = context.workbook.settings; - settings.onSettingsChanged.add(onChangedSetting); - - await context.sync(); - console.log("Settings changed handler registered."); - }); - } - - async function onChangedSetting(args: Excel.SettingsChangedEventArgs) { - try { - await Excel.run(async (context) => { - const changedSetting = args.settings.getItem("NeedsReview"); - changedSetting.load("value"); - - // Must sync with the context in the EventArgs object, - // not the context that Office passes to Excel.run. - await args.settings.context.sync(); - - console.log("Setting value is: " + changedSetting.value); - await context.sync(); - }); - } - catch (error) { - console.error(error); - } - } - - async function changeSetting() { - - // The settings.add method is also how you change a - // setting. There is no settings.setItem or setting.set - // method. For example: - // await Excel.run(async (context) => { - // const settings = context.workbook.settings; - // settings.add("NeedsReview", false); - // await context.sync(); - // }); - // However, a bug prevents the SettingsChanged event - // from firing when a setting is changed with the - // Excel 1.4 Settings APIs. So we must use the Settings - // object from the Office shared APIs: - Office.context.document.settings.set('NeedsReview', false); - await Office.context.document.settings.saveAsync(); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to register and use handlers for when a worksheet is added, activated, or deactivated, or when the settings of a workbook are changed.

-
- -
-

Try it out

- -

Added

-
- - -
- -

Activated/Deactivated

- - - - -

Settings

- - - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/30-events/events-worksheet-protection.yaml b/samples/excel/30-events/events-worksheet-protection.yaml deleted file mode 100644 index 509e0a554..000000000 --- a/samples/excel/30-events/events-worksheet-protection.yaml +++ /dev/null @@ -1,111 +0,0 @@ -order: 16 -id: excel-events-worksheet-protection -name: Worksheet protection events -description: Registers an event handler to listen for worksheet protection status changes. -host: EXCEL -api_set: - ExcelAPI: '1.14' -script: - content: | - $("#register-event").click(() => tryCatch(registerEvent)); - $("#change-protection").click(() => tryCatch(changeProtection)); - - async function registerEvent() { - // This function registers an event handler for the onProtectionChanged event of a worksheet. - await Excel.run(async (context) => { - // Set "Sample" as the active worksheet. - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - sheet.activate(); - - // Register the onProtectionChanged event handler. - sheet.onProtectionChanged.add(checkProtection); - await context.sync(); - console.log("Added a worksheet protection change event handler."); - }); - } - - async function checkProtection(event: Excel.WorksheetProtectionChangedEventArgs) { - // This function is an event handler that returns the protection status of a worksheet - // and information about the changed worksheet. - await Excel.run(async (context) => { - const protectionStatus = event.isProtected; - const worksheetId = event.worksheetId; - const source = event.source; - console.log("Protection status changed. Protection status is now: " + protectionStatus + "."); - console.log(" ID of changed worksheet: " + worksheetId + "."); - console.log(" Source of change event: " + source + "."); - }); - } - - async function changeProtection() { - // This function toggles the protection status of a worksheet between "protected" and "unprotected". - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - sheet.activate(); - - // Load the protected property of the WorksheetProtection object. - sheet.load("protection/protected"); - await context.sync(); - - // Enable worksheet protection if it's disabled, or disable worksheet protection if it's enabled. - if (sheet.protection.protected) { - sheet.protection.unprotect(); - } else { - sheet.protection.protect(); - } - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to register a worksheet protection change event handler. Once the event handler is registered, you can enable and disable worksheet protection for the current worksheet. When worksheet protection is enabled, the current worksheet can't be edited.

-
-
-

Try it out

- -

-

Toggle worksheet protection and then try editing a cell on the worksheet.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/30-events/events-worksheet.yaml b/samples/excel/30-events/events-worksheet.yaml deleted file mode 100644 index 682015fe7..000000000 --- a/samples/excel/30-events/events-worksheet.yaml +++ /dev/null @@ -1,234 +0,0 @@ -order: 15 -id: excel-events-worksheet -name: Worksheet events -description: 'Registers event handlers that run when data is changed in worksheet, the selected range changes in a worksheet, or the worksheet is recalculated.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - - $("#register-on-selection-changed-handler").click(() => tryCatch(registerSelectionChangedHandler)); - $("#select-range").click(() => tryCatch(selectRange)); - - $("#register-on-changed-handler").click(() => tryCatch(registerOnChangedHandler)); - $("#register-onCalculated-handler").click(() => tryCatch(registerOnCalculatedHandler)); - $("#recalculate").click(() => tryCatch(recalculate)); - - $("#delete-data").click(() => tryCatch(deleteData)); - - async function registerSelectionChangedHandler() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - sheet.onSelectionChanged.add(onSelectionChange); - await context.sync(); - - console.log("Added a worksheet-level selection change event handler."); - }); - } - - async function selectRange() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - let range = sheet.getRange("B7:C7"); - range.select(); - - await context.sync(); - }); - } - - async function onSelectionChange(event) { - await Excel.run(async (context) => { - console.log("The selected range has changed to: " + event.address); - }); - } - - async function registerOnCalculatedHandler() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - sheet.onCalculated.add(onCalculated); - await context.sync(); - - console.log("Added a worksheet-level on-calculated event handler."); - }); - } - - async function recalculate() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - let randomResult = context.workbook.functions.randBetween(1, 3000).load("value"); - await context.sync(); - - let row = sheet.tables.getItem("SalesTable").rows.getItemAt(0); - let newValue = [["Frames", 5000, 7000, 6544, randomResult.value, "=SUM(B2:E2)"]]; - row.values = newValue; - row.load("values"); - await context.sync(); - }); - } - - async function onCalculated(event) { - await Excel.run(async (context) => { - console.log("The worksheet has recalculated."); - }); - } - - async function registerOnChangedHandler() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - sheet.onChanged.add(onChange); - await context.sync(); - - console.log("Added a worksheet-level data-changed event handler."); - }); - } - - async function changeData() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - let range = sheet.getRange("B5"); - range.values = [[800]]; - range.format.autofitColumns(); - - await context.sync(); - - console.log("B5 value has been changed."); - }); - } - - async function deleteData() { - // This function deletes data from a range and sets the delete shift direction to "up". - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("A5:F5"); - range.delete(Excel.DeleteShiftDirection.up); - }); - } - - async function onChange(event: Excel.WorksheetChangedEventArgs) { - // This function is an event handler that returns the address, trigger source, - // and insert or delete shift directions of the change. - await Excel.run(async (context) => { - // Return the address where change occurred. - console.log(`Handler for worksheet onChanged event has been triggered.`); - console.log(` Data changed address: ` + event.address); - - // Return the source of the event that triggered the change. - console.log(` Data change trigger source: ` + event.triggerSource); - - // Note:insertShiftDirection and deleteShiftDirection are exclusive and both enums can't have a value at the same time. - // If one has a value, then the other will return undefined. - - // If the insert shift direction is defined, return it. - if (event.changeDirectionState.insertShiftDirection) { - console.log(` Cells inserted shift direction: ` + event.changeDirectionState.insertShiftDirection); - } - - // If the delete shift direction is defined, return it. - if (event.changeDirectionState.deleteShiftDirection) { - console.log(` Cells deleted shift direction: ` + event.changeDirectionState.deleteShiftDirection); - } - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let salesTable = sheet.tables.add("A1:F1", true); - salesTable.name = "SalesTable"; - - salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4", "Total"]]; - - salesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377, "=SUM(B2:E2)"], - ["Saddles", 400, 323, 276, 651, "=SUM(B3:E3)"], - ["Brake levers", 12000, 8766, 8456, 9812, "=SUM(B4:E4)"], - ["Chains", 1550, 1088, 692, 853, "=SUM(B5:E5)"], - ["Mirrors", 225, 600, 923, 544, "=SUM(B6:E6)"], - ["Spokes", 6005, 7634, 4589, 8765, "=SUM(B7:E7)"] - ]); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to register and use an event handler for the worksheet onSelectionChanged event.

-
- -
-

Set up

- -
- -
-

Try it out

- -

Selection Changed

- - -

Changed and Calculated

- - - -

Detect insert and delete shift directions

-

Use the "Insert" and "Delete" buttons in the Excel UI to trigger the onChanged event. Or, use the following "Delete" button to see the properties returned by the event when a table row is removed.

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/30-events/selection-changed-events.yaml b/samples/excel/30-events/selection-changed-events.yaml deleted file mode 100644 index 285379ebd..000000000 --- a/samples/excel/30-events/selection-changed-events.yaml +++ /dev/null @@ -1,160 +0,0 @@ -order: 9 -id: excel-selection-changed-events -name: Selection changed events -description: Registers handlers all the different `onSelectionChanged` events and displays how each event reports the selected addresses. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#register-event-handlers").click(() => tryCatch(registerEventHandlers)); - - async function registerEventHandlers() { - await Excel.run(async (context) => { - // Add a selection changed event handler for the binding. - let binding = context.workbook.bindings.getItemAt(0); - binding.onSelectionChanged.add(onBindingSelectionChange); - - // Add a selection changed event handler for the table. - let table = context.workbook.tables.getItemAt(0); - table.onSelectionChanged.add(onTableSelectionChange); - - // Add a selection changed event handler for the worksheet. - let sheet = context.workbook.worksheets.getItem("Sample"); - sheet.onSelectionChanged.add(onWorksheetSelectionChange); - - // Add a selection changed event handler for the worksheet collection. - context.workbook.worksheets.onSelectionChanged.add(onWorksheetCollectionSelectionChange); - - await context.sync(); - }); - } - - async function onBindingSelectionChange(args: Excel.BindingSelectionChangedEventArgs) { - await Excel.run(async (context) => { - console.log(`Binding event: The new selection is\nStarting Column: ${args.startColumn}\nStarting Row: ${args.startRow}\nColumn Count: ${args.columnCount}\nRow Count: ${args.rowCount}`); - }); - } - - async function onTableSelectionChange(args: Excel.TableSelectionChangedEventArgs) { - await Excel.run(async (context) => { - console.log(`Table event: The address of new selection is: ${args.address}`); - }); - } - - async function onWorksheetSelectionChange(args: Excel.WorksheetSelectionChangedEventArgs) { - await Excel.run(async (context) => { - console.log(`Worksheet event: The address of new selection is: ${args.address}`); - }); - } - - async function onWorksheetCollectionSelectionChange(args: Excel.WorksheetSelectionChangedEventArgs) { - await Excel.run(async (context) => { - console.log(`WorksheetCollection event: The address of new selection is: ${args.address}`); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - // Highlight an area and create a binding there. - let bindingRange = sheet.getRange("A15:D20"); - bindingRange.format.fill.color = "yellow"; - sheet.getRange("A15").values = [["Binding range"]]; - context.workbook.bindings.add(bindingRange, Excel.BindingType.range, "YellowBinding"); - - // Create a table. - let salesTable = sheet.tables.add("A1:E1", true); - salesTable.name = "SalesTable"; - - salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - salesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |+ -
-

This sample shows how to register and use event handlers for table onChanged and onSelectionChanged events.

-
- -
-

Set up

- - -

The onSelectionChanged events being listened for are:

-
    -
  • Binding
  • -
  • Table
  • -
  • Worksheet
  • -
  • WorksheetCollection
  • -
-
- -
-

Try it out

-
- -
-

The console will log the addresses reported by the different onSelectionChanged events. Change the cell or cells selected in the worksheet to see the results. Try selecting single cells, multiple cells, and multiple discontiguous cells.

-
- - - language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/34-named-item/create-and-remove-named-item.yaml b/samples/excel/34-named-item/create-and-remove-named-item.yaml deleted file mode 100644 index c152eb15d..000000000 --- a/samples/excel/34-named-item/create-and-remove-named-item.yaml +++ /dev/null @@ -1,236 +0,0 @@ -order: 1 -id: excel-named-item-create-and-remove-named-item -name: 'Create, access, and remove' -description: 'Creates, accesses, and removes named items in a worksheet.' -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - - $("#add-name-to-total").click(() => tryCatch(addNameToTotal)); - $("#add-name-to-header").click(() => tryCatch(addNameToHeader)); - $("#format-named-range").click(() => tryCatch(formatRangeByName)); - $("#remove-name").click(() => tryCatch(removeName)); - $("#list-named-items").click(() => tryCatch(listNamedItems)); - - async function addNameToTotal() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - sheet.names.add("TotalAmount", "=SUM(ExpensesTable[AMOUNT])"); - sheet.getRange("D11").values = [["=TotalAmount"]]; - - await context.sync(); - }); - } - - async function addNameToHeader() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const headerRange = sheet.getRange("A1:D1"); - - sheet.names.add("ExpensesHeader", headerRange); - const namedItems = sheet.names.load("name, type"); - - await context.sync(); - }); - } - - async function formatRangeByName() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const headerRowName = sheet.names.getItemOrNullObject("ExpensesHeader"); - headerRowName.load(); - await context.sync(); - - if (headerRowName.value) { - const headerRange = headerRowName.getRange(); - headerRange.format.fill.color = "red"; - } else { - console.log("No named item created for the range."); - } - - await context.sync(); - }); - } - - async function removeName() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const totalName = sheet.names.getItemOrNullObject("TotalAmount"); - totalName.load(); - await context.sync(); - - if (totalName.value) { - totalName.delete(); - - // Replace the named item (TotalAmount) with the actual formula for TotalAmount to avoid displaying #NAME in the cell. - sheet.getRange("D11").values = [["=SUM(ExpensesTable[AMOUNT])"]]; - } else { - console.log("No named item created for the formula."); - } - - await context.sync(); - }); - } - - async function listNamedItems() { - await Excel.run(async (context) => { - const namedItems = context.workbook.worksheets.getActiveWorksheet().names.load(); - await context.sync(); - - console.log("This worksheet contains " + namedItems.items.length + " named items."); - - for (let i = 0; i < namedItems.items.length; i++) { - console.log(JSON.stringify(namedItems.items[i])) + "\n"; - } - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add("A1:D1", true); - expensesTable.name = "ExpensesTable"; - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - - let newData = transactions.map(item => [item.date, item.merchant, item.category, item.amount - ]); - - expensesTable.rows.add(null, newData); - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - sheet.activate(); - - await context.sync(); - }); - } - - const transactions = [ - { - date: "1/1/2017", - merchant: "The Phone Company", - category: "Communications", - amount: "$120" - }, - { - date: "1/1/2017", - merchant: "SouthRidge Video", - category: "Entertainment", - amount: "$40" - }, - { - date: "1/1/2017", - merchant: "Coho Winery", - category: "Restaurant", - amount: "$47" - }, - { - date: "1/2/2017", - merchant: "Contoso, Ltd", - category: "Shopping", - amount: "$56" - }, - { - date: "1/2/2017", - merchant: "Contoso, Ltd", - category: "Shopping", - amount: "$110" - }, - { - date: "1/2/2017", - merchant: "Liberty Bakery & Cafe", - category: "Groceries", - amount: "$27" - }, - { - date: "1/2/2017", - merchant: "Liberty Bakery & Cafe", - category: "Groceries", - amount: "$38" - }, - { - date: "1/2/2017", - merchant: "Northwind Electric Cars", - category: "Transportation", - amount: "$42" - }, - { - date: "1/2/2017", - merchant: "Best For You Organics Company", - category: "Groceries", - amount: "$27" - } - ]; - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to create, access, and delete named items.

-
- -
-

Setup

- -

Try it out

-

Named items have unique names, so attempting to create a duplicate (pressing the button twice) will throw an error.

- - - - - -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/34-named-item/update-named-item.yaml b/samples/excel/34-named-item/update-named-item.yaml deleted file mode 100644 index 1cee72d6f..000000000 --- a/samples/excel/34-named-item/update-named-item.yaml +++ /dev/null @@ -1,136 +0,0 @@ -order: 2 -id: excel-update-named-item -name: Update -description: Creates and then updates a named item. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: |- - $("#add-named-item").click(() => tryCatch(addNamedItem)); - $("#update-named-item").click(() => tryCatch(updateNamedItem)); - $("#setup").click(() => tryCatch(setup)); - - async function addNamedItem() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - // Check if the named item already exists - const myNamedItem = sheet.names.getItemOrNullObject("MyRange"); - myNamedItem.load("no-properties-needed"); - await context.sync(); - - if (myNamedItem.isNullObject) { - // Add named item for the first range - const firstRange = sheet.getRange("B2:E7"); - sheet.names.add("MyRange", firstRange); - const namedItems = sheet.names.load("name, formula"); - firstRange.select(); - - await context.sync(); - console.log(`Just created the named item "${namedItems.items[0].name}" located here: ${namedItems.items[0].formula}`); - } else { - console.log("The named item already exists"); - } - }); - } - - async function updateNamedItem() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - // Get the named item - const myNamedItem = sheet.names.getItemOrNullObject("MyRange"); - myNamedItem.load("name, formula"); - await context.sync(); - - if (myNamedItem.isNullObject) { - console.log(`There is no named item. Create it with "Add named item for a range" first.`); - } else { - // Update named item to point to the second range - myNamedItem.formula = "=Sample!$B$10:$D$14"; - sheet.getRange("B10:D14").select(); - await context.sync(); - - console.log(`Just updated the named item "${myNamedItem.name}" -- it's now located here: ${myNamedItem.formula}`); - } - }); - } - - async function setup() { - await Excel.run(async (context) => { - // Create and activate the worksheet - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - sheet.activate(); - - // Format the first range - const firstRange = sheet.getRange("B2:E7"); - firstRange.format.fill.color = "yellow"; - - // Format the second range - const secondRange = sheet.getRange("B10:D14"); - secondRange.format.fill.color = "green"; - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create and update a named item.

-
- -
-

Setup

- -

Try it out

- - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/38-pivottable/pivottable-calculations.yaml b/samples/excel/38-pivottable/pivottable-calculations.yaml deleted file mode 100644 index ba8886dd7..000000000 --- a/samples/excel/38-pivottable/pivottable-calculations.yaml +++ /dev/null @@ -1,213 +0,0 @@ -order: 1 -id: excel-pivottable-calculations -name: Calculations -description: Changes the calculations the PivotTable performs. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.8' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - $("#deletePivot").click(() => tryCatch(deletePivot)); - $("#showPercentages").click(() => tryCatch(showPercentages)); - $("#showDifferenceFrom").click(() => tryCatch(showDifferenceFrom)); - $("#showSums").click(() => tryCatch(showSums)); - - async function showPercentages() { - await Excel.run(async (context) => { - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - const farmDataHierarchy: Excel.DataPivotHierarchy = pivotTable.dataHierarchies.getItem("Sum of Crates Sold at Farm"); - const wholesaleDataHierarchy: Excel.DataPivotHierarchy = pivotTable.dataHierarchies.getItem("Sum of Crates Sold Wholesale"); - - farmDataHierarchy.load("showAs"); - wholesaleDataHierarchy.load("showAs"); - await context.sync(); - - // Show the crates of each fruit type sold at the farm as a percentage of the column's total. - let farmShowAs = farmDataHierarchy.showAs; - farmShowAs.calculation = Excel.ShowAsCalculation.percentOfColumnTotal; - farmShowAs.baseField = pivotTable.rowHierarchies.getItem("Type").fields.getItem("Type"); - farmDataHierarchy.showAs = farmShowAs; - - let wholesaleShowAs = wholesaleDataHierarchy.showAs; - wholesaleShowAs.calculation = Excel.ShowAsCalculation.percentOfColumnTotal; - wholesaleShowAs.baseField = pivotTable.rowHierarchies.getItem("Type").fields.getItem("Type"); - wholesaleDataHierarchy.showAs = wholesaleShowAs; - await context.sync(); - }); - } - - async function showDifferenceFrom() { - await Excel.run(async (context) => { - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - const farmDataHierarchy: Excel.DataPivotHierarchy = pivotTable.dataHierarchies.getItem("Sum of Crates Sold at Farm"); - const wholesaleDataHierarchy: Excel.DataPivotHierarchy = pivotTable.dataHierarchies.getItem("Sum of Crates Sold Wholesale"); - - farmDataHierarchy.load("showAs"); - wholesaleDataHierarchy.load("showAs"); - await context.sync(); - - // Show the difference between crate sales of the "A Farms" and the other farms. - // This difference is both aggregated and shown for individual fruit types (where applicable). - let farmShowAs = farmDataHierarchy.showAs; - farmShowAs.calculation = Excel.ShowAsCalculation.differenceFrom; - farmShowAs.baseField = pivotTable.rowHierarchies.getItem("Farm").fields.getItem("Farm"); - farmShowAs.baseItem = pivotTable.rowHierarchies.getItem("Farm").fields.getItem("Farm").items.getItem("A Farms"); - farmDataHierarchy.showAs = farmShowAs; - - let wholesaleShowAs = wholesaleDataHierarchy.showAs; - wholesaleShowAs.calculation = Excel.ShowAsCalculation.differenceFrom; - wholesaleShowAs.baseField = pivotTable.rowHierarchies.getItem("Farm").fields.getItem("Farm"); - wholesaleShowAs.baseItem = pivotTable.rowHierarchies.getItem("Farm").fields.getItem("Farm").items.getItem("A Farms"); - wholesaleDataHierarchy.showAs = wholesaleShowAs; - await context.sync(); - }); - } - - async function showSums() { - await Excel.run(async (context) => { - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - const farmDataHierarchy: Excel.DataPivotHierarchy = pivotTable.dataHierarchies.getItem("Sum of Crates Sold at Farm"); - const wholesaleDataHierarchy: Excel.DataPivotHierarchy = pivotTable.dataHierarchies.getItem("Sum of Crates Sold Wholesale"); - - farmDataHierarchy.load("showAs"); - wholesaleDataHierarchy.load("showAs"); - await context.sync(); - - // Show the sum totals crates of each fruit type sold at the farm (the default behavior). - let farmShowAs = farmDataHierarchy.showAs; - farmShowAs.calculation = Excel.ShowAsCalculation.none; - farmDataHierarchy.showAs = farmShowAs; - - let wholesaleShowAs = wholesaleDataHierarchy.showAs; - wholesaleShowAs.calculation = Excel.ShowAsCalculation.none; - wholesaleDataHierarchy.showAs = wholesaleShowAs; - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - // Create the worksheets. - context.workbook.worksheets.getItemOrNullObject("Data").delete(); - const dataSheet = context.workbook.worksheets.add("Data"); - context.workbook.worksheets.getItemOrNullObject("Pivot").delete(); - const pivotSheet = context.workbook.worksheets.add("Pivot"); - - // Create farm data. - const data = [["Farm", "Type", "Classification", "Crates Sold at Farm", "Crates Sold Wholesale"], - ["A Farms", "Lime", "Organic", 300, 2000], - ["A Farms", "Lemon", "Organic", 250, 1800], - ["A Farms", "Orange", "Organic", 200, 2200], - ["B Farms", "Lime", "Conventional", 80, 1000], - ["B Farms", "Lemon", "Conventional", 75, 1230], - ["B Farms", "Orange", "Conventional", 25, 800], - ["B Farms", "Orange", "Organic", 20, 500], - ["B Farms", "Lemon", "Organic", 10, 770], - ["B Farms", "Kiwi", "Conventional", 30, 300], - ["B Farms", "Lime", "Organic", 50, 400], - ["C Farms", "Apple", "Organic", 275, 220], - ["C Farms", "Kiwi", "Organic", 200, 120], - ["D Farms", "Apple", "Conventional", 100, 3000], - ["D Farms", "Apple", "Organic", 80, 2800], - ["E Farms", "Lime", "Conventional", 160, 2700], - ["E Farms", "Orange", "Conventional", 180, 2000], - ["E Farms", "Apple", "Conventional", 245, 2200], - ["E Farms", "Kiwi", "Conventional", 200, 1500], - ["F Farms", "Kiwi", "Organic", 100, 150], - ["F Farms", "Lemon", "Conventional", 150, 270]]; - - const range = dataSheet.getRange("A1:E21"); - range.values = data; - range.format.autofitColumns(); - pivotSheet.activate(); - - // Create the PivotTable. - context.workbook.worksheets.getActiveWorksheet() - .pivotTables.add("Farm Sales", "Data!A1:E21", "A2"); - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm")); - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Type")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale")); - - await context.sync(); - }); - } - - async function deletePivot() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItem("Pivot").pivotTables.getItem("Farm Sales").delete(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to change the calculations of PivotTable data hierarchies.

-
- -
-

Set up

- -
- -
-

Try it out

-

-

- -

- -
-

Clean up

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/38-pivottable/pivottable-create-and-modify.yaml b/samples/excel/38-pivottable/pivottable-create-and-modify.yaml deleted file mode 100644 index 8ad09ddaf..000000000 --- a/samples/excel/38-pivottable/pivottable-create-and-modify.yaml +++ /dev/null @@ -1,278 +0,0 @@ -order: 2 -id: excel-pivottable-create-and-modify -name: Create and modify -description: Creates and modifies a PivotTable. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.8' -script: - content: |- - $("#deletePivot").click(() => tryCatch(deletePivot)); - $("#createWithNames").click(() => tryCatch(createWithNames)); - $("#addRow").click(() => tryCatch(addRow)); - $("#removeRow").click(() => tryCatch(removeRow)); - $("#toggleColumn").click(() => tryCatch(toggleColumn)); - $("#addValues").click(() => tryCatch(addValues)); - $("#changeHierarchyNames").click(() => tryCatch(changeHierarchyNames)); - $("#changeLayout").click(() => tryCatch(changeLayout)); - $("#setup").click(() => tryCatch(setup)); - - async function createWithNames() { - await Excel.run(async (context) => { - const rangeToAnalyze = context.workbook.worksheets.getItem("Data").getRange("A1:E21"); - const rangeToPlacePivot = context.workbook.worksheets.getItem("Pivot").getRange("A2"); - context.workbook.worksheets.getItem("Pivot").pivotTables.add("Farm Sales", rangeToAnalyze, rangeToPlacePivot); - - await context.sync(); - }); - } - - async function deletePivot() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItem("Pivot").pivotTables.getItem("Farm Sales").delete(); - - await context.sync(); - }); - } - - async function addRow() { - await Excel.run(async (context) => { - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - - // Check if the PivotTable already has rows. - const farmRow = pivotTable.rowHierarchies.getItemOrNullObject("Farm"); - const typeRow = pivotTable.rowHierarchies.getItemOrNullObject("Type"); - const classificationRow = pivotTable.rowHierarchies.getItemOrNullObject("Classification"); - pivotTable.rowHierarchies.load(); - await context.sync(); - - if (farmRow.isNullObject) { - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm")); - } else if (typeRow.isNullObject) { - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Type")); - } else if (classificationRow.isNullObject) { - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Classification")); - } - - await context.sync(); - }); - } - - async function removeRow() { - await Excel.run(async (context) => { - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - - // Check if the PivotTable already has rows. - const farmRow = pivotTable.rowHierarchies.getItemOrNullObject("Farm"); - const typeRow = pivotTable.rowHierarchies.getItemOrNullObject("Type"); - const classificationRow = pivotTable.rowHierarchies.getItemOrNullObject("Classification"); - pivotTable.rowHierarchies.load(); - await context.sync(); - - if (!classificationRow.isNullObject) { - pivotTable.rowHierarchies.remove(classificationRow); - } else if (!typeRow.isNullObject) { - pivotTable.rowHierarchies.remove(typeRow); - } else if (!farmRow.isNullObject) { - pivotTable.rowHierarchies.remove(farmRow); - } - - await context.sync(); - }); - } - - async function toggleColumn() { - await Excel.run(async (context) => { - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - - // Check if the PivotTable already has a column. - const column = pivotTable.columnHierarchies.getItemOrNullObject("Farm"); - column.load("id"); - await context.sync(); - - if (column.isNullObject) { - // Adding the farm column to the column hierarchy automatically removes it from the row hierarchy. - pivotTable.columnHierarchies.add(pivotTable.hierarchies.getItem("Farm")); - } else { - pivotTable.columnHierarchies.remove(column); - } - - await context.sync(); - }); - } - - async function addValues() { - await Excel.run(async (context) => { - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale")); - - await context.sync(); - }); - } - - async function changeHierarchyNames() { - await Excel.run(async (context) => { - const dataHierarchies = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales").dataHierarchies - dataHierarchies.load("no-properties-needed"); - await context.sync(); - - dataHierarchies.items[0].name = "Farm Sales"; - dataHierarchies.items[1].name = "Wholesale"; - await context.sync(); - }); - } - - async function changeLayout() { - await Excel.run(async (context) => { - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - pivotTable.layout.load("layoutType"); - await context.sync(); - - // Cycle between the three layout types. - if (pivotTable.layout.layoutType === "Compact") { - pivotTable.layout.layoutType = "Outline"; - } else if (pivotTable.layout.layoutType === "Outline") { - pivotTable.layout.layoutType = "Tabular"; - } else { - pivotTable.layout.layoutType = "Compact"; - } - await context.sync(); - console.log("Pivot layout is now " + pivotTable.layout.layoutType); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Data").delete(); - const dataSheet = context.workbook.worksheets.add("Data"); - context.workbook.worksheets.getItemOrNullObject("Pivot").delete(); - const pivotSheet = context.workbook.worksheets.add("Pivot"); - - const data = [["Farm", "Type", "Classification", "Crates Sold at Farm", "Crates Sold Wholesale"], - ["A Farms", "Lime", "Organic", 300, 2000], - ["A Farms", "Lemon", "Organic", 250, 1800], - ["A Farms", "Orange", "Organic", 200, 2200], - ["B Farms", "Lime", "Conventional", 80, 1000], - ["B Farms", "Lemon", "Conventional", 75, 1230], - ["B Farms", "Orange", "Conventional", 25, 800], - ["B Farms", "Orange", "Organic", 20, 500], - ["B Farms", "Lemon", "Organic", 10, 770], - ["B Farms", "Kiwi", "Conventional", 30, 300], - ["B Farms", "Lime", "Organic", 50, 400], - ["C Farms", "Apple", "Organic", 275, 220], - ["C Farms", "Kiwi", "Organic", 200, 120], - ["D Farms", "Apple", "Conventional", 100, 3000], - ["D Farms", "Apple", "Organic", 80, 2800], - ["E Farms", "Lime", "Conventional", 160, 2700], - ["E Farms", "Orange", "Conventional", 180, 2000], - ["E Farms", "Apple", "Conventional", 245, 2200], - ["E Farms", "Kiwi", "Conventional", 200, 1500], - ["F Farms", "Kiwi", "Organic", 100, 150], - ["F Farms", "Lemon", "Conventional", 150, 270]]; - - const range = dataSheet.getRange("A1:E21"); - range.values = data; - range.format.autofitColumns(); - - pivotSheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create PivotTables and add hierarchies to form rows, columns, and data sets.

-
- -
-

Set up

- -
-
-

Try it out

-
-
-

Create the PivotTable

- -
- -
-

Adjust the PivotTable

- -

- -

- -

- -

- -
-

Adjust formatting

- -

- -

- -
-

Delete the PivotTable

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/38-pivottable/pivottable-filters-and-summaries.yaml b/samples/excel/38-pivottable/pivottable-filters-and-summaries.yaml deleted file mode 100644 index 9430d6de1..000000000 --- a/samples/excel/38-pivottable/pivottable-filters-and-summaries.yaml +++ /dev/null @@ -1,235 +0,0 @@ -order: 3 -id: excel-pivottable-filters-and-summaries -name: Filters and summaries -description: Filters PivotTable data and shows different summarizations. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.8' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - $("#deletePivot").click(() => tryCatch(deletePivot)); - $("#filter").click(() => tryCatch(filter)); - $("#getCrateTotal").click(() => tryCatch(getCrateTotal)); - $("#minFunc").click(() => tryCatch(minFunc)); - $("#maxFunc").click(() => tryCatch(maxFunc)); - $("#countFunc").click(() => tryCatch(countFunc)); - $("#avgFunc").click(() => tryCatch(avgFunc)); - $("#sumFunc").click(() => tryCatch(sumFunc)); - - async function filter(functionType: Excel.AggregationFunction) { - await Excel.run(async (context) => { - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - const filters = pivotTable.filterHierarchies; - const filter = filters.getItemOrNullObject("Classification"); - filter.load(); - await context.sync(); - - // Add the Classification hierarchy to the filter, if it's not already there. - if (filter.isNullObject) { - filters.add(pivotTable.hierarchies.getItem("Classification")); - await context.sync(); - } - }); - } - - async function minFunc() { - genericFunctionSwitch(Excel.AggregationFunction.min); - } - async function maxFunc() { - genericFunctionSwitch(Excel.AggregationFunction.max); - } - async function countFunc() { - genericFunctionSwitch(Excel.AggregationFunction.count); - } - async function avgFunc() { - genericFunctionSwitch(Excel.AggregationFunction.average); - } - async function sumFunc() { - genericFunctionSwitch(Excel.AggregationFunction.sum); - } - - async function genericFunctionSwitch(functionType: Excel.AggregationFunction) { - await Excel.run(async (context) => { - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - pivotTable.dataHierarchies.load("no-properties-needed"); - await context.sync(); - - pivotTable.dataHierarchies.items[0].summarizeBy = functionType; - pivotTable.dataHierarchies.items[1].summarizeBy = functionType; - await context.sync(); - }); - } - - async function getCrateTotal() { - await Excel.run(async (context) => { - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - - // The layout controls the ranges used by the PivotTable. - const range = pivotTable.layout.getDataBodyRange(); - - // Get all the data hierarchy totals. - const grandTotalRange = range.getLastRow(); - grandTotalRange.load("address"); - await context.sync(); - - // Use the wholesale and farm sale totals to make a final sum. - const masterTotalRange = context.workbook.worksheets.getActiveWorksheet().getRange("B27:C27"); - masterTotalRange.formulas = [["All Crates", "=SUM(" + grandTotalRange.address + ")"]]; - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - // Create the worksheets. - context.workbook.worksheets.getItemOrNullObject("Data").delete(); - const dataSheet = context.workbook.worksheets.add("Data"); - context.workbook.worksheets.getItemOrNullObject("Pivot").delete(); - const pivotSheet = context.workbook.worksheets.add("Pivot"); - - // Create farm data. - const data = [["Farm", "Type", "Classification", "Crates Sold at Farm", "Crates Sold Wholesale"], - ["A Farms", "Lime", "Organic", 300, 2000], - ["A Farms", "Lemon", "Organic", 250, 1800], - ["A Farms", "Orange", "Organic", 200, 2200], - ["B Farms", "Lime", "Conventional", 80, 1000], - ["B Farms", "Lemon", "Conventional", 75, 1230], - ["B Farms", "Orange", "Conventional", 25, 800], - ["B Farms", "Orange", "Organic", 20, 500], - ["B Farms", "Lemon", "Organic", 10, 770], - ["B Farms", "Kiwi", "Conventional", 30, 300], - ["B Farms", "Lime", "Organic", 50, 400], - ["C Farms", "Apple", "Organic", 275, 220], - ["C Farms", "Kiwi", "Organic", 200, 120], - ["D Farms", "Apple", "Conventional", 100, 3000], - ["D Farms", "Apple", "Organic", 80, 2800], - ["E Farms", "Lime", "Conventional", 160, 2700], - ["E Farms", "Orange", "Conventional", 180, 2000], - ["E Farms", "Apple", "Conventional", 245, 2200], - ["E Farms", "Kiwi", "Conventional", 200, 1500], - ["F Farms", "Kiwi", "Organic", 100, 150], - ["F Farms", "Lemon", "Conventional", 150, 270]]; - - const range = dataSheet.getRange("A1:E21"); - range.values = data; - range.format.autofitColumns(); - pivotSheet.activate(); - - // Create the PivotTable. - context.workbook.worksheets.getActiveWorksheet() - .pivotTables.add("Farm Sales", "Data!A1:E21", "A2"); - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm")); - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Type")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale")); - - await context.sync(); - }); - } - - async function deletePivot() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItem("Pivot").pivotTables.getItem("Farm Sales").delete(); - - // Also clean up the extra data from getCrateTotal(). - context.workbook.worksheets.getActiveWorksheet().getRange("B27:C27").delete(Excel.DeleteShiftDirection.up); - await context.sync(); - }); - } - - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to filter PivotTables and manipulate their data.

-
- -
-

Set up

- -
- -
-

Try it out

-
- -
-

Change functions

-

-

-

-

- -

- -
-

Filtering

-

- After pressing the "Enable filter" button, manually select the classification filter for the PivotTable - -

-

Data Manipulation

- -
- -
-

Clean up

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/38-pivottable/pivottable-get-pivottables.yaml b/samples/excel/38-pivottable/pivottable-get-pivottables.yaml deleted file mode 100644 index 23ac8032e..000000000 --- a/samples/excel/38-pivottable/pivottable-get-pivottables.yaml +++ /dev/null @@ -1,199 +0,0 @@ -order: 4 -id: excel-pivottables-get-pivottables -name: Get PivotTables -description: Get existing PivotTables in the workbook through their collections and through the ranges they occupy. -host: EXCEL -api_set: - ExcelAPI: '1.12' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#get-pivottables-in-workbook").click(() => tryCatch(getPivotTablesInWorkbook)); - $("#get-pivottables-in-worksheet").click(() => tryCatch(getPivotTablesInWorksheet)); - $("#get-pivottables-in-selected-range").click(() => tryCatch(getPivotTablesInSelectedRange)); - - async function getPivotTablesInWorkbook() { - await Excel.run(async (context) => { - // Get the names of all the PivotTables in the workbook. - const pivotTables = context.workbook.pivotTables; - pivotTables.load("name"); - await context.sync(); - - // Display the names in the console. - console.log("PivotTables in the workbook:") - pivotTables.items.forEach((pivotTable) => { - console.log(`\t${pivotTable.name}`); - }); - }); - } - - async function getPivotTablesInWorksheet() { - await Excel.run(async (context) => { - // Get the names of all the PivotTables in the current worksheet. - const pivotTables = context.workbook.worksheets.getActiveWorksheet().pivotTables; - pivotTables.load("name"); - await context.sync(); - - // Display the names in the console. - console.log("PivotTables in the current worksheet:") - pivotTables.items.forEach((pivotTable) => { - console.log(`\t${pivotTable.name}`); - }); - }); - } - - async function getPivotTablesInSelectedRange() { - await Excel.run(async (context) => { - const activeRange = context.workbook.getSelectedRange(); - - // Get all the PivotTables that intersect with this range. - const partiallyContainedPivotTables = activeRange.getPivotTables(); - // Get all the PivotTables that are completely contained within this range. - const fullyContainedPivotTables = activeRange.getPivotTables(true); - - partiallyContainedPivotTables.load("name"); - fullyContainedPivotTables.load("name"); - await context.sync(); - - // Display the names in the console. - console.log("PivotTables in the current range:") - partiallyContainedPivotTables.items.forEach((pivotTable) => { - console.log(`\t${pivotTable.name}`); - }); - console.log("PivotTables completely contained in the current range:") - fullyContainedPivotTables.items.forEach((pivotTable) => { - console.log(`\t${pivotTable.name}`); - }); - }); - } - - async function setup() { - await Excel.run(async (context) => { - // Create the worksheets. - context.workbook.worksheets.getItemOrNullObject("Data").delete(); - const dataSheet = context.workbook.worksheets.add("Data"); - context.workbook.worksheets.getItemOrNullObject("TotalPivot").delete(); - context.workbook.worksheets.getItemOrNullObject("FilteredPivot").delete(); - const totalPivot = context.workbook.worksheets.add("TotalPivot"); - const filteredPivot = context.workbook.worksheets.add("FilteredPivot"); - - // Create farm data. - const data = [ - ["Farm", "Type", "Classification", "Crates Sold at Farm", "Crates Sold Wholesale"], - ["A Farms", "Lime", "Organic", 300, 2000], - ["A Farms", "Lemon", "Organic", 250, 1800], - ["A Farms", "Orange", "Organic", 200, 2200], - ["B Farms", "Lime", "Conventional", 80, 1000], - ["B Farms", "Lemon", "Conventional", 75, 1230], - ["B Farms", "Orange", "Conventional", 25, 800], - ["B Farms", "Orange", "Organic", 20, 500], - ["B Farms", "Lemon", "Organic", 10, 770], - ["B Farms", "Kiwi", "Conventional", 30, 300], - ["B Farms", "Lime", "Organic", 50, 400], - ["C Farms", "Apple", "Organic", 275, 220], - ["C Farms", "Kiwi", "Organic", 200, 120], - ["D Farms", "Apple", "Conventional", 100, 3000], - ["D Farms", "Apple", "Organic", 80, 2800], - ["E Farms", "Lime", "Conventional", 160, 2700], - ["E Farms", "Orange", "Conventional", 180, 2000], - ["E Farms", "Apple", "Conventional", 245, 2200], - ["E Farms", "Kiwi", "Conventional", 200, 1500], - ["F Farms", "Kiwi", "Organic", 100, 150], - ["F Farms", "Lemon", "Conventional", 150, 270] - ]; - - const range = dataSheet.getRange("A1:E21"); - range.values = data; - range.format.autofitColumns(); - - // Create the first PivotTable. - const pivotTable = totalPivot.pivotTables.add("All Farm Sales", "Data!A1:E21", "TotalPivot!A2"); - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm")); - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Type")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm")); - - // Create the second PivotTable. - const pivotTable2 = filteredPivot.pivotTables.add("Filtered Wholesale", "Data!A1:E21", "FilteredPivot!A2"); - pivotTable2.rowHierarchies.add(pivotTable2.hierarchies.getItem("Farm")); - pivotTable2.rowHierarchies.add(pivotTable2.hierarchies.getItem("Type")); - pivotTable2.dataHierarchies.add(pivotTable2.hierarchies.getItem("Crates Sold Wholesale")); - pivotTable2.filterHierarchies.add(pivotTable2.hierarchies.getItem("Classification")); - - // Switch to one of the worksheets with a PivotTable. - totalPivot.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to get PivotTables in the workbook. You can get them through PivotTableCollection objects - or by querying a Range object containing PivotTable data.

-
- -
-

Set up

-

This creates a data sheet and two PivotTables in two different worksheets. - -

- -
-

Try it out

-
- -
- -

- -

- -

Note that this button only works with a single selected range. - Multi-range selections aren't supported by `getPivotTables` at this time.

-
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/38-pivottable/pivottable-pivotfilters.yaml b/samples/excel/38-pivottable/pivottable-pivotfilters.yaml deleted file mode 100644 index d07c74f5e..000000000 --- a/samples/excel/38-pivottable/pivottable-pivotfilters.yaml +++ /dev/null @@ -1,328 +0,0 @@ -order: 5 -id: excel-pivottables-pivotfilters -name: PivotFilters -description: Applies PivotFilters to a PivotTable. -host: EXCEL -api_set: - ExcelAPI: '1.12' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#manual-filter").click(() => tryCatch(manualFilter)); - $("#date-filter").click(() => tryCatch(dateFilter)); - $("#value-filter").click(() => tryCatch(valueFilter)); - $("#label-filter").click(() => tryCatch(labelFilter)); - $("#clear-filters").click(() => tryCatch(clearFilters)); - $("#log-filters").click(() => tryCatch(logFilters)); - $("#get-crate-total").click(() => tryCatch(getCrateTotal)); - - async function manualFilter() { - await Excel.run(async (context) => { - // Add a PivotFilter to filter on manually-selected items. - - // Get the PivotTable. - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - - // PivotFilters can only be applied to PivotHierarchies that are being used for pivoting. - // If it's not already there, add "Classification" to the hierarchies. - let classHierarchy = pivotTable.filterHierarchies.getItemOrNullObject("Classification"); - await context.sync(); - if (classHierarchy.isNullObject) { - classHierarchy = pivotTable.filterHierarchies.add(pivotTable.hierarchies.getItem("Classification")); - } - - // Apply a manual filter to include only a specific PivotItem (the string "Organic"). - const filterField = classHierarchy.fields.getItem("Classification"); - const manualFilter = { selectedItems: ["Organic"]}; - filterField.applyFilter({ manualFilter: manualFilter }); - - await context.sync(); - }); - } - - async function dateFilter() { - await Excel.run(async (context) => { - // Add a date-based PivotFilter. - - // Get the PivotTable. - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - - // PivotFilters can only be applied to PivotHierarchies that are being used for pivoting. - // If it's not already there, add "Date Updated" to the hierarchies. - let dateHierarchy = pivotTable.rowHierarchies.getItemOrNullObject("Date Updated"); - await context.sync(); - if (dateHierarchy.isNullObject) { - dateHierarchy = pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Date Updated")); - } - - // Apply a date filter to filter out anything logged before August. - const filterField = dateHierarchy.fields.getItem("Date Updated"); - const dateFilter = { - condition: Excel.DateFilterCondition.afterOrEqualTo, - comparator: { - date: "2020-08-01", - specificity: Excel.FilterDatetimeSpecificity.month - } - }; - filterField.applyFilter({ dateFilter: dateFilter }); - - await context.sync(); - }); - } - - async function valueFilter() { - await Excel.run(async (context) => { - // Add a PivotFilter to filter on the values correlated with a row. - - // Get the PivotTable. - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - - // Get the "Farm" field. - const field = pivotTable.hierarchies.getItem("Farm").fields.getItem("Farm"); - - // Filter to only include rows with more than 500 wholesale crates sold. - const filter: Excel.PivotValueFilter = { - condition: Excel.ValueFilterCondition.greaterThan, - comparator: 500, - value: "Sum of Crates Sold Wholesale" - }; - - // Apply the value filter to the field. - field.applyFilter({ valueFilter: filter }); - - await context.sync(); - }); - } - - async function labelFilter() { - await Excel.run(async (context) => { - // Add a PivotFilter to filter based on the strings of item labels. - - // Get the PivotTable. - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - - // Get the "Type" field. - const field = pivotTable.hierarchies.getItem("Type").fields.getItem("Type"); - - // Filter out any types that start with "L" ("Lemons" and "Limes" in this case). - const filter: Excel.PivotLabelFilter = { - condition: Excel.LabelFilterCondition.beginsWith, - substring: "L", - exclusive: true - }; - - // Apply the label filter to the field. - field.applyFilter({ labelFilter: filter }); - - await context.sync(); - }); - } - - async function clearFilters() { - await Excel.run(async (context) => { - // Clear all the PivotFilters. - - // Get the PivotTable. - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - pivotTable.hierarchies.load("name"); - await context.sync(); - - // Clear the filters on each PivotField. - pivotTable.hierarchies.items.forEach((hierarchy) => { - hierarchy.fields.getItem(hierarchy.name).clearAllFilters(); - }); - await context.sync(); - }); - } - - async function getCrateTotal() { - await Excel.run(async (context) => { - // Get the total amounts from the PivotTable. - - // Get the PivotTable. - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - - // The layout controls the ranges used by the PivotTable. - const range = pivotTable.layout.getDataBodyRange(); - - // Get all the data hierarchy totals. - const grandTotalRange = range.getLastRow(); - grandTotalRange.load("address"); - - // Use the wholesale and farm sale totals to make a final sum. - const sumResult = context.workbook.functions.sum(grandTotalRange); - sumResult.load("value"); - await context.sync(); - - console.log(`Total crate count: ${sumResult.value}`); - await context.sync(); - }); - } - - async function logFilters() { - await Excel.run(async (context) => { - // Display all the active PivotFilters. - - // Get the PivotTable. - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - - // Get the number of PivotHierarchies. - pivotTable.hierarchies.load("name"); - let hierarchyCount = pivotTable.hierarchies.getCount(); - await context.sync(); - - // Iterate over all the hierarchies looking for filters on the PivotFields. - for (let i = 0; i < hierarchyCount.value; i++) { - let filters = pivotTable.hierarchies.items[i].fields.getItem(pivotTable.hierarchies.items[i].name).getFilters(); - await context.sync(); - - if ( - filters.value.dateFilter || - filters.value.labelFilter || - filters.value.manualFilter || - filters.value.valueFilter - ) { - console.log(`Filters found on "${pivotTable.hierarchies.items[i].name}" field:`); - console.log(filters.value); - } - } - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - // Create the worksheets. - context.workbook.worksheets.getItemOrNullObject("Data").delete(); - const dataSheet = context.workbook.worksheets.add("Data"); - context.workbook.worksheets.getItemOrNullObject("Pivot").delete(); - const pivotSheet = context.workbook.worksheets.add("Pivot"); - - // Create farm data. - const data = [ - ["Farm", "Type", "Classification", "Date Updated", "Crates Sold at Farm", "Crates Sold Wholesale"], - ["A Farms", "Lime", "Organic", "8/12/2020", 300, 2000], - ["A Farms", "Lemon", "Organic", "8/11/2020", 250, 1800], - ["A Farms", "Orange", "Organic", "8/1/2020", 200, 2200], - ["B Farms", "Lime", "Conventional", "8/2/2020", 80, 1000], - ["B Farms", "Lemon", "Conventional", "7/29/2020", 75, 1230], - ["B Farms", "Orange", "Conventional", "7/15/2020", 25, 800], - ["B Farms", "Orange", "Organic", "8/1/2020", 20, 500], - ["B Farms", "Lemon", "Organic", "8/5/2020", 10, 770], - ["B Farms", "Kiwi", "Conventional", "7/25/2020", 30, 300], - ["B Farms", "Lime", "Organic", "7/15/2020", 50, 600], - ["C Farms", "Apple", "Organic", "8/1/2020", 275, 220], - ["C Farms", "Kiwi", "Organic", "8/1/2020", 200, 120], - ["D Farms", "Apple", "Conventional", "7/23/2020", 100, 3000], - ["D Farms", "Apple", "Organic", "7/26/2020", 80, 2800], - ["E Farms", "Lime", "Conventional", "8/1/2020", 160, 2700], - ["E Farms", "Orange", "Conventional", "8/7/2020", 180, 2000], - ["E Farms", "Apple", "Conventional", "8/10/2020", 245, 2200], - ["E Farms", "Kiwi", "Conventional", "8/11/2020", 200, 1500], - ["F Farms", "Kiwi", "Organic", "7/30/2020", 100, 150], - ["F Farms", "Lemon", "Conventional", "7/14/2020", 150, 270] - ]; - - const range = dataSheet.getRange("A1:F21"); - range.values = data; - range.format.autofitColumns(); - pivotSheet.activate(); - - // Create the PivotTable. - context.workbook.worksheets.getActiveWorksheet().pivotTables.add("Farm Sales", "Data!A1:F21", "A2"); - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm")); - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Type")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale")); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to filter PivotTables with the different PivotFilters.

-
- -
-

Set up

- -
- -
-

Try it out

-
- -
-

Filters

-

Manual filter

- -

-

Date filter

- -

-

Value filter

- -

-

Label filter

- - -

PivotTable Status

-

-

-

-

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/38-pivottable/pivottable-pivotlayout.yaml b/samples/excel/38-pivottable/pivottable-pivotlayout.yaml deleted file mode 100644 index acbd8c3f0..000000000 --- a/samples/excel/38-pivottable/pivottable-pivotlayout.yaml +++ /dev/null @@ -1,323 +0,0 @@ -order: 6 -id: excel-pivottable-pivotlayout -name: PivotLayout -description: Sets PivotTable layout settings through the PivotLayout. -host: EXCEL -api_set: - ExcelAPI: '1.13' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#change-layout").click(() => tryCatch(changeLayout)); - $("#add-alt-text").click(() => tryCatch(addAltText)); - $("#add-line-spacing").click(() => tryCatch(addLineSpacing)); - $("#repeat-item-labels").click(() => tryCatch(repeatItemLabels)); - $("#toggle-field-headers").click(() => tryCatch(toggleFieldHeaders)); - $("#toggle-grand-totals").click(() => tryCatch(toggleGrandTotals)); - $("#set-empty-cell-text").click(() => tryCatch(setEmptyCellText)); - $("#toggle-fill-empty-cells").click(() => tryCatch(toggleFillEmptyCells)); - $("#toggle-auto-format").click(() => tryCatch(toggleAutoFormat)); - $("#toggle-preserve-formatting").click(() => tryCatch(togglePreserveFormatting)); - - async function changeLayout() { - await Excel.run(async (context) => { - // Change the PivotLayout.type to a new type. - const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales"); - pivotTable.layout.load("layoutType"); - await context.sync(); - - // Cycle between the three layout types. - if (pivotTable.layout.layoutType === "Compact") { - pivotTable.layout.layoutType = "Outline"; - } else if (pivotTable.layout.layoutType === "Outline") { - pivotTable.layout.layoutType = "Tabular"; - } else { - pivotTable.layout.layoutType = "Compact"; - } - - await context.sync(); - console.log("Pivot layout is now " + pivotTable.layout.layoutType); - }); - } - - async function addAltText() { - await Excel.run(async (context) => { - // Set the alt text for the displayed PivotTable. - const pivotTable = context.workbook.pivotTables.getItem("Farm Sales"); - const pivotLayout = pivotTable.layout; - - pivotLayout.altTextTitle = "Farm Sales PivotTable"; - pivotLayout.altTextDescription = "A summary of fruit sales. It is pivoted on farm name, and fruit type. The aggregated data is both the sums of crates sold at the farms and the sums of crates sold wholesale."; - console.log("Adding alt text. Check the PivotTable settings to see the changes."); - - await context.sync(); - }); - } - - async function addLineSpacing() { - await Excel.run(async (context) => { - // Add a blank row after each PivotItem in the row hierarchy. - const pivotTable = context.workbook.pivotTables.getItem("Farm Sales"); - const pivotLayout = pivotTable.layout; - - pivotLayout.displayBlankLineAfterEachItem(true); - console.log("Setting `PivotLayout.displayBlankLineAfterEachItem` to true."); - - await context.sync(); - }); - } - - async function repeatItemLabels() { - await Excel.run(async (context) => { - // Repeat the PivotItem labels for each row used by another level of the row hierarchy. - const pivotTable = context.workbook.pivotTables.getItem("Farm Sales"); - const pivotLayout = pivotTable.layout; - - pivotLayout.repeatAllItemLabels(true); - console.log("Setting `PivotLayout.repeatAllItemLabels` to true."); - - await context.sync(); - }); - } - - async function toggleFieldHeaders() { - await Excel.run(async (context) => { - // Turn the field headers on and off for the row and column hierarchies. - const pivotTable = context.workbook.pivotTables.getItem("Farm Sales"); - const pivotLayout = pivotTable.layout; - pivotLayout.load("showFieldHeaders"); - await context.sync(); - - let showHeaders = !pivotLayout.showFieldHeaders; - console.log(`Show field headers? - ${showHeaders}`); - pivotLayout.showFieldHeaders = showHeaders; - await context.sync(); - }); - } - - async function toggleGrandTotals() { - await Excel.run(async (context) => { - // Turn the grand totals on and off for the rows and columns. - const pivotTable = context.workbook.pivotTables.getItem("Farm Sales"); - const pivotLayout = pivotTable.layout; - - pivotLayout.load(["showRowGrandTotals", "showColumnGrandTotals"]); - await context.sync(); - - let showColumnTotals = !pivotLayout.showColumnGrandTotals; - let showRowTotals = !pivotLayout.showRowGrandTotals; - console.log(`Show column grand totals? - ${showColumnTotals}`); - console.log(`Show row grand totals? - ${showRowTotals}`); - - pivotLayout.showColumnGrandTotals = showColumnTotals; - pivotLayout.showRowGrandTotals = showRowTotals; - - await context.sync(); - }); - } - - async function setEmptyCellText() { - await Excel.run(async (context) => { - // Set a default value for an empty cell in the PivotTable. This doesn't include cells left blank by the layout. - const pivotTable = context.workbook.pivotTables.getItem("Farm Sales"); - const pivotLayout = pivotTable.layout; - - pivotLayout.emptyCellText = "--"; - - // Set the text alignment to match the rest of the PivotTable. - pivotLayout.getDataBodyRange().format.horizontalAlignment = Excel.HorizontalAlignment.right; - await context.sync(); - }); - } - - async function toggleFillEmptyCells() { - await Excel.run(async (context) => { - // Toggle whether empty cells are filled with a default value. - const pivotTable = context.workbook.pivotTables.getItem("Farm Sales"); - const pivotLayout = pivotTable.layout; - - pivotLayout.load("fillEmptyCells"); - await context.sync(); - - let fillToSet = !pivotLayout.fillEmptyCells; - console.log(`Filling empty cells? - ${fillToSet}`); - - pivotLayout.fillEmptyCells = fillToSet; - await context.sync(); - }); - } - - async function toggleAutoFormat() { - await Excel.run(async (context) => { - // Set whether the PivotTable adjusts the format after it is refreshed and recalculated. - const pivotTable = context.workbook.pivotTables.getItem("Farm Sales"); - const pivotLayout = pivotTable.layout; - - pivotLayout.load("autoFormat"); - await context.sync(); - - let autoFormatToSet = !pivotLayout.autoFormat; - console.log(`Automatically format PivotTable after a refresh? - ${autoFormatToSet}`); - - pivotLayout.autoFormat = autoFormatToSet; - await context.sync(); - }); - } - - async function togglePreserveFormatting() { - await Excel.run(async (context) => { - // Set whether the PivotTable keeps the established format after it is refreshed and recalculated. - const pivotTable = context.workbook.pivotTables.getItem("Farm Sales"); - const pivotLayout = pivotTable.layout; - - pivotLayout.load("preserveFormatting"); - await context.sync(); - - let preserveFormattingToSet = !pivotLayout.preserveFormatting; - console.log(`Preserve the formatting PivotTable after a refresh? - ${preserveFormattingToSet}`); - - pivotLayout.preserveFormatting = preserveFormattingToSet; - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Data").delete(); - const dataSheet = context.workbook.worksheets.add("Data"); - context.workbook.worksheets.getItemOrNullObject("Pivot").delete(); - const pivotSheet = context.workbook.worksheets.add("Pivot"); - - const data = [ - ["Farm", "Type", "Classification", "Crates Sold at Farm", "Crates Sold Wholesale"], - ["A Farms", "Lime", "Organic", 300, 2000], - ["A Farms", "Lemon", "Organic", 250, 1800], - ["A Farms", "Orange", "Organic", "", 2200], - ["B Farms", "Lime", "Conventional", 80, 1000], - ["B Farms", "Lemon", "Conventional", "", 1230], - ["B Farms", "Orange", "Conventional", 25, 800], - ["B Farms", "Orange", "Organic", 20, 500], - ["B Farms", "Lemon", "Organic", "", 770], - ["B Farms", "Kiwi", "Conventional", 30, 300], - ["B Farms", "Lime", "Organic", "", 400], - ["C Farms", "Apple", "Organic", 275, 220], - ["C Farms", "Kiwi", "Organic", 200, 120], - ["D Farms", "Apple", "Conventional", 100, ""], - ["D Farms", "Apple", "Organic", 80, 2800], - ["E Farms", "Lime", "Conventional", 160, 2700], - ["E Farms", "Orange", "Conventional", "", 2000], - ["E Farms", "Apple", "Conventional", 245, 2200], - ["E Farms", "Kiwi", "Conventional", 200, ""], - ["F Farms", "Kiwi", "Organic", 100, ""], - ["F Farms", "Lemon", "Conventional", "", 270] - ]; - - const range = dataSheet.getRange("A1:E21"); - range.values = data; - range.format.autofitColumns(); - - pivotSheet.activate(); - - const rangeToAnalyze = context.workbook.worksheets.getItem("Data").getRange("A1:E21"); - const rangeToPlacePivot = context.workbook.worksheets.getItem("Pivot").getRange("A2"); - const pivotTable = context.workbook.worksheets - .getItem("Pivot") - .pivotTables.add("Farm Sales", rangeToAnalyze, rangeToPlacePivot); - - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm")); - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Type")); - - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale")); - - // Add the following if you'd like to see how the layout settings affect a column hierarchy. - //pivotTable.columnHierarchies.add(pivotTable.hierarchies.getItem("Classification")); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to work with the PivotLayout class to display the PivotTable.

-
- -
-

Set up

- -
-
-

Try it out

- - - - -
-

Header and total settings

- -
-

Empty cell settings

- -
-

PivotTable refresh formatting settings

- - -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/38-pivottable/pivottable-refresh.yaml b/samples/excel/38-pivottable/pivottable-refresh.yaml deleted file mode 100644 index 87b0a6d01..000000000 --- a/samples/excel/38-pivottable/pivottable-refresh.yaml +++ /dev/null @@ -1,140 +0,0 @@ -order: 8 -id: excel-pivottable-refresh -name: Refresh -description: Refreshes a PivotTable based on table row additions. -host: EXCEL -api_set: - ExcelApi: '1.8' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#refresh-pivottable").click(() => tryCatch(refreshPivotTable)); - $("#add-table-row").click(() => tryCatch(addTableRow)); - - async function refreshPivotTable() { - // This function refreshes the "Farm Sales" PivotTable, - // which updates the PivotTable with changes made to the source table. - await Excel.run(async (context) => { - const pivotTable = context.workbook.pivotTables.getItem("Farm Sales"); - pivotTable.refresh(); - await context.sync(); - }); - } - - async function addTableRow() { - // This function adds a row to the PivotTable's source table. - await Excel.run(async (context) => { - const dataTable = context.workbook.tables.getItem("DataTable"); - dataTable.rows.add(null, [["G Farms", "Mango", "Organic", 200, 1000]]); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Farm", "Type", "Classification", "Crates Sold at Farm", "Crates Sold Wholesale"], - ["A Farms", "Lime", "Organic", 300, 2000], - ["A Farms", "Lemon", "Organic", 250, 1800], - ["A Farms", "Orange", "Organic", 200, 2200], - ["B Farms", "Lime", "Conventional", 80, 1000], - ["B Farms", "Lemon", "Conventional", 75, 1230], - ["B Farms", "Orange", "Conventional", 25, 800], - ["B Farms", "Orange", "Organic", 20, 500], - ["B Farms", "Lemon", "Organic", 10, 770], - ["B Farms", "Kiwi", "Conventional", 30, 300], - ["B Farms", "Lime", "Organic", 50, 400], - ["C Farms", "Apple", "Organic", 275, 220], - ["C Farms", "Kiwi", "Organic", 200, 120], - ["D Farms", "Apple", "Conventional", 100, 3000], - ["D Farms", "Apple", "Organic", 80, 2800], - ["E Farms", "Lime", "Conventional", 160, 2700], - ["E Farms", "Orange", "Conventional", 180, 2000], - ["E Farms", "Apple", "Conventional", 245, 2200], - ["E Farms", "Kiwi", "Conventional", 200, 1500], - ["F Farms", "Kiwi", "Organic", 100, 150], - ["F Farms", "Lemon", "Conventional", 150, 270] - ]; - - const range = sheet.getRange("A1:E21"); - range.values = data; - const table = sheet.tables.add(range, true); - table.name = "DataTable"; - range.format.autofitColumns(); - - const rangeToPlacePivot = sheet.getRange("G1"); - - // Make the source of the PivotTable a Table so added rows are picked up by the refresh operation. - const pivotTable = sheet.pivotTables.add("Farm Sales", table, rangeToPlacePivot); - - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale")); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to refresh a PivotTable.

-
- -
-

Setup

- -
-
-

Try it out

-

Add a row to the table, then refresh the PivotTable. Note that the PivotTable doesn't automatically refresh.

- -

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/38-pivottable/pivottable-slicer.yaml b/samples/excel/38-pivottable/pivottable-slicer.yaml deleted file mode 100644 index 96c967688..000000000 --- a/samples/excel/38-pivottable/pivottable-slicer.yaml +++ /dev/null @@ -1,214 +0,0 @@ -order: 9 -id: excel-pivottable-slicer -name: Slicer -description: Adds a slicer to a PivotTable. -host: EXCEL -api_set: - ExcelApi: '1.10' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#add-pivot-table").click(() => tryCatch(addPivotTable)); - $("#add-slicer").click(() => tryCatch(addSlicer)); - $("#format-slicer").click(() => tryCatch(formatSlicer)); - $("#apply-style").click(() => tryCatch(applyStyle)); - $("#add-filters").click(() => tryCatch(addFilters)); - $("#remove-filters").click(() => tryCatch(removeFilters)); - $("#remove-slicer").click(() => tryCatch(removeSlicer)); - - async function addSlicer() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Pivot"); - const slicer = sheet.slicers.add( - "Farm Sales", /* The slicer data source. For PivotTables, this can be the PivotTable object reference or name. */ - "Type" /* The field in the data source to filter by. For PivotTables, this can be a PivotField object reference or ID. */ - ); - slicer.name = "Fruit Slicer"; - await context.sync(); - }); - } - - async function formatSlicer() { - await Excel.run(async (context) => { - const slicer = context.workbook.slicers.getItem("Fruit Slicer"); - slicer.caption = "Fruit Types"; - slicer.left = 395; - slicer.top = 15; - slicer.height = 135; - slicer.width = 150; - await context.sync(); - }); - } - - async function applyStyle() { - await Excel.run(async (context) => { - const slicer = context.workbook.slicers.getItem("Fruit Slicer"); - slicer.style = "SlicerStyleLight6"; - await context.sync(); - }); - } - - async function addFilters() { - await Excel.run(async (context) => { - const slicer = context.workbook.slicers.getItem("Fruit Slicer"); - slicer.selectItems(["Lemon", "Lime", "Orange"]); - await context.sync(); - }); - } - - async function removeFilters() { - await Excel.run(async (context) => { - const slicer = context.workbook.slicers.getItem("Fruit Slicer"); - slicer.clearFilters(); - await context.sync(); - }); - } - - async function removeSlicer() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - sheet.slicers.getItemAt(0).delete(); - await context.sync(); - }); - } - - async function addPivotTable() { - await Excel.run(async (context) => { - const rangeToAnalyze = context.workbook.worksheets.getItem("Data").getRange("A1:E21"); - const rangeToPlacePivot = context.workbook.worksheets.getItem("Pivot").getRange("A2"); - - const pivotTable = context.workbook.worksheets - .getItem("Pivot") - .pivotTables.add("Farm Sales", rangeToAnalyze, rangeToPlacePivot); - - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm")); - - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale")); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Data").delete(); - const dataSheet = context.workbook.worksheets.add("Data"); - context.workbook.worksheets.getItemOrNullObject("Pivot").delete(); - const pivotSheet = context.workbook.worksheets.add("Pivot"); - - const data = [ - ["Farm", "Type", "Classification", "Crates Sold at Farm", "Crates Sold Wholesale"], - ["A Farms", "Lime", "Organic", 300, 2000], - ["A Farms", "Lemon", "Organic", 250, 1800], - ["A Farms", "Orange", "Organic", 200, 2200], - ["B Farms", "Lime", "Conventional", 80, 1000], - ["B Farms", "Lemon", "Conventional", 75, 1230], - ["B Farms", "Orange", "Conventional", 25, 800], - ["B Farms", "Orange", "Organic", 20, 500], - ["B Farms", "Lemon", "Organic", 10, 770], - ["B Farms", "Kiwi", "Conventional", 30, 300], - ["B Farms", "Lime", "Organic", 50, 400], - ["C Farms", "Apple", "Organic", 275, 220], - ["C Farms", "Kiwi", "Organic", 200, 120], - ["D Farms", "Apple", "Conventional", 100, 3000], - ["D Farms", "Apple", "Organic", 80, 2800], - ["E Farms", "Lime", "Conventional", 160, 2700], - ["E Farms", "Orange", "Conventional", 180, 2000], - ["E Farms", "Apple", "Conventional", 245, 2200], - ["E Farms", "Kiwi", "Conventional", 200, 1500], - ["F Farms", "Kiwi", "Organic", 100, 150], - ["F Farms", "Lemon", "Conventional", 150, 270] - ]; - - const range = dataSheet.getRange("A1:E21"); - range.values = data; - range.format.autofitColumns(); - - pivotSheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to work with a slicer on a PivotTable.

-
- -
-

Setup

- -

- -

-
-

Try it out

-

Add the slicer, then try out the formatting and filtering options.

- -

-

Formatting

- -

- -

-

Data

- -

- -

-

Clean up

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/38-pivottable/pivottable-source-data.yaml b/samples/excel/38-pivottable/pivottable-source-data.yaml deleted file mode 100644 index e0ceb5821..000000000 --- a/samples/excel/38-pivottable/pivottable-source-data.yaml +++ /dev/null @@ -1,135 +0,0 @@ -order: 7 -id: excel-pivottable-data-source -name: PivotTable data source -description: Gets information about the data source of a PivotTable. -host: EXCEL -api_set: - ExcelApi: '1.15' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#get-pivottable-data-source").click(() => tryCatch(getPivotTableDataSource)); - - async function getPivotTableDataSource() { - // This function logs information about the data source of a PivotTable. - await Excel.run(async (context) => { - const worksheet = context.workbook.worksheets.getItem("TotalPivot"); - const pivotTable = worksheet.pivotTables.getItem("All Farm Sales"); - - // Retrieve the type and string representation of the data source of the PivotTable. - const pivotTableDataSourceType = pivotTable.getDataSourceType(); - const pivotTableDataSourceString = pivotTable.getDataSourceString(); - await context.sync(); - - // Log the data source information. - console.log("Data source: " + pivotTableDataSourceString.value); - console.log("Source type: " + pivotTableDataSourceType.value); - }); - } - - async function setup() { - await Excel.run(async (context) => { - // Create the worksheets. - context.workbook.worksheets.getItemOrNullObject("Data").delete(); - const dataSheet = context.workbook.worksheets.add("Data"); - context.workbook.worksheets.getItemOrNullObject("TotalPivot").delete(); - const totalPivot = context.workbook.worksheets.add("TotalPivot"); - - // Create farm data. - const data = [ - ["Farm", "Type", "Classification", "Crates Sold at Farm", "Crates Sold Wholesale"], - ["A Farms", "Lime", "Organic", 300, 2000], - ["A Farms", "Lemon", "Organic", 250, 1800], - ["A Farms", "Orange", "Organic", 200, 2200], - ["B Farms", "Lime", "Conventional", 80, 1000], - ["B Farms", "Lemon", "Conventional", 75, 1230], - ["B Farms", "Orange", "Conventional", 25, 800], - ["B Farms", "Orange", "Organic", 20, 500], - ["B Farms", "Lemon", "Organic", 10, 770], - ["B Farms", "Kiwi", "Conventional", 30, 300], - ["B Farms", "Lime", "Organic", 50, 400], - ["C Farms", "Apple", "Organic", 275, 220], - ["C Farms", "Kiwi", "Organic", 200, 120], - ["D Farms", "Apple", "Conventional", 100, 3000], - ["D Farms", "Apple", "Organic", 80, 2800], - ["E Farms", "Lime", "Conventional", 160, 2700], - ["E Farms", "Orange", "Conventional", 180, 2000], - ["E Farms", "Apple", "Conventional", 245, 2200], - ["E Farms", "Kiwi", "Conventional", 200, 1500], - ["F Farms", "Kiwi", "Organic", 100, 150], - ["F Farms", "Lemon", "Conventional", 150, 270] - ]; - - const range = dataSheet.getRange("A1:E21"); - range.values = data; - range.format.autofitColumns(); - - // Create the PivotTable. - const pivotTable = totalPivot.pivotTables.add("All Farm Sales", "Data!A1:E21", "TotalPivot!A2"); - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm")); - pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Type")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale")); - pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm")); - - // Switch to the worksheet with a PivotTable. - totalPivot.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to get information about the data source of a PivotTable. It returns the type and string representation of the data source.

-

Note: This sample works in Excel on Windows and Excel on the web. It doesn't work in Excel on Mac; this is a known issue.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/cell-properties.yaml b/samples/excel/42-range/cell-properties.yaml deleted file mode 100644 index e923d3f2d..000000000 --- a/samples/excel/42-range/cell-properties.yaml +++ /dev/null @@ -1,194 +0,0 @@ -order: 6 -id: excel-range-cell-properties -name: Get and set cell properties -description: Sets different properties across a range then retrieves those properties. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#set-cell-properties").click(() => tryCatch(setCellProperties)); - $("#get-cell-properties").click(() => tryCatch(getCellProperties)); - $("#setup").click(() => tryCatch(setup)); - - async function setCellProperties() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // Creating the SettableCellProperties objects to use for the range. - // In your add-in, these should be created once, outside the function. - const topHeaderProps: Excel.SettableCellProperties = { - // The style property takes a string matching the name of an Excel style. - // Built-in style names are listed in the `BuiltInStyle` enum. - // Note that a style will overwrite any formatting, - // so do not use the format property with the style property. - style: "Heading1" - }; - - const headerProps: Excel.SettableCellProperties = { - // Any subproperties of format that are not set will not be changed when these cell properties are set. - format: { - fill: { - color: "Blue" - }, - font: { - color: "White", - bold: true - } - } - }; - - const nonApplicableProps: Excel.SettableCellProperties = { - format: { - fill: { - pattern: Excel.FillPattern.gray25 - }, - font: { - color: "Gray", - italic: true - } - } - }; - - const matchupScoreProps: Excel.SettableCellProperties = { - format: { - borders: { - bottom: { - style: Excel.BorderLineStyle.continuous - }, - left: { - style: Excel.BorderLineStyle.continuous - }, - right: { - style: Excel.BorderLineStyle.continuous - }, - top: { - style: Excel.BorderLineStyle.continuous - } - } - } - }; - - const range = sheet.getRange("A1:E5"); - - // You can use empty JSON objects to avoid changing a cell's properties. - range.setCellProperties([ - [topHeaderProps, {}, {}, {}, {}], - [{}, {}, headerProps, headerProps, headerProps], - [{}, headerProps, nonApplicableProps, matchupScoreProps, matchupScoreProps], - [{}, headerProps, matchupScoreProps, nonApplicableProps, matchupScoreProps], - [{}, headerProps, matchupScoreProps, matchupScoreProps, nonApplicableProps] - ]); - - sheet.getUsedRange().format.autofitColumns(); - await context.sync(); - }); - } - - async function getCellProperties() { - await Excel.run(async (context) => { - const cell = context.workbook.getActiveCell(); - - // Define the cell properties to get by setting the matching LoadOptions to true. - const propertiesToGet = cell.getCellProperties({ - address: true, - format: { - fill: { - color: true - }, - font: { - color: true - } - }, - style: true - }); - - // Sync to get the data from the workbook. - await context.sync(); - const cellProperties = propertiesToGet.value[0][0]; - console.log( - `Address: ${cellProperties.address}\nStyle: ${cellProperties.style}\nFill Color: ${cellProperties.format.fill.color}\nFont Color: ${cellProperties.format.font.color}`); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Matchups", " ", " ", " ", " "], - [" ", " ", "SEA", "POR", "VAN"], - [" ", "SEA", "N/A", -1, 2], - [" ", "POR", 1, "N/A", 4], - [" ", "VAN", -2, -4, "N/A"] - ]; - - const range = sheet.getRange("A1:E5"); - range.values = data; - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to format a range.

-
- -
-

Set up

- -
- -
-

Try it out

-

-

Select a cell and press the following button to display some of the cell properties.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/dynamic-arrays.yaml b/samples/excel/42-range/dynamic-arrays.yaml deleted file mode 100644 index 8411cc596..000000000 --- a/samples/excel/42-range/dynamic-arrays.yaml +++ /dev/null @@ -1,185 +0,0 @@ -order: 16 -id: excel-range-dynamic-arrays -name: Dynamic arrays -description: Applies formulas that use dynamic arrays and displays information about the ranges used to display the data. -host: EXCEL -api_set: - ExcelAPI: '1.12' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#copy-table-headers").click(() => tryCatch(copyTableHeaders)); - $("#apply-filter-function").click(() => tryCatch(applyFilterFunction)); - $("#display-spill-information").click(() => tryCatch(displaySpillInformation)); - - async function copyTableHeaders() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - // Set G4 to a formula that returns a dynamic array. - const targetCell = sheet.getRange("G4"); - targetCell.formulas = [["=A4:D4"]]; - - // Get the address of the cells that the dynamic array spilled into. - const spillRange = targetCell.getSpillingToRange(); - spillRange.load("address"); - - // Fit the columns for readability. - sheet.getUsedRange().format.autofitColumns(); - await context.sync(); - - console.log(`Copying the table headers spilled into ${spillRange.address}.`); - }); - } - - async function applyFilterFunction() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - /* Set G5 to a formula that returns a dynamic array. - * The FILTER formula filters the data in A5:D11 based on the values in the "C" column. - * The parameter for the filter is "H2". - */ - const targetCell = sheet.getRange("G5"); - targetCell.formulas = [['=FILTER(A5:D11,C5:C11=H2,"")']]; - - // Get the address of the cells that the dynamic array spilled into. - const spillRange = targetCell.getSpillingToRange(); - spillRange.load("address"); - - // Fit the columns for readability. - sheet.getUsedRange().format.autofitColumns(); - await context.sync(); - - console.log(`Applying the FILTER formula spilled into ${spillRange.address}.`); - }); - } - - async function displaySpillInformation() { - await Excel.run(async (context) => { - // Check the current cell for any spill parents or spilling-to ranges. - const currentRange = context.workbook.getSelectedRange(); - - // Spill parent shows the ranges that are causing data to spill into the current cell. - const spillParent = currentRange.getSpillParentOrNullObject(); - spillParent.load("address"); - - // Spilling-to range shows the ranges to which this cell is applying the results of a dynamic array. - const spillRange = currentRange.getSpillingToRangeOrNullObject(); - spillRange.load("address"); - await context.sync(); - - // Log the dynamic array information contained within the selected cell. - if (!spillParent.isNullObject) { - console.log(`The selected cell has a spill parent at ${spillParent.address}`); - } - if (!spillRange.isNullObject) { - console.log(`The selected cell is spilling into ${spillRange.address}`); - } - - if (spillParent.isNullObject && spillRange.isNullObject) { - console.log("The selected cell is not involved with any dynamic arrays (or you have multiple cells selected)."); - } - }); - } - - /** Create a new table with sample data */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const expensesTable = sheet.tables.add("A4:D4", true /*hasHeaders*/); - expensesTable.name = "ExpensesTable"; - - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - - expensesTable.rows.add(null /*add at the end*/, [ - ["1/1/2020", "The Phone Company", "Communications", "$120"], - ["1/2/2020", "Northwind Electric Cars", "Transportation", "$142"], - ["1/5/2020", "Best For You Organics Company", "Groceries", "$27"], - ["1/10/2020", "Coho Vineyard", "Restaurant", "$33"], - ["1/11/2020", "Bellows College", "Education", "$350"], - ["1/15/2020", "Trey Research", "Other", "$135"], - ["1/15/2020", "Best For You Organics Company", "Groceries", "$97"] - ]); - - sheet.getRange("A2:H2").values = [["Transactions", , , , , , "Category", "Groceries"]]; - sheet.getRange("A2").style = "Heading1"; - sheet.getRange("G2").style = "Heading2"; - sheet.getRange("H2").format.fill.color = "#EEEE99"; - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to apply formulas that return dynamic arrays and how to get the relevant information - about range spilling from the used ranges.

-
- -
-

Set up

- -
- -
-

Try it out

- -

- -

-

Select a spilled cell and press the following button to see information for that cell related to dynamic - arrays.

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/42-range/formatting.yaml b/samples/excel/42-range/formatting.yaml deleted file mode 100644 index a8abfa954..000000000 --- a/samples/excel/42-range/formatting.yaml +++ /dev/null @@ -1,124 +0,0 @@ -order: 5 -id: excel-range-formatting -name: Formatting -description: Formats a range. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - - $("#set-font-and-fill-color").click(() => tryCatch(setFontAndFillColor)); - $("#set-number-format").click(() => tryCatch(setNumberFormat)); - - async function setFontAndFillColor() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const range = sheet.getRange("B2:E2"); - range.format.fill.color = "#4472C4";; - range.format.font.color = "white"; - - await context.sync(); - }); - } - - async function setNumberFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const formats = [ - ["0.00", "0.00"], - ["0.00", "0.00"], - ["0.00", "0.00"] - ]; - - const range = sheet.getRange("D3:E5"); - range.numberFormat = formats; - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Product", "Qty", "Unit Price", "Total Price"], - ["Almonds", 2, 7.50, "=C3 * D3"], - ["Coffee", 1, 34.50, "=C4 * D4"], - ["Chocolate", 5, 9.56, "=C5 * D5"] - ]; - - const range = sheet.getRange("B2:E5"); - range.values = data; - range.format.autofitColumns(); - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to format a range.

-
- -
-

Set up

- -
- -
-

Try it out

- - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/insert-delete-clear-range.yaml b/samples/excel/42-range/insert-delete-clear-range.yaml deleted file mode 100644 index cd6db23fd..000000000 --- a/samples/excel/42-range/insert-delete-clear-range.yaml +++ /dev/null @@ -1,137 +0,0 @@ -order: 8 -id: excel-range-insert-delete-and-clear-range -name: 'Insert, delete, and clear' -description: 'Inserts, deletes, and clears a range.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - - $("#insert-range").click(() => tryCatch(insertRange)); - $("#delete-range").click(() => tryCatch(deleteRange)); - $("#clear-range").click(() => tryCatch(clearRange)); - - async function insertRange() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B4:E4"); - - range.insert(Excel.InsertShiftDirection.down); - - await context.sync(); - }); - } - - async function deleteRange() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B4:E4"); - - range.delete(Excel.DeleteShiftDirection.up); - - await context.sync(); - }); - } - - async function clearRange() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - let range = sheet.getRange("E2:E5"); - - range.clear(); - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Product", "Qty", "Unit Price", "Total Price"], - ["Almonds", 2, 7.50, "=C3 * D3"], - ["Coffee", 1, 34.50, "=C4 * D4"], - ["Chocolate", 5, 9.56, "=C5 * D5"] - ]; - - const range = sheet.getRange("B2:E5"); - range.values = data; - range.format.autofitColumns(); - - const header = range.getRow(0); - header.format.fill.color = "#4472C4"; - header.format.font.color = "white"; - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to insert, delete and clear the contents of a range.

-
- -
-

Set up

- -
- -
-

Try it out

- - - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/outline.yaml b/samples/excel/42-range/outline.yaml deleted file mode 100644 index 02f043b4a..000000000 --- a/samples/excel/42-range/outline.yaml +++ /dev/null @@ -1,240 +0,0 @@ -order: 9 -id: excel-outline -name: Outline -description: Creates an outline by grouping rows and columns. -host: EXCEL -api_set: - ExcelApi: '1.10' -script: - content: | - $("#setup-data").click(() => tryCatch(setupData)); - $("#setup-totals").click(() => tryCatch(setupTotals)); - $("#group-rows").click(() => tryCatch(groupRows)); - $("#group-columns").click(() => tryCatch(groupColumns)); - $("#collapse-outline").click(() => tryCatch(collapseOutline)); - $("#expand-outline").click(() => tryCatch(expandOutline)); - $("#ungroup").click(() => tryCatch(ungroup)); - - async function groupRows() { - Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // Group the larger, main level. Note that the outline controls - // will be on row 10, meaning 4-9 will collapse and expand. - sheet.getRange("4:9").group(Excel.GroupOption.byRows); - - // Group the smaller, sublevels. Note that the outline controls - // will be on rows 6 and 9, meaning 4-5 and 7-8 will collapse and expand. - sheet.getRange("4:5").group(Excel.GroupOption.byRows); - sheet.getRange("7:8").group(Excel.GroupOption.byRows); - await context.sync(); - }); - } - - async function groupColumns() { - Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // Group the larger, main level. Note that the outline controls - // will be on column R, meaning C-Q will collapse and expand. - sheet.getRange("C:Q").group(Excel.GroupOption.byColumns); - - // Group the smaller, sublevels. Note that the outline controls - // will be on columns G, L, and R, meaning C-F, H-K, and M-P will collapse and expand. - sheet.getRange("C:F").group(Excel.GroupOption.byColumns); - sheet.getRange("H:K").group(Excel.GroupOption.byColumns); - sheet.getRange("M:P").group(Excel.GroupOption.byColumns); - await context.sync(); - }); - } - - async function collapseOutline() { - Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // This collapses the entire outline. - sheet.showOutlineLevels(1, 1); - await context.sync(); - }); - } - - async function expandOutline() { - Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // This shows the top 3 outline levels; collapsing any additional sublevels. - sheet.showOutlineLevels(3, 3); - await context.sync(); - }); - } - - async function ungroup() { - Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // This removes two levels of groups from the "A1-R10" range. - // Any groups at the same level on the same dimension will be removed by a single call. - sheet.getRange("A1:R10").ungroup(Excel.GroupOption.byRows); - sheet.getRange("A1:R10").ungroup(Excel.GroupOption.byRows); - sheet.getRange("A1:R10").ungroup(Excel.GroupOption.byColumns); - sheet.getRange("A1:R10").ungroup(Excel.GroupOption.byColumns); - await context.sync(); - }); - } - - async function setupData() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Category", "Type", "Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4"], - ["Stone Fruit", "Peaches", 500, 2000, 5000, 1500, 600, 2200, 5400, 1300, 300, 1500, 4300, 1200], - [, "Plums", 700, 900, 1300, 800, 800, 1000, 2000, 700, 300, 600, 1100, 700], - ["Citrus", "Lemons", 8000, 3000, 4500, 7500, 8900, 4000, 3500, 4500, 6000, 2500, 4500, 9500], - [, "Limes", 12000, 7000, 8000, 13000, 16000, 10000, 8500, 12000, 11000, 5600, 6500, 11000] - ]; - - sheet.getRange("A3:N7").values = data; - sheet.getRange("A1").values = [["Fruit Sales"]]; - sheet.getRange("A1").style = "Heading1"; - sheet.getRanges("C2:N3,A3:B7").format.font.bold = true; - - sheet.getRange("A1:N7").format.autofitColumns(); - sheet.activate(); - - await context.sync(); - }); - } - - async function setupTotals() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const subtotalColumns = ["G", "L", "Q"]; - const subtotalRows = ["6", "9"]; - let year = 2017; - for (let column of subtotalColumns) { - sheet.getRange(`${column}:${column}`).insert(Excel.InsertShiftDirection.right); - sheet.getRange(`${column}3`).values = [["Year Total"]]; - sheet.getRange(`${column}3`).getRowsAbove(1).values = [[`${year++}`]]; - } - - for (let row of subtotalRows) { - sheet.getRange(`${row}:${row}`).insert(Excel.InsertShiftDirection.down); - sheet.getRange(`B${row}`).values = [["Category Total"]]; - } - - for (let column of subtotalColumns) { - const totalRange = sheet.getRange(`${column}4`); - const precedingRange = totalRange.getColumnsBefore(4); - precedingRange.load("address"); - await context.sync(); - totalRange.formulas = [[`=SUM(${precedingRange.address})`]]; - totalRange.format.font.italic = true; - totalRange.format.fill.color = "LightBlue"; - totalRange.autoFill(`${column}4:${column}9`); - } - - for (let row of subtotalRows) { - const totalRange = sheet.getRange(`C${row}`); - const precedingRange = totalRange.getRowsAbove(2); - precedingRange.load("address"); - await context.sync(); - totalRange.formulas = [[`=SUM(${precedingRange.address})`]]; - totalRange.format.font.italic = true; - totalRange.format.fill.color = "LightBlue"; - totalRange.autoFill(`C${row}:Q${row}`); - } - - sheet.getRange("R3").values = [["Grand Total"]]; - sheet.getRange("R4").formulas = [["=SUM(G4,K4,Q4)"]]; - sheet.getRange("R4").autoFill("R4:R9"); - - sheet.getRange("B10").values = [["Grand Total"]]; - sheet.getRange("C10").formulas = [["=SUM(C6,C9)"]]; - sheet.getRange("C10").autoFill("C10:R10"); - - sheet.getRange("A1:R9").format.autofitColumns(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback, option?) { - try { - await callback(option); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to group and ungroup rows and columns for an outline.

-
- -
-

Set up

- -

- -

- -
-

Try it out

- -

- -

-

Use the Excel UI to expand or collapse parts of the outline. The following buttons will expand or collapse the - entire outline.

- -

- -

-

When you are finished exploring the grouping functionality, use the following button to ungroup the rows and - columns.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/precedents.yaml b/samples/excel/42-range/precedents.yaml deleted file mode 100644 index 26988d156..000000000 --- a/samples/excel/42-range/precedents.yaml +++ /dev/null @@ -1,215 +0,0 @@ -order: 13 -id: excel-precedents -name: Precedents -description: This sample shows how to find and highlight the precedents of the currently selected cell. Precedents are cells referenced by the formula in a cell. -host: EXCEL -api_set: - ExcelApi: '1.14' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#select-first-cell").click(() => tryCatch(selectFirstCell)); - $("#select-second-cell").click(() => tryCatch(selectSecondCell)); - $("#get-direct-precedents").click(() => tryCatch(getDirectPrecedents)); - $("#get-all-precedents").click(() => tryCatch(getAllPrecedents)); - $("#clear-highlighting").click(() => tryCatch(clearFormatting)); - - /** Select a cell with precedents on one worksheet. */ - async function selectFirstCell() { - await Excel.run(async (context) => { - // Ensure correct worksheet is active. - const sheet = context.workbook.worksheets.getItem("Sample2020Data"); - sheet.activate(); - - // Select cell E4. - const range = sheet.getRange("E4"); - range.select(); - await context.sync(); - }); - } - - /** Select a cell with precedents on both worksheets. */ - async function selectSecondCell() { - await Excel.run(async (context) => { - // Ensure correct worksheet is active. - const sheet = context.workbook.worksheets.getItem("Sample2020Data"); - sheet.activate(); - - // Select cell F5. - const range = sheet.getRange("F5"); - range.select(); - await context.sync(); - }); - } - - async function getDirectPrecedents() { - await Excel.run(async (context) => { - // Precedents are cells referenced by the formula in a cell. - // A "direct precedent" is a cell directly referenced by the selected formula. - let range = context.workbook.getActiveCell(); - let directPrecedents = range.getDirectPrecedents(); - range.load("address"); - directPrecedents.areas.load("address"); - await context.sync(); - - console.log(`Direct precedent cells of ${range.address}:`); - - // Use the direct precedents API to loop through precedents of the active cell. - for (let i = 0; i < directPrecedents.areas.items.length; i++) { - // Highlight and console the address of each precedent cell. - directPrecedents.areas.items[i].format.fill.color = "Yellow"; - console.log(` ${directPrecedents.areas.items[i].address}`); - } - await context.sync(); - }); - } - - async function getAllPrecedents() { - await Excel.run(async (context) => { - // Precedents are cells referenced by the formula in a cell. - let range = context.workbook.getActiveCell(); - let precedents = range.getPrecedents(); - range.load("address"); - precedents.areas.load("address"); - await context.sync(); - - console.log(`All precedent cells of ${range.address}:`); - - // Use the precedents API to loop through precedents of the active cell. - for (let i = 0; i < precedents.areas.items.length; i++) { - // Highlight and console the address of each precedent cell. - precedents.areas.items[i].format.fill.color = "Orange"; - console.log(` ${precedents.areas.items[i].address}`); - } - await context.sync(); - }); - } - - /** Remove highlighting from precedent cells. */ - async function clearFormatting() { - await Excel.run(async (context) => { - const sheet1 = context.workbook.worksheets.getItem("Sample2019Data"); - let range1 = sheet1.getRange("B3:F5"); - range1.format.fill.clear(); - - const sheet2 = context.workbook.worksheets.getItem("Sample2020Data"); - let range2 = sheet2.getRange("B3:E5"); - range2.format.fill.clear(); - - await context.sync(); - }); - } - - /** Create two sample tables with methods that span the tables. */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample2019Data").delete(); - context.workbook.worksheets.getItemOrNullObject("Sample2020Data").delete(); - - // Set up the first sample table. - const sheet1 = context.workbook.worksheets.add("Sample2019Data"); - const data1 = [ - ["Product", "Qty", "Unit Price", "Total Price 2019"], - ["Almonds", 2, 7.5, "=C3 * D3"], - ["Coffee", 1, 34.5, "=C4 * D4"], - ["Chocolate", 5, 9.56, "=C5 * D5"] - ]; - - const range1 = sheet1.getRange("B2:E5"); - range1.values = data1; - range1.format.autofitColumns(); - - // Set up the second sample table. - const sheet2 = context.workbook.worksheets.add("Sample2020Data"); - const data2 = [ - ["Product", "Qty", "Unit Price", "Total Price 2020", "Average Annual Price"], - ["Almonds", 2, 8.0, "=C3 * D3", "=Sample2019Data!E3 + E3 / 2"], - ["Coffee", 1, 36.5, "=C4 * D4", "=Sample2019Data!E4 + E4 / 2"], - ["Chocolate", 5, 11.2, "=C5 * D5", "=Sample2019Data!E5 + E5 / 2"] - ]; - - const range2 = sheet2.getRange("B2:F5"); - range2.values = data2; - range2.format.autofitColumns(); - - // Style the tables. - const header1 = range1.getRow(0); - header1.format.fill.color = "#4472C4"; - header1.format.font.color = "white"; - - const header2 = range2.getRow(0); - header2.format.fill.color = "#4472C4"; - header2.format.font.color = "white"; - - sheet2.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to find and highlight the precedents of the currently selected cell.

-

Precedents are cells referenced by the formula in a cell. A formula can also reference a cell that contains a formula, which results in a series of precedents. A "direct precedent" is a cell directly referenced by the selected formula. This sample shows how to return both the direct precedents and all of the precedents.

-
-
-

Set up

- -
-
-

Try it out

- - - - - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/range-areas.yaml b/samples/excel/42-range/range-areas.yaml deleted file mode 100644 index cfbff6ec9..000000000 --- a/samples/excel/42-range/range-areas.yaml +++ /dev/null @@ -1,184 +0,0 @@ -order: 3 -id: excel-range-areas -name: Discontiguous ranges (RangeAreas) and special cells -description: 'Creates and uses RangeAreas, which are sets of ranges that need not be contiguous, through user selection and programmatic selection of special cells.' -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#reset").click(() => tryCatch(reset)); - $("#color-selected-ranges").click(() => tryCatch(colorSelectedRanges)); - $("#color-specified-ranges").click(() => tryCatch(colorSpecifiedRanges)); - $("#color-all-formula-ranges").click(() => tryCatch(colorAllFormulaRanges)); - $("#color-all-logical-text-ranges").click(() => tryCatch(colorAllLogicalAndTextRanges)); - $("#read-properties-specified-ranges").click(() => tryCatch(readPropertiesOfSpecifiedRanges)); - - async function colorSelectedRanges() { - await Excel.run(async (context) => { - - const selectedRanges = context.workbook.getSelectedRanges(); - selectedRanges.format.fill.color = "lightblue"; - - await context.sync(); - }) - } - - async function colorSpecifiedRanges() { - await Excel.run(async (context) => { - - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const specifiedRanges = sheet.getRanges("D3:D5, G3:G5"); - specifiedRanges.format.fill.color = "pink"; - - await context.sync(); - }) - } - - async function colorAllFormulaRanges() { - await Excel.run(async (context) => { - - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const usedRange = sheet.getUsedRange(); - - // Find the ranges with formulas. - const formulaRanges = usedRange.getSpecialCells("Formulas"); - formulaRanges.format.fill.color = "lightgreen"; - - await context.sync(); - }); - } - - async function colorAllLogicalAndTextRanges() { - await Excel.run(async (context) => { - - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const usedRange = sheet.getUsedRange(); - - // Find the ranges with either text or logical (boolean) values. - const formulaRanges = usedRange.getSpecialCells("Constants", "LogicalText"); - formulaRanges.format.fill.color = "orange"; - - return context.sync(); - }); - } - - async function readPropertiesOfSpecifiedRanges() { - await Excel.run(async (context) => { - - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const specifiedRanges = sheet.getRanges("C3:C5, E3:E5"); - specifiedRanges.load("format/fill/color, isEntireColumn, address, areaCount"); - - await context.sync() - - // Non-boolean properties return null unless the - // property value on all member ranges is the same. - // (RangeAreas.address is an exception.) - console.log("Color is: " + specifiedRanges.format.fill.color); - - // Boolean properties return false unless the - // property is true on ALL member ranges. - console.log("Each range is an entireColumn: " + specifiedRanges.isEntireColumn); - - // Returns a comma-delimited string of all the - // addresses of the member ranges. - console.log("Range addresses: " + specifiedRanges.address); - console.log("Number of ranges: " + specifiedRanges.areaCount); - - await context.sync(); - }); - } - - async function reset() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Product", "Qty", "Category", "Unit Price", "Base Price", "Tax", "Total Charge", "Manager's Discount", "Final Price"], - ["Almonds", 2, "Nuts", 7.50, "=C3 * E3", 0.1, "=SUM(F3,F3 * G3)", false, "=IF(I3 = TRUE, H3 * 0.9, H3)"], - ["Coffee", 1, "Beverage", 34.50, "=C4 * E4", 0.0, "=SUM(F4,F4 * G4)", true, "=IF(I4 = TRUE, H4 * 0.9, H4)"], - ["Chocolate", 5, "Candy", 9.56, "=C5 * E5", 0.2, "=SUM(F5,F5 * G5)", false, "=IF(I5 = TRUE, H5 * 0.9, H5)"] - ]; - - const range = sheet.getRange("B2:J5"); - range.values = data; - range.format.autofitColumns(); - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to apply actions simultaneously to multiple, discontiguous ranges. Some of these ranges are found using the Range object's getSpecialCells method.

-
- -
-

Set up

- -

Try it out

-

Select two or more ranges on the Sample worksheet. It doesn't matter if they have data or are contiguous. Then press Color selected ranges.

- -

Press the next button to color ranges that are specified by hard-coded addresses in the JavaScript.

- -

Add a formula to any cells you want on the Sample worksheet and press the next button.

- -

Add text to any cells and add a logical (Boolean) value to any cells on the Sample worksheet and press the next button.

- -

In Excel, select range C3:C5 and format its fill to a new color. Then set the fill for range E3:E5 to exactly the same color! Then press "Read properties of Qty and Unit Price ranges". Watch the console.

-

Next, change the fill color of one of the two ranges and press the button again.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/range-auto-fill.yaml b/samples/excel/42-range/range-auto-fill.yaml deleted file mode 100644 index c6042f1d1..000000000 --- a/samples/excel/42-range/range-auto-fill.yaml +++ /dev/null @@ -1,156 +0,0 @@ -order: 1 -id: excel-range-auto-fill -name: Auto fill -description: Writes to cells with the auto fill feature. -host: EXCEL -api_set: - ExcelApi: '1.10' -script: - content: | - $("#setup-data").click(() => tryCatch(setupData)); - $("#setup-first-sums").click(() => tryCatch(setupFirstSums)); - $("#auto-fill-values").click(() => tryCatch(autoFillValues)); - $("#auto-fill-formats").click(() => tryCatch(autoFillFormats)); - $("#auto-fill-copy").click(() => tryCatch(autoFillCopy)); - - async function autoFillValues() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const sumCell = sheet.getRange("F4"); - - // Copy only the values and formulas, not the formatting. The formulas will be contextually updated based on their new locations. - sumCell.autoFill("F4:F7", Excel.AutoFillType.fillValues); - sumCell.format.autofitColumns(); - await context.sync(); - }); - } - - async function autoFillFormats() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const sumCell = sheet.getRange("K4"); - - // Copy only the formatting, not the values and formulas. - sumCell.autoFill("K4:K7", Excel.AutoFillType.fillFormats); - sumCell.format.autofitColumns(); - await context.sync(); - }); - } - - async function autoFillCopy() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const sumCell = sheet.getRange("P4"); - - // Copy everything. The formulas will be contextually updated based on their new locations. - sumCell.autoFill("P4:P7", Excel.AutoFillType.fillCopy); - sumCell.format.autofitColumns(); - await context.sync(); - }); - } - - async function setupData() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Fruit", "Q1", "Q2", "Q3", "Q4", 2017, "Q1", "Q2", "Q3", "Q4", 2018, "Q1", "Q2", "Q3", "Q4", 2019], - ["Quinces", 500, 2000, 5000, 1500, , 600, 2200, 5400, 1300, , 300, 1500, 4300, 1200, ""], - ["Plums", 700, 900, 1300, 800, , 800, 1000, 2000, 700, , 300, 600, 1100, 700, ""], - ["Apples", 8000, 3000, 4500, 7500, , 8900, 4000, 3500, 4500, , 6000, 2500, 4500, 9500, ""], - ["Peaches", 12000, 7000, 8000, 13000, , 16000, 10000, 8500, 12000, , 11000, 5600, 6500, 11000, ""] - ]; - - sheet.getRange("A3:P7").values = data; - sheet.getRange("A1").values = [["Fruit Sales"]]; - sheet.getRange("A1").style = "Heading1"; - sheet.getRanges("B2:P3,A3:A7").format.font.bold = true; - - sheet.getRange("A1:P7").format.autofitColumns(); - sheet.activate(); - - await context.sync(); - }); - } - - async function setupFirstSums() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const sumRange = sheet.getRange("F4"); - sumRange.formulas = [["=SUM(B4:E4)"]]; - sumRange.format.fill.color = "LightBlue"; - sumRange.format.font.bold = true; - sheet.getRanges("K4,P4").copyFrom("F4", Excel.RangeCopyType.all); - sheet.getRanges("F4,K4,P4").format.autofitColumns(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback, option?) { - try { - await callback(option); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to provide cell data for surrounding cells using auto fill.

-
- -
-

Set up

- -

- -

- -
-

Try it out

- -

- -

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/range-copyfrom.yaml b/samples/excel/42-range/range-copyfrom.yaml deleted file mode 100644 index 0db6cc1ac..000000000 --- a/samples/excel/42-range/range-copyfrom.yaml +++ /dev/null @@ -1,225 +0,0 @@ -order: 2 -id: excel-range-copyfrom -name: Copy and paste ranges -description: Copies or moves data and formatting from one range to another. -host: EXCEL -api_set: - ExcelApi: '1.10' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#copyAll").click(() => tryCatch(copyAll)); - $("#copyFormula").click(() => tryCatch(copyFormula)); - $("#copyFormulaResult").click(() => tryCatch(copyFormulaResult)); - $("#copySingleAcrossRange").click(() => tryCatch(copySingleAcrossRange)); - $("#copyOnlyFormat").click(() => tryCatch(copyOnlyFormat)); - $("#skipBlanks").click(() => tryCatch(skipBlanks)); - $("#transpose").click(() => tryCatch(transpose)); - $("#move").click(() => tryCatch(move)); - - async function copyAll() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - // Place a label in front of the copied data. - sheet.getRange("F1").values = [["Copied Range"]]; - - // Copy a range starting at a single cell destination. - sheet.getRange("G1").copyFrom("A1:E1"); - await context.sync(); - }); - } - - async function copyFormula() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - // Place a label in front of the copied data. - sheet.getRange("F2").values = [["Copied Formula"]]; - - // Copy a range preserving the formulas. - // Note: non-formula values are copied over as is. - sheet.getRange("G2").copyFrom("A1:E1", Excel.RangeCopyType.formulas); - await context.sync(); - }); - } - - async function copyFormulaResult() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - // Place a label in front of the copied data. - sheet.getRange("F3").values = [["Copied Formula Result"]]; - - // Copy the resulting value of a formula. - sheet.getRange("G3").copyFrom("E1", Excel.RangeCopyType.values); - await context.sync(); - }); - } - - async function copySingleAcrossRange() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - // Place a label in front of the copied data. - sheet.getRange("F4").values = [["Single Source"]]; - - // Copy a single cell across an entire range. - sheet.getRange("G4:K4").copyFrom("A1", Excel.RangeCopyType.values); - await context.sync(); - }); - } - - async function copyOnlyFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - // Place a label in front of the copied data. - sheet.getRange("F5").values = [["Copied Formatting"]]; - - // Copy only the formatting of the cells. - sheet.getRange("G5").copyFrom("A1:E1", Excel.RangeCopyType.formats); - await context.sync(); - }); - } - - async function skipBlanks() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - // Place a label in front of the copied data. - sheet.getRange("F6").values = [["Copied Without Blanks"]]; - - // Fill the destination range so we can see the blank being skipped. - sheet.getRange("G6:K6").values = [["Old Data", "Old Data", "Old Data", "Old Data", "Old Data"]] - - // Copy a range, omitting the blank cells so existing data is not overwritten in those cells. - sheet.getRange("G6").copyFrom("A1:E1", - Excel.RangeCopyType.all, - true, // skipBlanks - false); // transpose - await context.sync(); - }); - } - - async function transpose() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - // Place a label in front of the transposed data. - sheet.getRange("F7").values = [["Transpose"]]; - - // Transpose a horizontal range of data into a vertical range. - sheet.getRange("G7").copyFrom("A1:E1", - Excel.RangeCopyType.all, - false, // skipBlanks - true); // transpose - await context.sync(); - }); - } - - async function move() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - // Place a label in front of the moved data. - sheet.getRange("F12").values = [["Moved Range:"]]; - - // Move the range from A1:E1 to G12:K12. - sheet.getRange("A1:E1").moveTo("G12"); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - - const sheet = context.workbook.worksheets.add("Sample"); - sheet.getRange("A1:D1").values = [["3", "5", "7", ""]]; - sheet.getRange("A1:D1").format.font.italic = true; - sheet.getRange("A1:D1").format.font.color = "DarkMagenta"; - sheet.getRange("E1").formulas = [["=SUM(A1:D1)"]]; - sheet.getRange("E1").format.font.bold = true; - sheet.getRange("E1").format.fill.color = "LightGreen"; - sheet.getRange("F1").format.columnWidth = 120; - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to copy data and formatting from one range (A1:E1) to another.

-
-
-

Setup

- -
-
-

Try it out

- -

- -

- -

- -

- -

- -

- -

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/range-dependents.yaml b/samples/excel/42-range/range-dependents.yaml deleted file mode 100644 index b79542f62..000000000 --- a/samples/excel/42-range/range-dependents.yaml +++ /dev/null @@ -1,174 +0,0 @@ -order: 22 -id: excel-range-dependents -name: Dependents -description: This sample shows how to find and highlight the dependents of the currently selected cell. Dependent cells contain formulas that refer to other cells. -host: EXCEL -api_set: - ExcelAPI: '1.15' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#select-D3").click(() => tryCatch(selectD3)); - $("#get-all-dependents").click(() => tryCatch(getAllDependents)); - $("#clear-highlighting").click(() => tryCatch(clearFormatting)); - - async function selectD3() { - // This function selects a cell with dependents across both worksheets. - await Excel.run(async (context) => { - // Activate the sample worksheet. - const sheet = context.workbook.worksheets.getItem("Sample2019Data"); - sheet.activate(); - - // Select cell D3. - const range = sheet.getRange("D3"); - range.select(); - await context.sync(); - }); - } - - async function getAllDependents() { - // This function highlights all the dependent cells of the active cell. - // Dependent cells contain formulas that refer to other cells. - await Excel.run(async (context) => { - // Get addresses of the active cell's dependent cells. - const range = context.workbook.getActiveCell(); - const dependents = range.getDependents(); - range.load("address"); - dependents.areas.load("address"); - await context.sync(); - - console.log(`All dependent cells of ${range.address}:`); - - // Use the dependents API to loop through dependents of the active cell. - for (let i = 0; i < dependents.areas.items.length; i++) { - // Highlight and print out the address of each dependent cell. - dependents.areas.items[i].format.fill.color = "Orange"; - console.log(` ${dependents.areas.items[i].address}`); - } - await context.sync(); - }); - } - - async function clearFormatting() { - // This function removes highlighting from dependent cells. - await Excel.run(async (context) => { - const sheet1 = context.workbook.worksheets.getItem("Sample2019Data"); - const range1 = sheet1.getRange("B3:E5"); - range1.format.fill.clear(); - - const sheet2 = context.workbook.worksheets.getItem("Sample2020Data"); - const range2 = sheet2.getRange("B3:F5"); - range2.format.fill.clear(); - - await context.sync(); - }); - } - - /** Create two sample tables on different worksheets, with functions that span the tables. */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample2019Data").delete(); - context.workbook.worksheets.getItemOrNullObject("Sample2020Data").delete(); - - // Set up the first sample table. - const sheet1 = context.workbook.worksheets.add("Sample2019Data"); - const data1 = [ - ["Product", "Qty", "Unit Price", "Total Price 2019"], - ["Almonds", 2, 7.5, "=C3 * D3"], - ["Coffee", 1, 34.5, "=C4 * D4"], - ["Chocolate", 5, 9.56, "=C5 * D5"] - ]; - - const range1 = sheet1.getRange("B2:E5"); - range1.values = data1; - range1.format.autofitColumns(); - - // Set up the second sample table. - const sheet2 = context.workbook.worksheets.add("Sample2020Data"); - const data2 = [ - ["Product", "Qty", "Unit Price", "Total Price 2020", "Average Annual Price"], - ["Almonds", 2, 8.0, "=C3 * D3", "=Sample2019Data!E3 + E3 / 2"], - ["Coffee", 1, 36.5, "=C4 * D4", "=Sample2019Data!E4 + E4 / 2"], - ["Chocolate", 5, 11.2, "=C5 * D5", "=Sample2019Data!E5 + E5 / 2"] - ]; - - const range2 = sheet2.getRange("B2:F5"); - range2.values = data2; - range2.format.autofitColumns(); - - // Style the tables. - const header1 = range1.getRow(0); - header1.format.fill.color = "#4472C4"; - header1.format.font.color = "white"; - - const header2 = range2.getRow(0); - header2.format.fill.color = "#4472C4"; - header2.format.font.color = "white"; - - sheet2.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to find and highlight the dependents of the currently selected cell.

-

Dependent cells contain formulas that refer to other cells.

-
-
-

Set up

- -
-
-

Try it out

-

Cell D3 has dependents across worksheets.

- - - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/range-direct-dependents.yaml b/samples/excel/42-range/range-direct-dependents.yaml deleted file mode 100644 index 27f0ce290..000000000 --- a/samples/excel/42-range/range-direct-dependents.yaml +++ /dev/null @@ -1,169 +0,0 @@ -order: 21 -id: excel-direct-dependents -name: Direct dependents -description: This sample shows how to find and highlight the direct dependents of the currently selected cell. Dependent cells contain formulas that refer to other cells. -host: EXCEL -api_set: - ExcelAPI: '1.13' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#select-D3").click(() => tryCatch(selectD3)); - $("#select-E4").click(() => tryCatch(selectE4)); - $("#get-direct-dependents").click(() => tryCatch(getDirectDependents)); - - /** Select a cell with direct dependents on the same worksheet. */ - async function selectD3() { - await Excel.run(async (context) => { - // Activate the sample worksheet. - const sheet = context.workbook.worksheets.getItem("Sample2019Data"); - sheet.activate(); - - // Select cell D3. - const range = sheet.getRange("D3"); - range.select(); - await context.sync(); - }); - } - - /** Select a cell with direct dependents across worksheets. */ - async function selectE4() { - await Excel.run(async (context) => { - // Activate the sample worksheet. - const sheet = context.workbook.worksheets.getItem("Sample2019Data"); - sheet.activate(); - - // Select cell E4. - const range = sheet.getRange("E4"); - range.select(); - await context.sync(); - }); - } - - async function getDirectDependents() { - await Excel.run(async (context) => { - // Direct dependents are cells that contain formulas that refer to other cells. - let range = context.workbook.getActiveCell(); - let directDependents = range.getDirectDependents(); - range.load("address"); - directDependents.areas.load("address"); - await context.sync(); - - console.log(`Direct dependent cells of ${range.address}:`); - - // Use the direct dependents API to loop through direct dependents of the active cell. - for (let i = 0; i < directDependents.areas.items.length; i++) { - // Highlight and print the address of each dependent cell. - directDependents.areas.items[i].format.fill.color = "Yellow"; - console.log(` ${directDependents.areas.items[i].address}`); - } - await context.sync(); - }); - } - - /** Create two sample tables on different worksheets with methods that span the tables. */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample2019Data").delete(); - context.workbook.worksheets.getItemOrNullObject("Sample2020Data").delete(); - - // Set up the first sample table. - const sheet1 = context.workbook.worksheets.add("Sample2019Data"); - const data1 = [ - ["Product", "Qty", "Unit Price", "Total Price 2019"], - ["Almonds", 2, 7.5, "=C3 * D3"], - ["Coffee", 1, 34.5, "=C4 * D4"], - ["Chocolate", 5, 9.56, "=C5 * D5"] - ]; - - const range1 = sheet1.getRange("B2:E5"); - range1.values = data1; - range1.format.autofitColumns(); - - // Set up the second sample table. - const sheet2 = context.workbook.worksheets.add("Sample2020Data"); - const data2 = [ - ["Product", "Qty", "Unit Price", "Total Price 2020", "Average Annual Price"], - ["Almonds", 2, 8.0, "=C3 * D3", "=Sample2019Data!E3 + E3 / 2"], - ["Coffee", 1, 36.5, "=C4 * D4", "=Sample2019Data!E4 + E4 / 2"], - ["Chocolate", 5, 11.2, "=C5 * D5", "=Sample2019Data!E5 + E5 / 2"] - ]; - const range2 = sheet2.getRange("B2:F5"); - range2.values = data2; - range2.format.autofitColumns(); - - // Style the tables. - const header1 = range1.getRow(0); - header1.format.fill.color = "#4472C4"; - header1.format.font.color = "white"; - const header2 = range2.getRow(0); - header2.format.fill.color = "#4472C4"; - header2.format.font.color = "white"; - sheet2.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to find and highlight the dependents of the currently selected cell. Dependent cells contain formulas that refer to other cells.

-
- -
-

Set up

- -
- -
-

Try it out

-

Cells in the 'E' column have direct dependents on the same worksheet. Cells in the 'F' column have direct dependents on another worksheet.

- -
- -
- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/range-find.yaml b/samples/excel/42-range/range-find.yaml deleted file mode 100644 index 5037390c8..000000000 --- a/samples/excel/42-range/range-find.yaml +++ /dev/null @@ -1,171 +0,0 @@ -order: 4 -id: excel-range-find -name: Find text matches within a range -description: Finds a cell within a range based on string matching. -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - $("#findText").click(() => tryCatch(findText)); - $("#findTextWithNullCheck").click(() => tryCatch(findTextWithNullCheck)); - $("#toggleComplete").click(() => tryCatch(toggleComplete)); - $("#toggleCase").click(() => tryCatch(toggleCase)); - $("#toggleDirection").click(() => tryCatch(toggleDirection)); - - let isCompleteMatchToggle = false; - let isMatchCaseToggle = false; - let searchDirectionToggle = Excel.SearchDirection.forward; - - async function findText() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const table = sheet.tables.getItem("ExpensesTable"); - const searchRange = table.getRange(); - - // NOTE: If no match is found, an ItemNotFound error - // is thrown when Range.find is evaluated. - const foundRange = searchRange.find($("#searchText").val().toString(), { - completeMatch: isCompleteMatchToggle, - matchCase: isMatchCaseToggle, - searchDirection: searchDirectionToggle - }); - - foundRange.load("address"); - await context.sync(); - - - console.log(foundRange.address); - }); - } - - async function findTextWithNullCheck() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const table = sheet.tables.getItem("ExpensesTable"); - const searchRange = table.getRange(); - const foundRange = searchRange.findOrNullObject($("#searchText").val().toString(), { - completeMatch: isCompleteMatchToggle, - matchCase: isMatchCaseToggle, - searchDirection: searchDirectionToggle - }); - - foundRange.load("address"); - await context.sync(); - - if (foundRange.isNullObject) { - console.log("Text not found"); - } else { - console.log(foundRange.address); - } - }); - } - - function toggleComplete() { - isCompleteMatchToggle = !isCompleteMatchToggle; - console.log("Finding complete match = " + isCompleteMatchToggle); - } - - function toggleCase() { - isMatchCaseToggle = !isMatchCaseToggle; - console.log("Finding matched case = " + isMatchCaseToggle); - } - - function toggleDirection() { - searchDirectionToggle = searchDirectionToggle === Excel.SearchDirection.forward ? Excel.SearchDirection.backwards : Excel.SearchDirection.forward; - console.log("Search direction = " + searchDirectionToggle); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const expensesTable = sheet.tables.add("A1:D1", true /*hasHeaders*/); - expensesTable.name = "ExpensesTable"; - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - expensesTable.rows.add(null /*add at the end*/, [ - ["1/1/2017", "The Phone Company", "Communications", "$120"], - ["1/2/2017", "Northwind Electric Cars", "Transportation", "$142"], - ["1/5/2017", "Best For You Organics Company", "Groceries", "$27"], - ["1/10/2017", "Coho Vineyard", "Restaurant", "$33"], - ["1/11/2017", "The Phone Company", "communications", "$5"], - ["1/15/2017", "Coho Vineyard (Wine)", "Groceries", "$60"], - ["1/15/2017", "Best For You Organics Company", "Groceries", "$97"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to find a cell with a matching string value within a range.

-
-
-

Setup

- -
-
-

Try it out

-

Enter text to search for in the box below and press Find text or Find text with null check to display the found text's address in the console.

-

-

-

-

Toggle the following search options to test different search behaviors.

-

-

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/range-get-range-edge.yaml b/samples/excel/42-range/range-get-range-edge.yaml deleted file mode 100644 index a16b965c3..000000000 --- a/samples/excel/42-range/range-get-range-edge.yaml +++ /dev/null @@ -1,232 +0,0 @@ -order: 20 -id: excel-range-get-range-edge -name: Select used range edge -description: 'This sample shows how to select the edges of the used range, based on the currently selected range.' -host: EXCEL -api_set: - ExcelAPI: '1.13' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#select-E9").click(() => tryCatch(selectE9)); - $("#select-D8-E9").click(() => tryCatch(selectD8E9)); - $("#get-range-edge-left").click(() => tryCatch(getRangeEdgeLeft)); - $("#get-range-edge-up").click(() => tryCatch(getRangeEdgeUp)); - $("#get-extended-range-right").click(() => tryCatch(getExtendedRangeRight)); - $("#get-extended-range-down").click(() => tryCatch(getExtendedRangeDown)); - - async function getRangeEdgeLeft() { - await Excel.run(async (context) => { - // Get the selected range. - const range = context.workbook.getSelectedRange(); - - // Get the active cell in the workbook. - const activeCell = context.workbook.getActiveCell(); - - // Get the left-most cell of the current used range. - // This method acts like the Ctrl+Arrow key keyboard shortcut while a range is selected. - const rangeEdge = range.getRangeEdge( - "Left", // Specify the direction as a string. - activeCell // If the selected range contains more than one cell, the active cell must be defined. - ); - - // Select the edge of the range. - rangeEdge.select(); - - await context.sync(); - }); - } - - async function getRangeEdgeUp() { - await Excel.run(async (context) => { - // Get the selected range. - const range = context.workbook.getSelectedRange(); - - // Specify the direction with the `KeyboardDirection` enum. - const direction = Excel.KeyboardDirection.up; - - // Get the active cell in the workbook. - const activeCell = context.workbook.getActiveCell(); - - // Get the top-most cell of the current used range. - // This method acts like the Ctrl+Arrow key keyboard shortcut while a range is selected. - const rangeEdge = range.getRangeEdge( - direction, - activeCell // If the selected range contains more than one cell, the active cell must be defined. - ); - rangeEdge.select(); - - await context.sync(); - }); - } - - async function getExtendedRangeRight() { - await Excel.run(async (context) => { - // Get the selected range. - const range = context.workbook.getSelectedRange(); - - // Get the active cell in the workbook. - const activeCell = context.workbook.getActiveCell(); - - // Get all the cells from the currently selected range to the right-most edge of the used range. - // This method acts like the Ctrl+Shift+Arrow key keyboard shortcut while a range is selected. - const extendedRange = range.getExtendedRange( - "Right", // Specify the direction as a string. - activeCell // If the selected range contains more than one cell, the active cell must be defined. - ); - extendedRange.select(); - - await context.sync(); - }); - } - - async function getExtendedRangeDown() { - await Excel.run(async (context) => { - // Get the selected range. - const range = context.workbook.getSelectedRange(); - - // Specify the direction with the `KeyboardDirection` enum. - const direction = Excel.KeyboardDirection.down; - - // Get the active cell in the workbook. - const activeCell = context.workbook.getActiveCell(); - - // Get all the cells from the currently selected range to the bottom-most edge of the used range. - // This method acts like the Ctrl+Shift+Arrow key keyboard shortcut while a range is selected. - const extendedRange = range.getExtendedRange( - direction, - activeCell // If the selected range contains more than one cell, the active cell must be defined. - ); - extendedRange.select(); - - await context.sync(); - }); - } - - /** Select a range with one cell. */ - async function selectE9() { - await Excel.run(async (context) => { - // Get the active worksheet. - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // Select cell E9. - const range = sheet.getRange("E9"); - range.select(); - await context.sync(); - }); - } - - /** Select a range with multiple cells. */ - async function selectD8E9() { - await Excel.run(async (context) => { - // Get the active worksheet. - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // Select range D8:E9. - const range = sheet.getRange("D8:E9"); - range.select(); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const expensesTable = sheet.tables.add("C5:F5", true /*hasHeaders*/); - expensesTable.name = "ExpensesTable"; - - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - - expensesTable.rows.add(null /*add at the end*/, [ - ["1/1/2017", "The Phone Company", "Communications", "$120"], - ["1/2/2017", "Northwind Electric Cars", "Transportation", "$142"], - ["1/5/2017", "Best For You Organics Company", "Groceries", "$27"], - ["1/10/2017", "Coho Vineyard", "Restaurant", "$33"], - ["1/11/2017", "Bellows College", "Education", "$350"], - ["1/15/2017", "Trey Research", "Other", "$135"], - ["1/15/2017", "Best For You Organics Company", "Groceries", "$97"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to select the edges of the used range, based on the currently selected range.

-
-
-

Set up

- -
- -
-

Try it out

- - -
-

The first type of range edge selection selects the cell at the furthest edge of the current used range, in the directions up or left. This action matches the result of using the Ctrl+Arrow key keyboard shortcut while a range is selected.

- - -
-

The second type of range edge selection selects all the cells from the currently selected range to the furthest edge of the used range, in the directions right or down. This action matches the result of using the Ctrl+Shift+Arrow key keyboard shortcut while a range is selected.

- - -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/range-hyperlink.yaml b/samples/excel/42-range/range-hyperlink.yaml deleted file mode 100644 index 1f7f91207..000000000 --- a/samples/excel/42-range/range-hyperlink.yaml +++ /dev/null @@ -1,327 +0,0 @@ -order: 7 -id: excel-range-hyperlink -name: Hyperlinks -description: 'Creates, updates, and clears hyperlinks in a range.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - - $("#create-url-hyperlinks").click(() => tryCatch(createUrlHyperlinks)); - $("#create-document-hyperlinks").click(() => tryCatch(createDocumentHyperlinks)); - $("#update-hyperlinks").click(() => tryCatch(updateHyperlinks)); - $("#clear-hyperlinks").click(() => tryCatch(clearHyperlinks)); - - async function createUrlHyperlinks() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Orders"); - - let productsRange = sheet.getRange("A3:A5"); - productsRange.load("values"); - - await context.sync(); - - // Create a hyperlink to a URL - // for each product name in the first table. - for (let i = 0; i < productsRange.values.length; i++) { - let cellRange = productsRange.getCell(i, 0); - let cellText = productsRange.values[i][0]; - - let hyperlink = { - textToDisplay: cellText, - screenTip: "Search Bing for '" + cellText + "'", - address: "https://www.bing.com/?q=" + cellText - } - cellRange.hyperlink = hyperlink; - } - - await context.sync(); - }); - } - - async function createDocumentHyperlinks() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Orders"); - - let productsRange = sheet.getRange("A9:A11"); - productsRange.load("values"); - - await context.sync(); - - // Create a hyperlink to a location within the workbook - // for each product name in the second table. - for (let i = 0; i < productsRange.values.length; i++) { - let cellRange = productsRange.getCell(i, 0); - let cellText = productsRange.values[i][0]; - - let hyperlink = { - textToDisplay: cellText, - screenTip: "Navigate to the '" + cellText + "' worksheet", - documentReference: cellText + "!A1" - } - cellRange.hyperlink = hyperlink; - } - - await context.sync(); - }); - } - - async function updateHyperlinks() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Orders"); - - let productsRange = sheet.getRange("A3:A5"); - productsRange.load("values"); - - await context.sync(); - - // Update the hyperlink screen tip and address - // for each product name in the first table. - for (let i = 0; i < productsRange.values.length; i++) { - let cellRange = productsRange.getCell(i, 0); - let cellText = productsRange.values[i][0]; - - let hyperlink = { - textToDisplay: cellText, - screenTip: "View Wikipedia page for '" + cellText + "'", - address: "https://wikipedia.org/wiki/" + cellText - } - cellRange.hyperlink = hyperlink; - } - - await context.sync(); - - console.log("Updated the hyperlink for each of the products in the first table."); - }); - } - - async function clearHyperlinks() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Orders"); - - const productsRange = sheet.getRange("A3:A11"); - productsRange.load("values"); - - await context.sync(); - - // Clear all hyperlinks. - for (let i = 0; i < productsRange.values.length; i++) { - let cellRange = productsRange.getCell(i, 0); - - // Clear the hyperlink. - // This eliminates the hyperlink but does not update text format. - cellRange.clear(Excel.ClearApplyTo.hyperlinks); - - // Update text format. - cellRange.format.font.underline = Excel.RangeUnderlineStyle.none; - cellRange.format.font.color = "#000000"; - } - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Orders").delete(); - const ordersSheet = context.workbook.worksheets.add("Orders"); - - context.workbook.worksheets.getItemOrNullObject("Apple").delete(); - const appleSheet = context.workbook.worksheets.add("Apple"); - - context.workbook.worksheets.getItemOrNullObject("Banana").delete(); - const bananaSheet = context.workbook.worksheets.add("Banana"); - - context.workbook.worksheets.getItemOrNullObject("Melon").delete(); - const melonSheet = context.workbook.worksheets.add("Melon"); - - createOrdersData(ordersSheet); - createAppleData(appleSheet); - createBananaData(bananaSheet); - createMelonData(melonSheet); - - ordersSheet.activate(); - await context.sync(); - }); - } - - function createOrdersData(ordersSheet: Excel.Worksheet) { - const productsData1 = [ - ["Vegetable", "Qty", "Unit Price", "Total Price"], - ["Potato", 10, 1.00, "=B3 * C3"], - ["Tomato", 7, 2.50, "=B4 * C4"], - ["Lettuce", 5, 1.50, "=B5 * C5"] - ]; - - const range1 = ordersSheet.getRange("A2:D5"); - range1.values = productsData1; - range1.format.autofitColumns(); - range1.format.fill.color = "lightgray"; - - const header1 = range1.getResizedRange(-3, 0); - header1.format.fill.color = "lightblue"; - header1.format.font.bold = true; - - const productsData2 = [ - ["Fruit", "Qty", "Unit Price", "Total Price"], - ["Apple", 10, 2.00, "=B9 * C9"], - ["Banana", 5, 0.75, "=B10 * C10"], - ["Melon", 8, 3.50, "=B11 * C11"] - ]; - - const range2 = ordersSheet.getRange("A8:D11"); - range2.values = productsData2; - range2.format.autofitColumns(); - range2.format.fill.color = "lightgray"; - - const header2 = range2.getResizedRange(-3, 0); - header2.format.fill.color = "lightblue"; - header2.format.font.bold = true; - } - - function createAppleData(appleSheet: Excel.Worksheet) { - const applesData = [ - ["Month", "Apples sold"], - ["January 2016", 100], - ["February 2016", 50], - ["March 2016", 200], - ["April 2016", 75], - ["May 2016", 150], - ["June 2016", 190], - ["July 2016", 200], - ["August 2016", 115], - ["September 2016", 80], - ["October 2016", 70], - ["November 2016", 160], - ["December 2016", 195] - ]; - - const range = appleSheet.getRange("A1:B13"); - range.values = applesData; - range.format.autofitColumns(); - - const header = range.getResizedRange(-12, 0); - header.format.fill.color = "pink"; - header.format.font.bold = true; - } - - function createBananaData(bananaSheet: Excel.Worksheet) { - const bananasData = [ - ["Month", "Bananas sold"], - ["January 2016", 175], - ["February 2016", 250], - ["March 2016", 300], - ["April 2016", 175], - ["May 2016", 50], - ["June 2016", 95], - ["July 2016", 270], - ["August 2016", 150], - ["September 2016", 85], - ["October 2016", 125], - ["November 2016", 160], - ["December 2016", 175] - ]; - - const range = bananaSheet.getRange("A1:B13"); - range.values = bananasData; - range.format.autofitColumns(); - - const header = range.getResizedRange(-12, 0); - header.format.fill.color = "yellow"; - header.format.font.bold = true; - } - - function createMelonData(melonSheet: Excel.Worksheet) { - const melonsData = [ - ["Month", "Melons sold"], - ["January 2016", 275], - ["February 2016", 180], - ["March 2016", 350], - ["April 2016", 125], - ["May 2016", 250], - ["June 2016", 195], - ["July 2016", 170], - ["August 2016", 350], - ["September 2016", 185], - ["October 2016", 225], - ["November 2016", 260], - ["December 2016", 275] - ]; - - const range = melonSheet.getRange("A1:B13"); - range.values = melonsData; - range.format.autofitColumns(); - - const header = range.getResizedRange(-12, 0); - header.format.fill.color = "lightgreen"; - header.format.font.bold = true; - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create, update, and clear a hyperlink for a range.

-
- -
-

Set up

- -
- -
-

Try it out

-

-

-

- -

- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/range-merged-ranges.yaml b/samples/excel/42-range/range-merged-ranges.yaml deleted file mode 100644 index 0961a0015..000000000 --- a/samples/excel/42-range/range-merged-ranges.yaml +++ /dev/null @@ -1,139 +0,0 @@ -order: 19 -id: excel-merged-ranges -name: Merged ranges -description: This sample shows how to create and find merged ranges in a worksheet. -host: EXCEL -api_set: - ExcelAPI: '1.13' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#create-merged-range").click(() => tryCatch(createMergedRange)); - $("#get-merged-range").click(() => tryCatch(getMergedRange)); - - async function createMergedRange() { - await Excel.run(async (context) => { - // Retrieve the worksheet and the table in that worksheet. - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const tableRange = sheet.getRange("B2:E6"); - - // Create a merged range in the first row of the table. - const chartTitle = tableRange.getRow(0); - chartTitle.merge(true); - - // Format the merged range. - chartTitle.format.horizontalAlignment = "Center"; - - await context.sync(); - }); - } - - async function getMergedRange() { - await Excel.run(async (context) => { - // Retrieve the worksheet and the table in that worksheet. - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const tableRange = sheet.getRange("B2:E6"); - - // Retrieve the merged range within the table and load its details. - const mergedAreas = tableRange.getMergedAreasOrNullObject(); - mergedAreas.load("address"); - mergedAreas.load("cellCount"); - - // Select the merged range. - const range = mergedAreas.areas.getItemAt(0); - range.select(); - await context.sync(); - - // Print out the details of the `mergedAreas` range object. - console.log(`Address of the merged range: ${mergedAreas.address}`); - console.log(`Number of cells in the merged range: ${mergedAreas.cellCount}`); - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - // Create a table. - const data = [ - ["Product chart", "", "", ""], - ["Product", "Qty", "Unit Price", "Total Price"], - ["Almonds", 2, 7.5, "=C4 * D4"], - ["Coffee", 1, 34.5, "=C5 * D5"], - ["Chocolate", 5, 9.56, "=C6 * D6"] - ]; - - const tableRange = sheet.getRange("B2:E6"); - tableRange.values = data; - tableRange.format.autofitColumns(); - - // Add a header row to the table. - const header = tableRange.getRow(1); - header.format.fill.color = "#4472C4"; - header.format.font.color = "white"; - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create and find merged ranges in a worksheet.

-
- -
-

Set up

- -
- -
-

Try it out

- - -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/range-relationships.yaml b/samples/excel/42-range/range-relationships.yaml deleted file mode 100644 index 63156897b..000000000 --- a/samples/excel/42-range/range-relationships.yaml +++ /dev/null @@ -1,262 +0,0 @@ -order: 10 -id: excel-range-range-relationships -name: Range relationships -description: 'Shows relationships between ranges, such as bounding rectangles and intersections.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#bounding-rect").click(() => tryCatch(boundingRect)); - $("#intersection").click(() => tryCatch(intersection)); - $("#offset-range").click(() => tryCatch(offsetRange)); - $("#resized-range").click(() => tryCatch(resizedRange)); - $("#create-sales-contest-charts").click(() => tryCatch(createContestCharts)); - - async function boundingRect() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const rangeA = sheet.getRange("H2:J5"); - const rangeB = sheet.getRange("J4:L8"); - - const boundingRect = rangeA.getBoundingRect(rangeB); - boundingRect.format.fill.color = "Blue"; - boundingRect.getCell(0, 0).values = [["Bounding Rect"]]; - - await context.sync(); - }); - } - - async function intersection() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const rangeA = sheet.getRange("H2:J5"); - const rangeB = sheet.getRange("J4:L8"); - - const intersection = rangeA.getIntersection(rangeB); - intersection.format.fill.color = "Blue"; - intersection.getCell(0, 0).values = [["Intersection"]]; - - await context.sync(); - }); - } - - async function offsetRange() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const rangeA = sheet.getRange("H2:J5"); - - const offsetRange = rangeA.getOffsetRange(6, 3); - offsetRange.format.fill.color = "Blue"; - offsetRange.getCell(0, 0).values = [["OffsetRange(6,3)"]]; - - await context.sync(); - }); - } - - async function resizedRange() { - await Excel.run(async context => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const rangeB = sheet.getRange("J4:L8"); - - const resizedRange = rangeB.getResizedRange(2, -1); - resizedRange.format.fill.color = "Blue"; - resizedRange.getCell(0, 0).values = [["ResizedRange(2,-1)"]]; - - await context.sync(); - }); - } - - async function createContestCharts() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - - // We want the most recent quarter that has data, so - // exclude quarters without data and get the last of - // the remaining columns. - const usedDataRange = dataRange.getUsedRange(true /* valuesOnly */); - const currentQuarterRange = usedDataRange.getLastColumn(); - - // Asian and European teams have separate contests. - const asianSalesRange = sheet.getRange("A2:E4"); - const europeanSalesRange = sheet.getRange("A5:E7"); - - // The data for each chart is the intersection of the - // current quarter column and the rows for the continent. - const asianContestRange = asianSalesRange.getIntersectionOrNullObject(currentQuarterRange); - const europeanContestRange = europeanSalesRange.getIntersectionOrNullObject(currentQuarterRange); - - // Must sync before you can test the output of *OrNullObject - // method/property. - await context.sync(); - - if (asianContestRange.isNullObject) { - // See the declaration of this function for how to - // test this code path. - reportMissingData("Asian"); - } else { - createContinentChart( - sheet, - "Asian", - asianContestRange, - "A9", - "F24" - ); - } - - if (europeanContestRange.isNullObject) { - // See the declaration of this function for how to - // test this code path. - reportMissingData("European"); - } else { - createContinentChart( - sheet, - "European", - europeanContestRange, - "A25", - "F40" - ); - } - - await context.sync(); - }); - } - - function createContinentChart( - sheet: Excel.Worksheet, - continent: string, - contestRange: Excel.Range, - startPosition: string, - endPosition: string - ) { - let chart = sheet.charts.add("ColumnClustered", contestRange, "Columns"); - chart.setPosition(startPosition, endPosition); - chart.title.text = `${continent} Current Quarter Sales Contest`; - chart.legend.position = "Right"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - } - - function reportMissingData(continent: string) { - // To test this function, - // (1) Press "Create Table" - // (2) Delete data from the rows for one continent, - // INCLUDING THE "Sales Team" COLUMN VALUES. - // (3) Press "Create sales contest charts". - console.log(`Missing ${continent} Data`); - console.log(`There is no data for the ${continent} teams.`); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const rangeA = sheet.getRange("H2:J5"); - rangeA.format.fill.color = "green"; - rangeA.getCell(0, 0).values = [["Range A"]]; - - const rangeB = sheet.getRange("J4:L8"); - rangeB.format.fill.color = "yellow"; - rangeB.getCell(0, 0).values = [["Range B"]]; - - let salesTable = sheet.tables.add("A1:E1", true); - salesTable.name = "SalesTable"; - salesTable.getHeaderRowRange().values = [ - ["Sales Team", "Qtr1", "Qtr2", "Qtr3", "Qtr4"] - ]; - - salesTable.rows.add(null, [ - ["Asian Team 1", 500, 700, 654, null], - ["Asian Team 2", 400, 323, 276, null], - ["Asian Team 3", 1200, 876, 845, null], - ["European Team 1", 600, 500, 854, null], - ["European Team 2", 5001, 2232, 4763, null], - ["European Team 3", 130, 776, 104, null] - ]); - - salesTable.getRange().format.autofitColumns(); - salesTable.getRange().format.autofitRows(); - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to do various operations on ranges, for example, getting the bounding rect of two ranges.

-
- -
-

Set up

- -
- -
-

Try it out

-

-

-

-

-

Display charts based on the intersection of the current quarter and a continent.

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/range-remove-duplicates.yaml b/samples/excel/42-range/range-remove-duplicates.yaml deleted file mode 100644 index 1d61d4180..000000000 --- a/samples/excel/42-range/range-remove-duplicates.yaml +++ /dev/null @@ -1,133 +0,0 @@ -order: 11 -id: excel-range-remove-duplicates -name: Remove duplicates -description: Removes duplicate entries from a range. -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - - $("#delete-name").click(() => tryCatch(deleteName)); - $("#delete-distributor").click(() => tryCatch(deleteDistributor)); - - async function deleteName() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B2:D11"); - - const deleteResult = range.removeDuplicates([0],true); - deleteResult.load(); - await context.sync(); - - console.log(deleteResult.removed + " entries with duplicate names removed."); - console.log(deleteResult.uniqueRemaining + " entries with unique names remain in the range."); - }); - } - - async function deleteDistributor() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B2:D11"); - - const deleteResult = range.removeDuplicates([1], true); - deleteResult.load(); - await context.sync(); - - console.log(deleteResult.removed + " entries with duplicate distributors removed."); - console.log(deleteResult.uniqueRemaining + " entries with unique distributors remain in the range."); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Product Name", "Distributor", "Order Amount"], - ["Onions", "Contoso Produce", 3], - ["Potatoes", "Contoso Produce", 9], - ["Red Wine", "Coho Vineyard", 7], - ["Onions", "Best For You Organics Company", 8], - ["Arugula", "Best For You Organics Company", 7], - ["Potatoes", "Contoso Produce", 12], - ["Red Wine", "Coho Vineyard", 3], - ["Onions", "Contoso Produce", 9], - ["Arugula", "Best For You Organics Company", 4] - ]; - - const range = sheet.getRange("B2:D11"); - range.values = data; - range.format.autofitColumns(); - - const header = range.getRow(0); - header.format.fill.color = "#4472C4"; - header.format.font.color = "white"; - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to remove rows with duplicate column values from a range.

-
- -
-

Set up

- -
- -
-

Try it out

-

-

-

Note that blank cells are considered in the remove duplicate checks. Since the duplicates are removed from the entire original range, the numbers logged to the console may be higher than expected.

-
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/range-text-orientation.yaml b/samples/excel/42-range/range-text-orientation.yaml deleted file mode 100644 index 7211ee30b..000000000 --- a/samples/excel/42-range/range-text-orientation.yaml +++ /dev/null @@ -1,127 +0,0 @@ -order: 15 -id: excel-range-text-orientation -name: Text orientation -description: Gets and sets the text orientation within a range. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#set-text-orientation").click(() => tryCatch(setTextOrientation)); - $("#get-text-orientation").click(() => tryCatch(getTextOrientation)); - - async function setTextOrientation() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B2:E2"); - - // Set textOrientation to either an integer between -90 and 90 - // or to 180 for vertically-oriented text. - range.format.textOrientation = 90; - - await context.sync(); - }); - } - - async function getTextOrientation() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B2:E2"); - range.load("address, format/textOrientation"); - - await context.sync(); - - let textOrientation = range.format.textOrientation === null ? - "null (which indicates that the text orientation for cells within the specified range is not uniform)" : - range.format.textOrientation; - - console.log(`The text orientation within the range "${range.address}" is ${textOrientation}.`); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Product", "Qty", "Unit Price", "Total Price"], - ["Almonds", 2, 7.50, "=C3 * D3"], - ["Coffee", 1, 34.50, "=C4 * D4"], - ["Chocolate", 5, 9.56, "=C5 * D5"] - ]; - - const range = sheet.getRange("B2:E5"); - range.values = data; - range.format.autofitColumns(); - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to set and get the text orientation within a range.

-
- -
-

Set up

- -
- -
-

Try it out

- - -
- - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/selected-range.yaml b/samples/excel/42-range/selected-range.yaml deleted file mode 100644 index 4c14a5798..000000000 --- a/samples/excel/42-range/selected-range.yaml +++ /dev/null @@ -1,87 +0,0 @@ -order: 12 -id: excel-range-selected-range -name: Selected range -description: Gets and sets the currently selected range. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.1' -script: - content: | - $("#get-selection").click(() => tryCatch(getSelection)); - $("#set-selection").click(() => tryCatch(setSelection)); - - async function getSelection() { - await Excel.run(async (context) => { - const range = context.workbook.getSelectedRange(); - range.load("address"); - - await context.sync(); - - console.log(`The address of the selected range is "${range.address}"`) - }); - } - - async function setSelection() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const range = sheet.getRange("B2:E6"); - - range.select(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to get and set the currently selected range.

-
- -
-

Try it out

- - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/set-get-values.yaml b/samples/excel/42-range/set-get-values.yaml deleted file mode 100644 index b9c1d91fc..000000000 --- a/samples/excel/42-range/set-get-values.yaml +++ /dev/null @@ -1,244 +0,0 @@ -order: 18 -id: excel-range-values-and-formulas -name: Values and formulas -description: Gets and sets values and formulas for a range. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - - $("#set-value").click(() => tryCatch(setValue)); - $("#set-values").click(() => tryCatch(setValues)); - $("#set-formula").click(() => tryCatch(setFormula)); - $("#set-formulas").click(() => tryCatch(setFormulas)); - $("#set-formulas-r1c1").click(() => tryCatch(setFormulasR1C1)); - $("#get-values").click(() => tryCatch(getValues)); - $("#get-texts").click(() => tryCatch(getTexts)); - $("#get-formulas").click(() => tryCatch(getFormulas)); - - async function setValue() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const range = sheet.getRange("C3"); - range.values = [[ 5 ]]; - range.format.autofitColumns(); - - await context.sync(); - }); - } - - async function setValues() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const data = [ - ["Potato Chips", 10, 1.80], - ]; - - const range = sheet.getRange("B5:D5"); - range.values = data; - range.format.autofitColumns(); - - await context.sync(); - }); - } - - async function setFormula() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const range = sheet.getRange("E3"); - range.formulas = [[ "=C3 * D3" ]]; - range.format.autofitColumns(); - - await context.sync(); - }); - } - - async function setFormulas() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const data = [ - ["Total Price"], - ["=C3 * D3"], - ["=C4 * D4"], - ["=C5 * D5"], - ["=SUM(E3:E5)"] - ]; - - const range = sheet.getRange("E2:E6"); - range.formulas = data; - range.format.autofitColumns(); - - await context.sync(); - }); - } - - async function setFormulasR1C1() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const data = [ - ["Total Price"], - ["=R[0]C[-2] * R[0]C[-1]"], - ["=R[0]C[-2] * R[0]C[-1]"], - ["=R[0]C[-2] * R[0]C[-1]"], - ["=SUM(R[-3]C[0]:R[-1]C[0])"] - ]; - - const range = sheet.getRange("E2:E6"); - range.formulasR1C1 = data; - range.format.autofitColumns(); - - await context.sync(); - }); - } - - async function getValues() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B2:E6"); - range.load("values"); - - await context.sync(); - - console.log(JSON.stringify(range.values, null, 4)); - }); - } - - async function getTexts() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B2:E6"); - range.load("text"); - - await context.sync(); - - console.log(JSON.stringify(range.text, null, 4)); - }); - } - - async function getFormulas() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B2:E6"); - range.load("formulas"); - - await context.sync(); - - console.log(JSON.stringify(range.formulas, null, 4)); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Product", "Qty", "Unit Price"], - ["Almonds", 2, 7.50], - ["Coffee", 1, 34.50], - ["Chocolate", 5, 9.56] - ]; - - const range = sheet.getRange("B2:D5"); - range.values = data; - range.format.autofitColumns(); - - const header = range.getRow(0); - header.format.fill.color = "#4472C4"; - header.format.font.color = "white"; - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to set and get values and formulas for a range.

-
- -
-

Set up

- -
- -
-

Try it out

- - - - - - - -
- - - - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/style.yaml b/samples/excel/42-range/style.yaml deleted file mode 100644 index 2ad8bcd6c..000000000 --- a/samples/excel/42-range/style.yaml +++ /dev/null @@ -1,235 +0,0 @@ -order: 14 -id: excel-range-style -name: Style -description: 'Creates a custom style, applies a custom and built-in styles to a range, gets style properties, and deletes the custom style.' -author: siewmoi -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: |+ - $("#setup").click(() => tryCatch(setup)); - $("#add-new-style").click(() => tryCatch(addNewStyle)); - $("#apply-new-style").click(() => tryCatch(applyNewStyle)); - $("#apply-built-in-style").click(() => tryCatch(applyBuiltInStyle)); - $("#get-style-font").click(() => tryCatch(getStyleFontProperties)); - $("#get-style-alignment").click(() => tryCatch(getStyleAlignmentProperties)); - $("#delete-new-style").click(() => tryCatch(deleteNewStyle)); - - async function addNewStyle() { - await Excel.run(async (context) => { - let styles = context.workbook.styles; - - // Add a new style to the style collection. - // Styles is in the Home tab ribbon. - styles.add("Diagonal Orientation Style"); - - let newStyle = styles.getItem("Diagonal Orientation Style"); - - // The "Diagonal Orientation Style" properties. - newStyle.textOrientation = 38; - newStyle.autoIndent = true; - newStyle.includeProtection = true; - newStyle.shrinkToFit = true; - newStyle.locked = false; - - await context.sync(); - - console.log("Successfully added a new style with diagonal orientation to the Home tab ribbon."); - }); - } - - async function applyNewStyle() { - await Excel.run(async (context) => { - let worksheet = context.workbook.worksheets.getItem("Sample"); - let range = worksheet.getRange("A1:E1"); - // Apply new style. - range.style = ("Diagonal Orientation Style"); - range.format.verticalAlignment = "Justify"; - - await context.sync(); - }); - } - - async function applyBuiltInStyle() { - await Excel.run(async (context) => { - let worksheet = context.workbook.worksheets.getItem("Sample"); - let range = worksheet.getRange("A1:E1"); - - // Apply built-in style. - // Styles are in the Home tab ribbon. - range.style = Excel.BuiltInStyle.neutral; - range.format.horizontalAlignment = "Right"; - - await context.sync(); - }); - } - - async function getStyleFontProperties() { - await Excel.run(async (context) => { - let style = context.workbook.styles.getItem("Normal"); - style.font.load("bold, color, italic, name, size"); - style.fill.load("color"); - - await context.sync(); - - console.log("Bold: " + style.font.bold); - console.log("Font color: " + style.font.color); - console.log("Italic: " + style.font.italic); - console.log("Name: " + style.font.name); - console.log("Size: " + style.font.size); - console.log("Fill color: " + style.fill.color); - }); - } - - async function getStyleAlignmentProperties() { - await Excel.run(async (context) => { - let style = context.workbook.styles.getItem("Diagonal Orientation Style"); - style.load("textOrientation, horizontalAlignment, autoIndent, readingOrder, wrapText, includeProtection, shrinkToFit, locked"); - - await context.sync(); - - console.log("Orientation: " + style.textOrientation); - console.log("Horizontal alignment: " + style.horizontalAlignment); - console.log("Add indent: " + style.autoIndent); - console.log("Reading order: " + style.readingOrder); - console.log("Wrap text: " + style.wrapText); - console.log("Include protection: " + style.includeProtection); - console.log("Shrink to fit: " + style.shrinkToFit); - console.log("Style locked: " + style.locked); - }); - } - - async function deleteNewStyle() { - await Excel.run(async (context) => { - let style = context.workbook.styles.getItem("Diagonal Orientation Style"); - - // Delete the diagonal orientation style from the style collection. - // Styles are in the Home tab ribbon. - style.delete(); - - await context.sync(); - - console.log("Successfully deleted the diagonal orientation style from the Home tab ribbon."); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let salesTable = sheet.tables.add('A1:E1', true); - salesTable.name = "SalesTable"; - - salesTable.getHeaderRowRange().values = [["Bicycle Parts Product", "Quarter 1", "Quarter 2", "Quarter 3", "Quarter 4"]]; - - salesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - - - - language: typescript -template: - content: | -
-

This sample shows how to add, apply, get and delete styles.

-
- -
-

Set up

- -
- -
-

Try it out

-

Add new style will throw an error if the style has already been added.

- -
- -
- -
- -
- -
- -
- -
- -
- -
- -
-

Clean up

-

Delete new style throws an error if the style doesn't exist (that is, hasn't been added). Deleting the style also causes the other buttons using the style to fail.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/42-range/used-range.yaml b/samples/excel/42-range/used-range.yaml deleted file mode 100644 index ceb41f352..000000000 --- a/samples/excel/42-range/used-range.yaml +++ /dev/null @@ -1,149 +0,0 @@ -order: 17 -id: excel-range-used-range -name: Used range -description: Tests for a used range and creates a chart from a table only if there's data in the table. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#try-create-chart-from-table").click(() => tryCatch(tryCreateChartFromEmptyTable)); - $("#fill-table").click(() => tryCatch(fillTable)); - - async function tryCreateChartFromEmptyTable() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - - // Pass true so only cells with values count as used - const usedDataRange = dataRange.getUsedRangeOrNullObject( - true /* valuesOnly */ - ); - - //Must sync before reading value returned from *OrNullObject method/property. - await context.sync(); - - if (usedDataRange.isNullObject) { - console.log("Need Data to Make Chart"); - console.log("To create a meaningful chart, press 'Fill the table' (or add names to the Product column and numbers to some of the other cells). Then press 'Try to create chart' again."); - } else { - const chart = sheet.charts.add( - Excel.ChartType.columnClustered, - dataRange, - "Columns" - ); - chart.setPosition("A15", "F30"); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Right"; - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - } - - await context.sync(); - }); - } - - async function fillTable() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - dataRange.values = [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765]]; - - dataRange.format.autofitColumns(); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async context => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let salesTable = sheet.tables.add("B2:F2", true /* hasHeaders */); - salesTable.name = "SalesTable"; - salesTable.showTotals = true; - salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - // The table should be created wtih no data. - salesTable.rows.add(null, [ - [null, null, null, null, null], - [null, null, null, null, null], - [null, null, null, null, null], - [null, null, null, null, null], - [null, null, null, null, null], - [null, null, null, null, null]]); - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample creates a chart from a table, but only if there's data in the table.

-
- -
-

Set up

- -
- -
-

Try it out

-

- -

- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/44-shape/shape-create-and-delete.yaml b/samples/excel/44-shape/shape-create-and-delete.yaml deleted file mode 100644 index 3469e9ea7..000000000 --- a/samples/excel/44-shape/shape-create-and-delete.yaml +++ /dev/null @@ -1,142 +0,0 @@ -order: 1 -id: excel-shape-create-and-delete -name: Create and delete geometric shapes -description: Creates a few different geometric shapes and deletes them from the worksheet. -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#createHexagon").click(() => tryCatch(createHexagon)); - $("#createTriangle").click(() => tryCatch(createTriangle)); - $("#createSmileyFace").click(() => tryCatch(createSmileyFace)); - $("#removeAll").click(() => tryCatch(removeAll)); - - async function createHexagon() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - const shape = sheet.shapes.addGeometricShape(Excel.GeometricShapeType.hexagon); - shape.left = 5; - shape.top = 5; - shape.height = 175; - shape.width = 200; - await context.sync(); - }); - } - - async function createTriangle() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - const shape = sheet.shapes.addGeometricShape(Excel.GeometricShapeType.triangle); - shape.left = 100; - shape.top = 300; - shape.height = 150; - shape.width = 200; - shape.rotation = 45; - shape.fill.clear(); - await context.sync(); - }); - } - - async function createSmileyFace() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - const shape = sheet.shapes.addGeometricShape(Excel.GeometricShapeType.smileyFace); - shape.left = 300; - shape.top = 100; - shape.height = 100; - shape.width = 100; - shape.fill.foregroundColor = "yellow" - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Shapes").delete(); - const sheet = context.workbook.worksheets.add("Shapes"); - - sheet.activate(); - await context.sync(); - }); - } - - async function removeAll() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Shapes").delete(); - const sheet = context.workbook.worksheets.add("Shapes"); - - const shapes = sheet.shapes; - - // load all the shapes in the collection without loading their properties - shapes.load("items/$none"); - await context.sync(); - - shapes.items.forEach((shape) => shape.delete()); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create different shapes, then delele them.

-
-
-

Setup

- -
-
-

Try it out

-

-

-

-

-

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/44-shape/shape-groups.yaml b/samples/excel/44-shape/shape-groups.yaml deleted file mode 100644 index b6d60f218..000000000 --- a/samples/excel/44-shape/shape-groups.yaml +++ /dev/null @@ -1,157 +0,0 @@ -order: 5 -id: excel-shape-groups -name: Shape groups -description: Groups and ungroups shapes. -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#createShapes").click(() => tryCatch(createShapes)); - $("#groupShapes").click(() => tryCatch(groupShapes)); - $("#moveGroup").click(() => tryCatch(moveGroup)); - $("#ungroupShapes").click(() => tryCatch(ungroupShapes)); - - async function groupShapes() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - const square = sheet.shapes.getItem("Square"); - const pentagon = sheet.shapes.getItem("Pentagon"); - const octagon = sheet.shapes.getItem("Octagon"); - - const shapeGroup = sheet.shapes.addGroup([square, pentagon, octagon]); - shapeGroup.name = "Group"; - console.log("Shapes grouped"); - - await context.sync(); - }); - } - - async function moveGroup() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - - const shapeGroup = sheet.shapes.getItem("Group"); - shapeGroup.incrementLeft(50); - shapeGroup.incrementTop(50); - - await context.sync(); - }); - } - - async function ungroupShapes() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - - const shapeGroup = sheet.shapes.getItem("Group").group; - shapeGroup.ungroup(); - console.log("Shapes ungrouped"); - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Shapes").delete(); - const sheet = context.workbook.worksheets.add("Shapes"); - - sheet.activate(); - await context.sync(); - }); - } - - async function createShapes() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const rectangle = shapes.addGeometricShape(Excel.GeometricShapeType.rectangle); - rectangle.left = 100; - rectangle.top = 100; - rectangle.height = 150; - rectangle.width = 150; - rectangle.name = "Square"; - rectangle.fill.setSolidColor("green"); - - const pentagon = shapes.addGeometricShape(Excel.GeometricShapeType.pentagon); - pentagon.left = 125; - pentagon.top = 125; - pentagon.height = 100; - pentagon.width = 100; - pentagon.name = "Pentagon"; - pentagon.fill.setSolidColor("purple"); - - const octagon = shapes.addGeometricShape(Excel.GeometricShapeType.octagon); - octagon.left = 150; - octagon.top = 150; - octagon.height = 50; - octagon.width = 50; - octagon.name = "Octagon"; - octagon.fill.setSolidColor("red"); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to group and upgroup shapes in a worksheet.

-
-
-

Setup

-

- -

-
-

Try it out

-

-

-

-

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/44-shape/shape-images.yaml b/samples/excel/44-shape/shape-images.yaml deleted file mode 100644 index e28300275..000000000 --- a/samples/excel/44-shape/shape-images.yaml +++ /dev/null @@ -1,141 +0,0 @@ -order: 2 -id: excel-shape-images -name: Image shapes -description: Creates and adjusts image-based shapes. -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#selectedFile").change(() => tryCatch(readImageFromFile)); - $("#flipImage").click(() => tryCatch(flipImage)); - $("#getImageFormat").click(() => tryCatch(getImageFormat)); - $("#writeOutImageString").click(() => tryCatch(writeOutImageString)); - - async function readImageFromFile() { - const myFile = document.getElementById("selectedFile"); - const reader = new FileReader(); - - reader.onload = (event) => { - Excel.run((context) => { - const startIndex = reader.result.toString().indexOf("base64,"); - const myBase64 = reader.result.toString().substr(startIndex + 7); - const sheet = context.workbook.worksheets.getItem("Shapes"); - const image = sheet.shapes.addImage(myBase64); - image.name = "Image"; - return context.sync(); - }); - }; - - // Read in the image file as a data URL. - reader.readAsDataURL(myFile.files[0]); - } - - async function flipImage() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - const shape = sheet.shapes.getItem("Image"); - shape.incrementRotation(180); - await context.sync(); - }); - } - - async function getImageFormat() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - const image = sheet.shapes.getItem("Image").image; - image.load("format"); - await context.sync(); - - console.log("The image's format is: " + image.format); - await context.sync(); - }); - } - - async function writeOutImageString() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - const shape = sheet.shapes.getItem("Image"); - const result = shape.getAsImage(Excel.PictureFormat.png); - await context.sync(); - - const imageString = result.value; - // Your add-in would save this string as a .png file. - console.log("The image's Base64-encoded string: " + imageString); - }); - } - - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Shapes").delete(); - const sheet = context.workbook.worksheets.add("Shapes"); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create and use an image-based shape.

-
-
-

Setup

- -
-
-

Try it out

-

Select an image file (JPEG or PNG).

-

-

Use the following buttons to work with the image shape.

-

-

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/44-shape/shape-lines.yaml b/samples/excel/44-shape/shape-lines.yaml deleted file mode 100644 index 8fd8207fe..000000000 --- a/samples/excel/44-shape/shape-lines.yaml +++ /dev/null @@ -1,231 +0,0 @@ -order: 3 -id: excel-shape-lines -name: Lines -description: Creates and modifies line shapes. -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - $("#createShapes").click(() => tryCatch(createShapes)); - $("#addStraightLine").click(() => tryCatch(addStraightLine)); - $("#addCurvedLine").click(() => tryCatch(addCurvedLine)); - $("#arrowLine").click(() => tryCatch(arrowLine)); - $("#diamondLine").click(() => tryCatch(diamondLine)); - $("#connectStraightLine").click(() => tryCatch(connectStraightLine)); - $("#disconnectStraightLine").click(() => tryCatch(disconnectStraightLine)); - $("#connectCurvedLine").click(() => tryCatch(connectCurvedLine)); - $("#disconnectCurvedLine").click(() => tryCatch(disconnectCurvedLine)); - $("#deleteLines").click(() => tryCatch(deleteLines)); - - async function addStraightLine() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const line = shapes.addLine(200, 50, 300, 150, Excel.ConnectorType.straight); - line.name = "StraightLine"; - await context.sync(); - }); - } - - async function addCurvedLine() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const line = shapes.addLine(200, 300, 300, 400, Excel.ConnectorType.curve); - line.name = "CurvedLine"; - await context.sync(); - }); - } - - async function arrowLine() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const line = shapes.getItem("StraightLine").line; - line.beginArrowheadLength = Excel.ArrowheadLength.long; - line.beginArrowheadWidth = Excel.ArrowheadWidth.wide; - line.beginArrowheadStyle = Excel.ArrowheadStyle.oval; - - line.endArrowheadLength = Excel.ArrowheadLength.long; - line.endArrowheadWidth = Excel.ArrowheadWidth.wide; - line.endArrowheadStyle = Excel.ArrowheadStyle.triangle; - - await context.sync(); - }); - } - - async function diamondLine() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const line = shapes.getItem("CurvedLine").line; - line.beginArrowheadLength = Excel.ArrowheadLength.short; - line.beginArrowheadWidth = Excel.ArrowheadWidth.narrow; - line.beginArrowheadStyle = Excel.ArrowheadStyle.diamond; - - line.endArrowheadLength = Excel.ArrowheadLength.short; - line.endArrowheadWidth = Excel.ArrowheadWidth.narrow; - line.endArrowheadStyle = Excel.ArrowheadStyle.diamond; - - await context.sync(); - }); - } - - async function connectStraightLine() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const line = shapes.getItem("StraightLine").line; - line.connectBeginShape(shapes.getItem("Left"), 2); - line.connectEndShape(shapes.getItem("Right"), 0); - await context.sync(); - }); - } - - async function disconnectStraightLine() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const line = shapes.getItem("StraightLine").line; - line.disconnectBeginShape(); - line.disconnectEndShape(); - await context.sync(); - }); - } - - async function connectCurvedLine() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const line = shapes.getItem("CurvedLine").line; - line.connectBeginShape(shapes.getItem("Left"), 2); - line.connectEndShape(shapes.getItem("Right"), 0); - await context.sync(); - }); - } - - async function disconnectCurvedLine() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const line = shapes.getItem("CurvedLine").line; - line.disconnectBeginShape(); - line.disconnectEndShape(); - await context.sync(); - }); - } - - async function deleteLines() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - shapes.getItem("StraightLine").delete(); - shapes.getItem("CurvedLine").delete(); - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Shapes").delete(); - const sheet = context.workbook.worksheets.add("Shapes"); - - sheet.activate(); - await context.sync(); - }); - } - - async function createShapes() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - - const shape1 = sheet.shapes.addGeometricShape(Excel.GeometricShapeType.diamond); - shape1.left = 5; - shape1.top = 5; - shape1.height = 100; - shape1.width = 100; - shape1.name = "Left"; - - const shape2 = sheet.shapes.addGeometricShape(Excel.GeometricShapeType.cloud); - shape2.left = 400; - shape2.top = 300; - shape2.height = 100; - shape2.width = 100; - shape2.name = "Right"; - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create and modify line shapes.

-
-
-

Setup

-

- -

-
-

Try it out

-

-

-

-

-

-

-

-

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/44-shape/shape-move-and-order.yaml b/samples/excel/44-shape/shape-move-and-order.yaml deleted file mode 100644 index f5a6625e8..000000000 --- a/samples/excel/44-shape/shape-move-and-order.yaml +++ /dev/null @@ -1,172 +0,0 @@ -order: 4 -id: excel-shape-move-and-order -name: Move and order shapes -description: Moves created shapes around the worksheet and adjusts their z-order. -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#moveLeft").click(() => tryCatch(moveLeft)); - $("#moveDown").click(() => tryCatch(moveDown)); - $("#rotate").click(() => tryCatch(rotate)); - $("#scaleUp").click(() => tryCatch(scaleUp)); - $("#moveZOrderDown").click(() => tryCatch(moveZOrderDown)); - $("#createShapes").click(() => tryCatch(createShapes)); - - async function moveLeft() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - const shape = sheet.shapes.getItem("Square") - shape.incrementLeft(-25); - await context.sync(); - }); - } - - async function moveDown() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - const shape = sheet.shapes.getItem("Pentagon") - shape.incrementTop(25); - await context.sync(); - }); - } - - async function rotate() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - const shape = sheet.shapes.getItem("Pentagon") - shape.incrementRotation(30); - await context.sync(); - }); - } - - async function scaleUp() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - const shape = sheet.shapes.getItem("Octagon") - shape.lockAspectRatio = true; - shape.scaleHeight(1.25, Excel.ShapeScaleType.currentSize); - await context.sync(); - }); - } - - async function moveZOrderDown() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Shapes"); - const shape = sheet.shapes.getItem("Octagon") - shape.setZOrder(Excel.ShapeZOrder.sendBackward); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Shapes").delete(); - const sheet = context.workbook.worksheets.add("Shapes"); - - sheet.activate(); - await context.sync(); - }); - } - - async function createShapes() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const rectangle = shapes.addGeometricShape(Excel.GeometricShapeType.rectangle); - rectangle.left = 100; - rectangle.top = 100; - rectangle.height = 150; - rectangle.width = 150; - rectangle.name = "Square"; - rectangle.fill.setSolidColor("green"); - - const pentagon = shapes.addGeometricShape(Excel.GeometricShapeType.pentagon); - pentagon.left = 125; - pentagon.top = 125; - pentagon.height = 100; - pentagon.width = 100; - pentagon.name = "Pentagon"; - pentagon.fill.setSolidColor("purple"); - - const octagon = shapes.addGeometricShape(Excel.GeometricShapeType.octagon); - octagon.left = 150; - octagon.top = 150; - octagon.height = 50; - octagon.width = 50; - octagon.name = "Octagon"; - octagon.fill.setSolidColor("red"); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to change the position of shapes, both on the worksheet and their relative positioning when stacked.

-
-
-

Setup

-

- -

-
-

Try it out

-

-

-

-

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/44-shape/shape-textboxes.yaml b/samples/excel/44-shape/shape-textboxes.yaml deleted file mode 100644 index 114d919df..000000000 --- a/samples/excel/44-shape/shape-textboxes.yaml +++ /dev/null @@ -1,147 +0,0 @@ -order: 6 -id: excel-shape-textboxes -name: Textboxes -description: Creates a textbox shape and works with the text in it and other shapes. -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#createGeometricShape").click(() => tryCatch(createGeometricShape)); - $("#createTextbox").click(() => tryCatch(createTextbox)); - $("#centerTextbox").click(() => tryCatch(centerTextbox)); - $("#autoSizeText").click(() => tryCatch(autoSizeText)); - $("#deleteText").click(() => tryCatch(deleteText)); - - - async function createTextbox() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const textbox = shapes.addTextBox("A box with text"); - textbox.left = 100; - textbox.top = 100; - textbox.height = 20; - textbox.width = 175; - textbox.name = "Textbox"; - await context.sync(); - }); - } - - async function createGeometricShape() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const wave = shapes.addGeometricShape(Excel.GeometricShapeType.wave); - wave.left = 100; - wave.top = 400; - wave.height = 50; - wave.width = 150; - wave.name = "Wave"; - wave.fill.setSolidColor("lightblue"); - wave.textFrame.textRange.text = "A geometric shape"; - await context.sync(); - }); - } - - async function centerTextbox() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const textbox = shapes.getItem("Textbox"); - textbox.textFrame.horizontalAlignment = Excel.ShapeTextHorizontalAlignment.center; - await context.sync(); - }); - } - - async function autoSizeText() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const textbox = shapes.getItem("Textbox"); - textbox.textFrame.autoSizeSetting = Excel.ShapeAutoSize.autoSizeShapeToFitText; - await context.sync(); - }); - } - - async function deleteText() { - await Excel.run(async (context) => { - const shapes = context.workbook.worksheets.getItem("Shapes").shapes; - const textbox = shapes.getItem("Textbox"); - textbox.textFrame.deleteText(); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Shapes").delete(); - const sheet = context.workbook.worksheets.add("Shapes"); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create and modify textboxes and other shapes with text.

-
-
-

Setup

- -
-
-

Try it out

-

-

-

-

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/46-table/add-rows-and-columns-to-a-table.yaml b/samples/excel/46-table/add-rows-and-columns-to-a-table.yaml deleted file mode 100644 index 006660870..000000000 --- a/samples/excel/46-table/add-rows-and-columns-to-a-table.yaml +++ /dev/null @@ -1,179 +0,0 @@ -order: 1 -id: excel-table-add-rows-and-columns-to-a-table -name: Add rows and columns -description: Adds rows and columns to a table. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - - $("#add-row").click(() => tryCatch(addRow)); - $("#add-column").click(() => tryCatch(addColumn)); - $("#add-calculated-column").click(() => tryCatch(addCalculatedColumn)); - - async function addRow() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - expensesTable.rows.add(null, [ - ["1/16/2017", "THE PHONE COMPANY", "Communications", "$120"], - ["1/20/2017", "NORTHWIND ELECTRIC CARS", "Transportation", "$142"], - ["1/20/2017", "BEST FOR YOU ORGANICS COMPANY", "Groceries", "$27"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - await context.sync(); - }); - } - - async function addColumn() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - expensesTable.columns.add(null, [ - ["Deductable?"], - ["Yes"], - ["Yes"], - ["No"], - ["No"], - ["Yes"], - ["Yes"], - ["No"], - ["Yes"], - ["Yes"], - ["No"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - await context.sync(); - }); - } - - async function addCalculatedColumn() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - const weekendFormula = '=IF(OR((TEXT([@DATE], "dddd") = "Saturday"), (TEXT([@DATE], "dddd") = "Sunday")), "Weekend", "Weekday")'; - expensesTable.columns.add(null, [ - ["Type of the Day"], - [weekendFormula], - [weekendFormula], - [weekendFormula], - [weekendFormula], - [weekendFormula], - [weekendFormula], - [weekendFormula], - [weekendFormula], - [weekendFormula], - [weekendFormula] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - await context.sync(); - }); - } - - /** Create a new table with sample data */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const expensesTable = sheet.tables.add("A1:D1", true /*hasHeaders*/); - expensesTable.name = "ExpensesTable"; - expensesTable.getHeaderRowRange().values = [ - ["Date", "Merchant", "Category", "Amount"] - ]; - - expensesTable.rows.add(null /*add at the end*/, [ - ["1/1/2017", "The Phone Company", "Communications", "$120"], - ["1/2/2017", "Northwind Electric Cars", "Transportation", "$142"], - ["1/5/2017", "Best For You Organics Company", "Groceries", "$27"], - ["1/10/2017", "Coho Vineyard", "Restaurant", "$33"], - ["1/11/2017", "Bellows College", "Education", "$350"], - ["1/15/2017", "Trey Research", "Other", "$135"], - ["1/15/2017", "Best For You Organics Company", "Groceries", "$97"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to add columns and rows to a table.

-
- -
-

Set up

- -
- -
-

Try it out

-

Press the following buttons in order, so rows and columns of appropriate sizes are added.

-

-

- -

- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/46-table/convert-range-to-table.yaml b/samples/excel/46-table/convert-range-to-table.yaml deleted file mode 100644 index 1e7924e1b..000000000 --- a/samples/excel/46-table/convert-range-to-table.yaml +++ /dev/null @@ -1,105 +0,0 @@ -order: 2 -id: excel-table-convert-range-to-table -name: Convert a range -description: Converts a range to a table. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#convert-range-to-table").click(() => tryCatch(convertRangeToTable)); - - async function convertRangeToTable() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - let expensesTable = sheet.tables.add('A1:E7', true); - expensesTable.name = "ExpensesTable"; - - await context.sync(); - }); - } - - /** Create a range */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"], - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765]]; - - const range = sheet.getRange("A1:E7"); - range.values = values; - - sheet.getRange("A1:E1").format.font.bold = true; - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to convert a range to a table.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/46-table/create-table.yaml b/samples/excel/46-table/create-table.yaml deleted file mode 100644 index ab0340392..000000000 --- a/samples/excel/46-table/create-table.yaml +++ /dev/null @@ -1,90 +0,0 @@ -order: 3 -id: excel-table-create-table -name: Create a table -description: Creates a table. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#create-table").click(() => tryCatch(createTable)); - - async function createTable() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const expensesTable = sheet.tables.add("A1:D1", true /*hasHeaders*/); - expensesTable.name = "ExpensesTable"; - - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - - expensesTable.rows.add(null /*add at the end*/, [ - ["1/1/2017", "The Phone Company", "Communications", "$120"], - ["1/2/2017", "Northwind Electric Cars", "Transportation", "$142"], - ["1/5/2017", "Best For You Organics Company", "Groceries", "$27"], - ["1/10/2017", "Coho Vineyard", "Restaurant", "$33"], - ["1/11/2017", "Bellows College", "Education", "$350"], - ["1/15/2017", "Trey Research", "Other", "$135"], - ["1/15/2017", "Best For You Organics Company", "Groceries", "$97"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to create a table.

-
- -
-

Try it out

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/46-table/filter-data.yaml b/samples/excel/46-table/filter-data.yaml deleted file mode 100644 index 229a37783..000000000 --- a/samples/excel/46-table/filter-data.yaml +++ /dev/null @@ -1,136 +0,0 @@ -order: 4 -id: excel-table-filter-data -name: Filter data -description: Filters table data. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#filter-table").click(() => tryCatch(filterTable)); - $("#clear-filters").click(() => tryCatch(clearFilters)); - - async function filterTable() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - let filter = expensesTable.columns.getItem("Amount").filter; - filter.apply({ - filterOn: Excel.FilterOn.dynamic, - dynamicCriteria: Excel.DynamicFilterCriteria.belowAverage - }); - - filter = expensesTable.columns.getItem("Category").filter; - filter.apply({ - filterOn: Excel.FilterOn.values, - values: ["Restaurant", "Groceries"] - }); - - await context.sync(); - }); - } - - async function clearFilters() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - expensesTable.clearFilters(); - - await context.sync(); - }); - } - - /** Create a new table with sample data */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const expensesTable = sheet.tables.add("A1:D1", true /*hasHeaders*/); - expensesTable.name = "ExpensesTable"; - - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - - expensesTable.rows.add(null /*add at the end*/, [ - ["1/1/2017", "The Phone Company", "Communications", "$120"], - ["1/2/2017", "Northwind Electric Cars", "Transportation", "$142"], - ["1/5/2017", "Best For You Organics Company", "Groceries", "$27"], - ["1/10/2017", "Coho Vineyard", "Restaurant", "$33"], - ["1/11/2017", "Bellows College", "Education", "$350"], - ["1/15/2017", "Trey Research", "Other", "$135"], - ["1/15/2017", "Best For You Organics Company", "Groceries", "$97"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to filter the data in a table using different filter types.

-
- -
-

Set up

- -
- -
-

Try it out

- - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/46-table/formatting.yaml b/samples/excel/46-table/formatting.yaml deleted file mode 100644 index a40833fc5..000000000 --- a/samples/excel/46-table/formatting.yaml +++ /dev/null @@ -1,112 +0,0 @@ -order: 5 -id: excel-table-formatting -name: Formatting -description: Formats a table. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#format-table").click(() => tryCatch(formatTable)); - - async function formatTable() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - expensesTable.getHeaderRowRange().format.fill.color = "#C70039"; - expensesTable.getDataBodyRange().format.fill.color = "#DAF7A6"; - expensesTable.rows.getItemAt(1).getRange().format.fill.color = "#FFC300"; - expensesTable.columns.getItemAt(0).getDataBodyRange().format.fill.color = "#FFA07A"; - - await context.sync(); - }); - } - - /** Create a new table with sample data */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const expensesTable = sheet.tables.add("A1:D1", true /*hasHeaders*/); - expensesTable.name = "ExpensesTable"; - - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - - expensesTable.rows.add(null /*add at the end*/, [ - ["1/1/2017", "The Phone Company", "Communications", "$120"], - ["1/2/2017", "Northwind Electric Cars", "Transportation", "$142"], - ["1/5/2017", "Best For You Organics Company", "Groceries", "$27"], - ["1/10/2017", "Coho Vineyard", "Restaurant", "$33"], - ["1/11/2017", "Bellows College", "Education", "$350"], - ["1/15/2017", "Trey Research", "Other", "$135"], - ["1/15/2017", "Best For You Organics Company", "Groceries", "$97"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to format the different components of a table.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/46-table/get-data-from-table.yaml b/samples/excel/46-table/get-data-from-table.yaml deleted file mode 100644 index 3b48ea6df..000000000 --- a/samples/excel/46-table/get-data-from-table.yaml +++ /dev/null @@ -1,127 +0,0 @@ -order: 6 -id: excel-table-get-data-from-table -name: Get data -description: Gets data from a table. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#get-data-from-table").click(() => tryCatch(getData)); - - async function getData() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - const headerRange = expensesTable.getHeaderRowRange().load("values"); - const bodyRange = expensesTable.getDataBodyRange().load("values"); - const columnRange = expensesTable.columns.getItem("MERCHANT").getDataBodyRange().load("values"); - const rowRange= expensesTable.rows.getItemAt(1).load("values"); - - await sheet.context.sync(); - - const headerValues = headerRange.values; - const bodyValues = bodyRange.values; - const merchantColumnValues = columnRange.values; - const secondRowValues = rowRange.values; - - sheet.getRange("A18:A18").values = [["Results"]]; - sheet.getRange("A20:D20").values = headerValues; - sheet.getRange("A21:D27").values = bodyValues; - sheet.getRange("B30:B36").values = merchantColumnValues; - sheet.getRange("A17:D17").values = secondRowValues; - - await context.sync(); - }); - } - - /** Create a new table with some sample data */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const expensesTable = sheet.tables.add('A1:D1', true /*hasHeaders*/); - expensesTable.name = "ExpensesTable"; - - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - - expensesTable.rows.add(null /*add at the end*/, [ - ["1/1/2017", "The Phone Company", "Communications", "$120"], - ["1/2/2017", "Northwind Electric Cars", "Transportation", "$142"], - ["1/5/2017", "Best For You Organics Company", "Groceries", "$27"], - ["1/10/2017", "Coho Vineyard", "Restaurant", "$33"], - ["1/11/2017", "Bellows College", "Education", "$350"], - ["1/15/2017", "Trey Research", "Other", "$135"], - ["1/15/2017", "Best For You Organics Company", "Groceries", "$97"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |+ -
-

This sample shows how to get data from a table and write it to the sheet.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- - - language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/46-table/get-visible-range-of-a-filtered-table.yaml b/samples/excel/46-table/get-visible-range-of-a-filtered-table.yaml deleted file mode 100644 index c719c7902..000000000 --- a/samples/excel/46-table/get-visible-range-of-a-filtered-table.yaml +++ /dev/null @@ -1,150 +0,0 @@ -order: 7 -id: excel-table-get-visible-range-of-a-filtered-table -name: Get visible range -description: Gets the visible range from a filtered table. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: |+ - $("#create-table").click(() => tryCatch(createTable)); - $("#filter-table").click(() => tryCatch(filterTable)); - $("#get-range").click(() => tryCatch(getRange)); - $("#get-visible-range").click(() => tryCatch(getVisibleRange)); - - async function getVisibleRange() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const expensesTable = sheet.tables.getItem("ExpensesTable"); - const visibleRange = expensesTable.getDataBodyRange().getVisibleView().load("values"); - await sheet.context.sync(); - - const visibleValues = visibleRange.values; - console.log(visibleValues); - await context.sync(); - }); - } - - async function getRange() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const expensesTable = sheet.tables.getItem("ExpensesTable"); - const range = expensesTable.getDataBodyRange().load("values"); - await sheet.context.sync(); - - const values = range.values; - console.log(values); - await context.sync(); - }); - } - - /** Create a new table with some sample data*/ - async function createTable() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add('A1:D1', true /*hasHeaders*/); - expensesTable.name = "ExpensesTable"; - - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - - expensesTable.rows.add(null /*add at the end*/, [ - ["1/1/2017", "The Phone Company", "Communications", "$120"], - ["1/2/2017", "Northwind Electric Cars", "Transportation", "$142"], - ["1/5/2017", "Best For You Organics Company", "Groceries", "$27"], - ["1/10/2017", "Coho Vineyard", "Restaurant", "$33"], - ["1/11/2017", "Bellows College", "Education", "$350"], - ["1/15/2017", "Trey Research", "Other", "$135"], - ["1/15/2017", "Best For You Organics Company", "Groceries", "$97"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Filter the table*/ - async function filterTable() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const expensesTable = sheet.tables.getItem("ExpensesTable"); - const filter = expensesTable.columns.getItem("Amount").filter; - - filter.apply({ - filterOn: Excel.FilterOn.dynamic, - dynamicCriteria: Excel.DynamicFilterCriteria.belowAverage - }); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - - language: typescript -template: - content: |+ -
-

This sample shows how to filter the data in a table using different filter types.

-
- -
-

Set up

- - -
- -
-

Try it out

- - -
- - language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/46-table/import-json-data.yaml b/samples/excel/46-table/import-json-data.yaml deleted file mode 100644 index 937fa71bb..000000000 --- a/samples/excel/46-table/import-json-data.yaml +++ /dev/null @@ -1,153 +0,0 @@ -order: 8 -id: excel-table-import-json-data -name: Import JSON data -description: Imports JSON data into a table. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#import-json-data").click(() => tryCatch(importJsonData)); - - async function importJsonData() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add("A1:D1", true); - expensesTable.name = "ExpensesTable"; - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - - const newData = transactions.map(item => - [item.DATE, item.MERCHANT, item.CATEGORY, item.AMOUNT]); - - expensesTable.rows.add(null, newData); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - const transactions = [ - { - "DATE":"1/1/2017", - "MERCHANT":"The Phone Company", - "CATEGORY":"Communications", - "AMOUNT":"$120" - }, - { - "DATE":"1/1/2017", - "MERCHANT":"Southridge Video", - "CATEGORY":"Entertainment", - "AMOUNT":"$40" - }, - { - "DATE":"1/1/2017", - "MERCHANT":"Coho Winery", - "CATEGORY":"Restaurant", - "AMOUNT":"$47" - }, - { - "DATE":"1/2/2017", - "MERCHANT":"Contoso Ltd", - "CATEGORY":"Shopping", - "AMOUNT":"$56" - }, - { - "DATE":"1/2/2017", - "MERCHANT":"Contoso Ltd", - "CATEGORY":"Shopping", - "AMOUNT":"$110" - }, - { - "DATE":"1/2/2017", - "MERCHANT":"Liberty Bakery & Cafe", - "CATEGORY":"Groceries", - "AMOUNT":"$27" - }, - { - "DATE":"1/2/2017", - "MERCHANT":"Liberty Bakery & Cafe", - "CATEGORY":"Groceries", - "AMOUNT":"$38" - }, - { - "DATE":"1/2/2017", - "MERCHANT":"Northwind Electric Cars", - "CATEGORY":"Transportation", - "AMOUNT":"$42" - }, - { - "DATE":"1/2/2017", - "MERCHANT":"Best For You Organics Company", - "CATEGORY":"Groceries", - "AMOUNT":"$27" - }, - { - "DATE":"1/3/2017", - "MERCHANT":"Contoso, LTD", - "CATEGORY":"Shopping", - "AMOUNT":"$25" - }, - { - "DATE":"1/5/2017", - "MERCHANT":"Munson's Pickles & Preserves Farm", - "CATEGORY":"Groceries", - "AMOUNT":"$178" - } - ]; - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |+ -
-

This sample shows how to import json data into a new table.

-
- -
-

Try it out

- -
- - language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/46-table/resize-table.yaml b/samples/excel/46-table/resize-table.yaml deleted file mode 100644 index 999354183..000000000 --- a/samples/excel/46-table/resize-table.yaml +++ /dev/null @@ -1,108 +0,0 @@ -order: 10 -id: excel-table-resize -name: Resize a table -description: This sample shows how to resize a table. -host: EXCEL -api_set: - ExcelAPI: '1.13' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#resize-table").click(() => tryCatch(resizeTable)); - - async function resizeTable() { - await Excel.run(async (context) => { - // Retrieve the worksheet and a table on that worksheet. - const sheet = context.workbook.worksheets.getItem("Sample"); - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - // Resize the table. - expensesTable.resize("A1:D20"); - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const expensesTable = sheet.tables.add("A1:D1", true /*hasHeaders*/); - expensesTable.name = "ExpensesTable"; - - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - - expensesTable.rows.add(null /*add at the end*/, [ - ["1/1/2017", "The Phone Company", "Communications", "$120"], - ["1/2/2017", "Northwind Electric Cars", "Transportation", "$142"], - ["1/5/2017", "Best For You Organics Company", "Groceries", "$27"], - ["1/10/2017", "Coho Vineyard", "Restaurant", "$33"], - ["1/11/2017", "Bellows College", "Education", "$350"], - ["1/15/2017", "Trey Research", "Other", "$135"], - ["1/15/2017", "Best For You Organics Company", "Groceries", "$97"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to resize a table.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/46-table/sort-data.yaml b/samples/excel/46-table/sort-data.yaml deleted file mode 100644 index 255f6015c..000000000 --- a/samples/excel/46-table/sort-data.yaml +++ /dev/null @@ -1,119 +0,0 @@ -order: 9 -id: excel-table-sort-data -name: Sort data -description: Sorts the data within a table. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#sort-table").click(() => tryCatch(sortTable)); - - async function sortTable() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - // sort the table by the "Amount" column - const sortFields = [ - { - key: 3, - ascending: false - } - ]; - expensesTable.sort.apply(sortFields); - - await context.sync(); - }); - } - - /** Create a new table with sample data */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const sheet = context.workbook.worksheets.getItem("Sample"); - - const expensesTable = sheet.tables.add("A1:D1", true /*hasHeaders*/); - expensesTable.name = "ExpensesTable"; - - expensesTable.getHeaderRowRange().values = [ - ["Date", "Merchant", "Category", "Amount"] - ]; - - expensesTable.rows.add(null /*add at the end*/, [ - ["1/1/2017", "The Phone Company", "Communications", "$120"], - ["1/2/2017", "Northwind Electric Cars", "Transportation", "$142"], - ["1/5/2017", "Best For You Organics Company", "Groceries", "$27"], - ["1/10/2017", "Coho Vineyard", "Restaurant", "$33"], - ["1/11/2017", "Bellows College", "Education", "$350"], - ["1/15/2017", "Trey Research", "Other", "$135"], - ["1/15/2017", "Best For You Organics Company", "Groceries", "$97"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to sort the data in a table.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/50-workbook/create-get-change-delete-settings.yaml b/samples/excel/50-workbook/create-get-change-delete-settings.yaml deleted file mode 100644 index 6c20d2a05..000000000 --- a/samples/excel/50-workbook/create-get-change-delete-settings.yaml +++ /dev/null @@ -1,121 +0,0 @@ -order: 2 -id: excel-settings-create-get-change-delete-settings -name: Add-in settings -description: 'Creates, gets, changes, and deletes settings that are unique to the specific workbook and add-in combination.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#create-setting").click(() => tryCatch(createSetting)); - $("#change-setting").click(() => tryCatch(changeSetting)); - $("#delete-setting").click(() => tryCatch(deleteSetting)); - - async function createSetting() { - await Excel.run(async (context) => { - const settings = context.workbook.settings; - settings.add("NeedsReview", true); - const needsReview = settings.getItem("NeedsReview"); - needsReview.load("value"); - - await context.sync(); - - console.log(`Workbook needs review: ${needsReview.value}`); - }); - } - - async function deleteSetting() { - await Excel.run(async (context) => { - const settings = context.workbook.settings; - let needsReview = settings.getItem("NeedsReview"); - needsReview.delete(); - needsReview = settings.getItemOrNullObject("NeedsReview"); - - await context.sync(); - - if (needsReview.isNullObject) { - console.log("The setting has been deleted"); - } else { - console.log("The setting was not deleted"); - } - - await context.sync(); - }); - } - - async function changeSetting() { - await Excel.run(async (context) => { - const settings = context.workbook.settings; - - // The settings.add method is also how you change a - // setting. There is no settings.setItem or setting.set - // method. - settings.add("NeedsReview", false); - const needsReview = settings.getItem("NeedsReview"); - needsReview.load("value"); - - await context.sync(); - - console.log(`Workbook needs review: ${needsReview.value}`); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create, get, change, and delete settings in the workbook.

-
- -
-

Try it out

-

Press the button to create and display a setting.

- -

Press the button to change setting.

- -

Press the button to delete the setting.

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/50-workbook/create-workbook.yaml b/samples/excel/50-workbook/create-workbook.yaml deleted file mode 100644 index 01840918a..000000000 --- a/samples/excel/50-workbook/create-workbook.yaml +++ /dev/null @@ -1,92 +0,0 @@ -order: 4 -id: excel-workbook-create-workbook -name: Create workbook -description: 'Creates a new, empty workbook and creates a new workbook by copying an existing one.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.8' -script: - content: | - $("#create-new-blank-workbook").click(() => tryCatch(createBlankWorkbook)); - $("#file").change(() => tryCatch(createWorkbookFromExisting)); - - async function createBlankWorkbook() { - await Excel.run(async (context) => { - Excel.createWorkbook(); - }); - } - - async function createWorkbookFromExisting() { - const myFile = document.getElementById("file"); - const reader = new FileReader(); - - reader.onload = ((event) => { - Excel.run(context => { - // Remove the metadata before the Base64-encoded string. - const startIndex = reader.result.toString().indexOf("base64,"); - const myBase64 = reader.result.toString().substr(startIndex + 7); - - Excel.createWorkbook(myBase64); - return context.sync(); - }); - }); - - // Read in the file as a data URL so we can parse the Base64-encoded string. - reader.readAsDataURL(myFile.files[0]); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to create a new, empty workbook and how to create a new workbook by copying an existing one.

-
- -
-

Try it out

-

Create empty workbook

-

-

Copy existing workbook

-

Select an Excel workbook to copy and open in a new instance of Excel.

-
- -
-
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/50-workbook/culture-info-date-time.yaml b/samples/excel/50-workbook/culture-info-date-time.yaml deleted file mode 100644 index e370c1793..000000000 --- a/samples/excel/50-workbook/culture-info-date-time.yaml +++ /dev/null @@ -1,145 +0,0 @@ -order: 6 -id: excel-culture-info-date-time -name: 'Culture info: date and time' -description: This sample shows how to use the read-only cultural settings APIs to retrieve system date and time settings. -host: EXCEL -api_set: - ExcelAPI: '1.12' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#display-date-time-setting").click(() => tryCatch(displayDateTimeSetting)); - $("#write-date-time-setting").click(() => tryCatch(writeDateTimeSetting)); - - async function displayDateTimeSetting() { - await Excel.run(async (context) => { - context.application.cultureInfo.datetimeFormat.load([ - "longDatePattern", - "shortDatePattern", - "dateSeparator", - "longTimePattern", - "timeSeparator" - ]); - await context.sync(); - - // Use the cultural settings API to retrieve the user's system date and time settings. - const systemLongDatePattern = context.application.cultureInfo.datetimeFormat.longDatePattern; - const systemShortDatePattern = context.application.cultureInfo.datetimeFormat.shortDatePattern; - const systemDateSeparator = context.application.cultureInfo.datetimeFormat.dateSeparator; - const systemLongTimePattern = context.application.cultureInfo.datetimeFormat.longTimePattern; - const systemTimeSeparator = context.application.cultureInfo.datetimeFormat.timeSeparator; - - // Display the date and time settings in your console. - console.log("System date/time settings: "); - console.log(` System long date format: ${systemLongDatePattern}`); - console.log(` System short date format: ${systemShortDatePattern}`); - console.log(` System date separator: ${systemDateSeparator}`); - console.log(` System long time format: ${systemLongTimePattern}`); - console.log(` System time separator: ${systemTimeSeparator}`); - - await context.sync(); - }); - } - - async function writeDateTimeSetting() { - await Excel.run(async (context) => { - context.application.cultureInfo.datetimeFormat.load([ - "longDatePattern", - "shortDatePattern", - "dateSeparator", - "longTimePattern", - "timeSeparator" - ]); - await context.sync(); - - // Use the cultural settings API to retrieve the user's system date and time settings. - const systemLongDatePattern = context.application.cultureInfo.datetimeFormat.longDatePattern; - const systemShortDatePattern = context.application.cultureInfo.datetimeFormat.shortDatePattern; - const systemDateSeparator = context.application.cultureInfo.datetimeFormat.dateSeparator; - const systemLongTimePattern = context.application.cultureInfo.datetimeFormat.longTimePattern; - const systemTimeSeparator = context.application.cultureInfo.datetimeFormat.timeSeparator; - - // Write the date and time settings in your table. - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const dateTimeData = sheet.getRange("A2:B6"); - dateTimeData.values = [ - ["Long date", systemLongDatePattern], - ["Short date", systemShortDatePattern], - ["Date separator", systemDateSeparator], - ["Long time format", systemLongTimePattern], - ["Time separator", systemTimeSeparator] - ]; - - sheet.tables - .getItemAt(0) - .getRange() - .format.autofitColumns(); - - await context.sync(); - }); - } - - /** Create a table with only header content. */ - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - const range = sheet.getRange("A1:B1"); - range.values = [["Culture Setting", "Setting Format"]]; - const table = sheet.tables.add("A1:B6", true); - range.format.autofitColumns(); - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to use the read-only cultural settings APIs to retrieve system date and time settings.

-
-
-

Setup

-
-
-

Try it out

- -

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/50-workbook/culture-info.yaml b/samples/excel/50-workbook/culture-info.yaml deleted file mode 100644 index b7aaaa803..000000000 --- a/samples/excel/50-workbook/culture-info.yaml +++ /dev/null @@ -1,159 +0,0 @@ -order: 5 -id: excel-culture-info -name: Culture info -description: This sample shows how to apply the cultural settings APIs to help normalize data. -host: EXCEL -api_set: - ExcelApi: '1.11' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#display-culture-info").click(() => tryCatch(displayCultureInfo)); - $("#write-decimal").click(() => tryCatch(writeDecimal)); - $("#write-big-number").click(() => tryCatch(writeBigNumber)); - - async function displayCultureInfo() { - await Excel.run(async (context) => { - context.application.load("decimalSeparator,thousandsSeparator"); - context.application.cultureInfo.numberFormat.load("numberDecimalSeparator,numberGroupSeparator"); - await context.sync(); - - // Local settings are set under the "Options > Advanced" menu. - const localDecimalSeparator = context.application.decimalSeparator; - const localThousandsSeparator = context.application.thousandsSeparator; - - const systemDecimalSeparator = context.application.cultureInfo.numberFormat.numberDecimalSeparator; - const systemThousandsSeparator = context.application.cultureInfo.numberFormat.numberGroupSeparator; - - console.log("Local character settings: "); - console.log(` Local decimal separator: ${localDecimalSeparator}`); - console.log(` Local thousands separator: ${localThousandsSeparator}`); - - console.log("System culture settings: "); - console.log(` System decimal separator: ${systemDecimalSeparator}`); - console.log(` System thousands separator: ${systemThousandsSeparator}`); - console.log(` `); - - await context.sync(); - }); - } - - async function writeDecimal() { - // This will convert a number like "14,37" to "14.37" - // (assuming the system decimal separator is "."). - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const decimalSource = sheet.getRange("B2"); - decimalSource.load("values"); - context.application.cultureInfo.numberFormat.load("numberDecimalSeparator"); - await context.sync(); - - const systemDecimalSeparator = context.application.cultureInfo.numberFormat.numberDecimalSeparator; - const oldDecimalString: string = decimalSource.values[0][0]; - - // This assumes the input column is standardized to use "," as the decimal separator. - const newDecimalString = oldDecimalString.replace(",", systemDecimalSeparator); - - const resultRange = sheet.getRange("C2"); - resultRange.values = [[newDecimalString]]; - resultRange.format.autofitColumns(); - await context.sync(); - }); - } - - async function writeBigNumber() { - await Excel.run(async (context) => { - // This will convert a number like "123-456-789" to "123,456,789" - // (assuming the system thousands separator is ","). - const sheet = context.workbook.worksheets.getItem("Sample"); - const bigNumberSource = sheet.getRange("B3"); - bigNumberSource.load("values"); - context.application.cultureInfo.numberFormat.load("numberGroupSeparator"); - await context.sync(); - - const systemThousandsSeparator = context.application.cultureInfo.numberFormat.numberGroupSeparator; - const oldBigNumberString: string = bigNumberSource.values[0][0]; - - // This assumes the input column is standardized to use "-" as the number group separator. - const newBigNumberString = oldBigNumberString.replace(/-/g, systemThousandsSeparator); - - const resultRange = sheet.getRange("C3"); - resultRange.values = [[newBigNumberString]]; - resultRange.format.autofitColumns(); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - const range = sheet.getRange("A1:C3"); - range.values = [["", "Stored", "Converted"], ["Decimal", "14,37", ""], ["Large Number", "123-456-789", ""]]; - range.format.autofitColumns(); - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to apply the cultural settings APIs to help normalize data.

-
- -
-

Setup

- -
- -
-

Try it out

- - - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/50-workbook/data-protection.yaml b/samples/excel/50-workbook/data-protection.yaml deleted file mode 100644 index 07123e44a..000000000 --- a/samples/excel/50-workbook/data-protection.yaml +++ /dev/null @@ -1,265 +0,0 @@ -order: 7 -id: excel-workbook-data-protection -name: Data protection -description: Protects data in a worksheet and the workbook structure. -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#protect-data-in-worksheet").click(() => tryCatch(protectDataInWorksheet)); - $("#unprotect-data-in-worksheet").click(() => tryCatch(unprotectDataInWorksheet)); - $("#protect-workbook-structure").click(() => tryCatch(protectWorkbookStructure)); - $("#unprotect-workbook-structure").click(() => tryCatch(unprotectWorkbookStructure)); - $("#password-protect-data-in-worksheet").click(() => tryCatch(passwordProtectDataInWorksheet)); - $("#password-unprotect-data-in-worksheet").click(() => tryCatch(passwordUnprotectDataInWorksheet)); - $("#password-protect-workbook-structure").click(() => tryCatch(passwordProtectWorkbookStructure)); - $("#password-unprotect-workbook-structure").click(() => tryCatch(passwordUnprotectWorkbookStructure)); - - async function protectDataInWorksheet() { - await Excel.run(async (context) => { - let activeSheet = context.workbook.worksheets.getActiveWorksheet(); - activeSheet.load("protection/protected"); - - await context.sync(); - - if (!activeSheet.protection.protected) { - activeSheet.protection.protect(); - } - }); - } - - async function unprotectDataInWorksheet() { - await Excel.run(async (context) => { - let activeSheet = context.workbook.worksheets.getActiveWorksheet(); - activeSheet.protection.unprotect(); - }); - } - - async function protectWorkbookStructure() { - await Excel.run(async (context) => { - let workbook = context.workbook; - workbook.load("protection/protected"); - - await context.sync(); - - if (!workbook.protection.protected) { - workbook.protection.protect(); - } - }); - } - - async function unprotectWorkbookStructure() { - await Excel.run(async (context) => { - let workbook = context.workbook; - workbook.protection.unprotect(); - }); - } - - async function passwordProtectDataInWorksheet() { - let password = await passwordHandler(); - passwordHelper(password); - await Excel.run(async (context) => { - let activeSheet = context.workbook.worksheets.getActiveWorksheet(); - activeSheet.load("protection/protected"); - - await context.sync(); - - if (!activeSheet.protection.protected) { - activeSheet.protection.protect(null, password); - } - }); - } - - async function passwordUnprotectDataInWorksheet() { - let password = await passwordHandler(); - passwordHelper(password); - await Excel.run(async (context) => { - let activeSheet = context.workbook.worksheets.getActiveWorksheet(); - activeSheet.protection.unprotect(password); - }); - } - - async function passwordProtectWorkbookStructure() { - let password = await passwordHandler(); - passwordHelper(password); - await Excel.run(async (context) => { - let workbook = context.workbook; - workbook.load("protection/protected"); - - await context.sync(); - - if (!workbook.protection.protected) { - workbook.protection.protect(password); - } - }); - } - - async function passwordUnprotectWorkbookStructure() { - let password = await passwordHandler(); - passwordHelper(password); - await Excel.run(async (context) => { - let workbook = context.workbook; - workbook.protection.unprotect(password); - }); - } - - function passwordHelper(password: string) { - - if (null == password || password.trim() == "") { - let errorMessage = "Password is expected but not provided"; - console.log(errorMessage); - } - } - - async function passwordHandler(): Promise { - let settingName = "TheTestPasswordUsedByThisSnippet"; - let savedPassword = Office.context.document.settings.get(settingName); - if (null == savedPassword || savedPassword.trim() == "") { - let item = document.getElementById("test-password"); - let testPassword = item.hasAttribute("value") ? item.getAttribute("value") : null; - if (null != testPassword && testPassword.trim() != "") { - // store test password for retrieval upon re-opening this workbook - Office.context.document.settings.set(settingName, testPassword); - await Office.context.document.settings.saveAsync(); - - savedPassword = testPassword; - } - } else { - document.getElementById("test-password").setAttribute("value", savedPassword); - } - - console.log("Test password is " + savedPassword); - - return savedPassword; - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add('A1:E1', true); - expensesTable.name = "SalesTable"; - - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to protect a worksheet's data and the workbook's structure.

-
- -
-

Set up

- -
- -
-

Try it out

-

Protect without password

-

-

Click the next button and then notice that you cannot edit data in the worksheet.

- -

-

- -

-

-

Click the next button and then notice that you cannot add or delete a worksheet.

- -

-

- -

-

Protect with password

- - -

-

Click the next button and then notice that you cannot edit data in the worksheet.

- -

-

- -

-

-

Click the next button and then notice that you cannot add or delete a worksheet.

- -

-

- -

-
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/50-workbook/workbook-calculation.yaml b/samples/excel/50-workbook/workbook-calculation.yaml deleted file mode 100644 index 8a5c101cc..000000000 --- a/samples/excel/50-workbook/workbook-calculation.yaml +++ /dev/null @@ -1,194 +0,0 @@ -order: 3 -id: excel-workbook-calculation -name: Calculations -description: 'Demonstrates the calculation APIs of the workbook: events for when the worksheet recalculates and application-level calculation controls.' -host: EXCEL -api_set: - ExcelApi: '1.11' -script: - content: | - $("#setup").click(() => tryCatch(setup)); $("#register-onCalculated-handler").click(() => tryCatch(registerOnCalculatedHandler)); $("#recalculate-single").click(() => tryCatch(recalculateSingle)); $("#recalculate-column").click(() => tryCatch(recalculateColumn)); $("#manual-calculations").click(() => tryCatch(switchToManualCalculations)); $("#automatic-calculations").click(() => tryCatch(switchToAutomaticCalculations)); $("#force-calculation").click(() => tryCatch(forceCalculation)); - async function registerOnCalculatedHandler() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - sheet.onCalculated.add(onCalculated); - await context.sync(); - - console.log("Added a worksheet-level on-calculated event handler."); - }); - } - - async function onCalculated(event: Excel.WorksheetCalculatedEventArgs) { - await Excel.run(async (context) => { - // `event.address` returns the address of the range that completed calculation. - // If multiple ranges completed calculation, the string is a comma-separated list of those range addresses. - console.log(`The Range ${event.address} has recalculated.`); - }); - } - - async function recalculateSingle() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const randomRow = Math.floor(Math.random() * 6); - const randomColumn = Math.floor(Math.random() * 4); - const randomResult = Math.floor(Math.random() * 10000); - - const cellToChange = sheet.getRange("B2:E7").getCell(randomRow, randomColumn); - - cellToChange.load("address"); - await context.sync(); - console.log(`Changing cell ${cellToChange.address}`); - - cellToChange.values = [[randomResult]]; - await context.sync(); - }); - } - - async function recalculateColumn() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const columnToChange = sheet.getRange("B2:B7"); - columnToChange.load("address"); - await context.sync(); - - console.log(`Changing Range ${columnToChange.address}`); - - columnToChange.values = [ - [Math.floor(Math.random() * 10000)], - [Math.floor(Math.random() * 10000)], - [Math.floor(Math.random() * 10000)], - [Math.floor(Math.random() * 10000)], - [Math.floor(Math.random() * 10000)], - [Math.floor(Math.random() * 10000)] - ]; - await context.sync(); - }); - } - - async function switchToManualCalculations() { - await Excel.run(async (context) => { - context.application.calculationMode = Excel.CalculationMode.manual; - context.application.load("calculationMode"); - await context.sync(); - - console.log("Current calculation mode: " + context.application.calculationMode); - }); - } - - async function switchToAutomaticCalculations() { - await Excel.run(async (context) => { - context.application.calculationMode = Excel.CalculationMode.automatic; - context.application.load("calculationMode"); - await context.sync(); - - console.log("Current calculation mode: " + context.application.calculationMode); - }); - } - - async function forceCalculation() { - await Excel.run(async (context) => { - context.application.calculate(Excel.CalculationType.recalculate); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let salesTable = sheet.tables.add("A1:F1", true); - salesTable.name = "SalesTable"; - - salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4", "Total"]]; - - salesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377, "=SUM(B2:E2)"], - ["Saddles", 400, 323, 276, 651, "=SUM(B3:E3)"], - ["Brake levers", 12000, 8766, 8456, 9812, "=SUM(B4:E4)"], - ["Chains", 1550, 1088, 692, 853, "=SUM(B5:E5)"], - ["Mirrors", 225, 600, 923, 544, "=SUM(B6:E6)"], - ["Spokes", 6005, 7634, 4589, 8765, "=SUM(B7:E7)"] - ]); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to use the calculation APIs.

-
- -
-

Set up

- -
- -
-

Try it out

- -

Calculation events

- -

Use these buttons to change data in the table or manually edit the worksheet.

- - - -

Manual calculations

-

Try switching to manual calculation, then editing the workbook.

- - - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/50-workbook/workbook-get-active-cell.yaml b/samples/excel/50-workbook/workbook-get-active-cell.yaml deleted file mode 100644 index 6b56e6c76..000000000 --- a/samples/excel/50-workbook/workbook-get-active-cell.yaml +++ /dev/null @@ -1,73 +0,0 @@ -order: 1 -id: excel-workbook-get-active-cell -name: Active cell -description: Gets the active cell of the entire workbook. -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#get-active-cell").click(() => tryCatch(run)); - - async function run() { - await Excel.run(async (context) => { - - let myWorkbook = context.workbook; - let activeCell = myWorkbook.getActiveCell(); - activeCell.load("address"); - - await context.sync(); - - console.log("The active cell is " + activeCell.address); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to get the active cell of the entire workbook.

-
- -
-

Try it out

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml b/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml deleted file mode 100644 index 4f502f69c..000000000 --- a/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml +++ /dev/null @@ -1,101 +0,0 @@ -order: 9 -id: excel-workbook-insert-external-worksheets -name: Insert external worksheets -description: Inserts worksheets from another workbook into the current workbook. -host: EXCEL -api_set: - ExcelAPI: '1.13' -script: - content: | - $("#file").change(getBase64); - $("#insert-sheets").click(() => tryCatch(insertSheets)); - - let externalWorkbook; - - async function getBase64() { - // Retrieve the file and set up an HTML FileReader element. - const myFile = document.getElementById("file"); - const reader = new FileReader(); - - reader.onload = (event) => { - // Remove the metadata before the Base64-encoded string. - const startIndex = reader.result.toString().indexOf("base64,"); - externalWorkbook = reader.result.toString().substr(startIndex + 7); - }; - - // Read the file as a data URL so that we can parse the Base64-encoded string. - reader.readAsDataURL(myFile.files[0]); - } - - async function insertSheets() { - await Excel.run(async (context) => { - // Retrieve the source workbook. - const workbook = context.workbook; - - // Set up the insert options. - const options = { - sheetNamesToInsert: [], // Insert all the worksheets from the source workbook. - positionType: Excel.WorksheetPositionType.after, // Insert after the `relativeTo` sheet. - relativeTo: "Sheet1" // The sheet relative to which the other worksheets will be inserted. Used with `positionType`. - }; - - // Insert the new worksheets. - workbook.insertWorksheetsFromBase64(externalWorkbook, options); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to copy the worksheets from an existing workbook into the current workbook.

-
- -
-

Try it out

-

Select an Excel workbook to copy its worksheets into the current workbook.

-
- -
-
-

Insert the worksheets from the selected workbook.

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/50-workbook/workbook-save-and-close.yaml b/samples/excel/50-workbook/workbook-save-and-close.yaml deleted file mode 100644 index c93326fad..000000000 --- a/samples/excel/50-workbook/workbook-save-and-close.yaml +++ /dev/null @@ -1,95 +0,0 @@ -order: 8 -id: excel-workbook-save-and-close -name: Save and close -description: Saves and closes a workbook. -host: EXCEL -api_set: - ExcelAPI: '1.11' -script: - content: | - $("#saveWithPrompt").click(() => tryCatch(saveWithPrompt)); - $("#saveWithoutPrompt").click(() => tryCatch(saveWithoutPrompt)); - $("#closeWithSave").click(() => tryCatch(closeWithSave)); - $("#closeWithoutSave").click(() => tryCatch(closeWithoutSave)); - - async function saveWithPrompt() { - await Excel.run(async (context) => { - context.workbook.save(Excel.SaveBehavior.prompt); - }); - } - - async function saveWithoutPrompt() { - await Excel.run(async (context) => { - context.workbook.save(Excel.SaveBehavior.save); - }); - } - - async function closeWithSave() { - await Excel.run(async (context) => { - context.workbook.close(Excel.CloseBehavior.save); - }); - } - - async function closeWithoutSave() { - await Excel.run(async (context) => { - context.workbook.close(Excel.CloseBehavior.skipSave); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to save a workbook, both with and without a prompt to the user, and how to close the workbook.

-
- -
-

Try it out

-

-

-

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/54-worksheet/active-worksheet.yaml b/samples/excel/54-worksheet/active-worksheet.yaml deleted file mode 100644 index cabb12f81..000000000 --- a/samples/excel/54-worksheet/active-worksheet.yaml +++ /dev/null @@ -1,132 +0,0 @@ -order: 1 -id: excel-worksheet-active-worksheet -name: Active worksheet -description: Gets and sets the active worksheet. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.1' -script: - content: |- - $("#setup").click(() => tryCatch(setup)); - - $("#get-active-worksheet").click(() => tryCatch(getActiveWorksheet)); - $("#set-active-worksheet").click(() => tryCatch(setActiveWorksheet)); - - async function getActiveWorksheet() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - sheet.load("name"); - - await context.sync(); - - console.log(`The active worksheet is "${sheet.name}"`); - }); - } - - async function setActiveWorksheet() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - sheet.load("name"); - - const sheets = context.workbook.worksheets; - sheets.load("items"); - - await context.sync(); - - let newSheet = sheet; - - if (sheets.items.length > 1) { - if (sheet.id === sheets.items[0].id) { - newSheet = sheets.items[1]; - } else { - newSheet = sheets.items[0]; - } - newSheet.load("name"); - - newSheet.activate(); - - await context.sync(); - } else { - console.log("Cannot change the active worksheet since there is only one sheet in the workbook"); - } - - console.log(`The active worksheet is "${newSheet.name}"`); - }); - } - - async function setup() { - await Excel.run(async (context) => { - - const sheets = context.workbook.worksheets; - sheets.load("items"); - - await context.sync(); - - if (sheets.items.length < 2) { - sheets.add(); - - await context.sync(); - } - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to get and set the active worksheet.

-
- -
-

Set up

- -
- -
-

Try it out

- - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/54-worksheet/add-delete-rename-move-worksheet.yaml b/samples/excel/54-worksheet/add-delete-rename-move-worksheet.yaml deleted file mode 100644 index 904c01b51..000000000 --- a/samples/excel/54-worksheet/add-delete-rename-move-worksheet.yaml +++ /dev/null @@ -1,151 +0,0 @@ -order: 2 -id: excel-worksheet-add-delete-rename-move-worksheet -name: 'Add, delete, rename, and move worksheet' -description: 'Adds, deletes, renames, and moves a worksheet.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.1' -script: - content: | - $("#add-worksheet").click(() => tryCatch(addWorksheet)); - $("#delete-worksheet").click(() => tryCatch(deleteWorksheet)); - $("#rename-worksheet").click(() => tryCatch(renameWorksheet)); - $("#move-worksheet").click(() => tryCatch(moveWorksheet)); - - async function addWorksheet() { - await Excel.run(async (context) => { - const sheets = context.workbook.worksheets; - - const sheet = sheets.add(); - sheet.load("name, position"); - - await context.sync(); - console.log(`Added worksheet named "${sheet.name}" in position ${sheet.position}`) - }); - } - - async function deleteWorksheet() { - await Excel.run(async (context) => { - const sheets = context.workbook.worksheets; - sheets.load("items/name"); - - await context.sync(); - - if (sheets.items.length > 1) { - const lastSheet = sheets.items[sheets.items.length - 1]; - - console.log(`Deleting worksheet named "${lastSheet.name}"`); - lastSheet.delete(); - - await context.sync(); - - } else { - console.log("Unable to delete the last worksheet in the workbook"); - } - }); - } - - async function renameWorksheet() { - await Excel.run(async (context) => { - const currentSheet = context.workbook.worksheets.getActiveWorksheet(); - - currentSheet.name = await uniqueWorksheetName(context); - - await context.sync(); - console.log(`Renamed worksheet to "${currentSheet.name}"`); - }); - } - - async function uniqueWorksheetName(context: Excel.RequestContext) { - let number = 1; - let name: string; - while (true) { - name = `Renamed${number}`; - - try { - const sheet = context.workbook.worksheets.getItem(name); - - await context.sync(); - - ++number; - } - catch (e) { - break; - } - } - return name; - } - - async function moveWorksheet() { - await Excel.run(async (context) => { - const sheets = context.workbook.worksheets; - sheets.load("items"); - await context.sync(); - - const lastSheet = sheets.items[sheets.items.length - 1]; - lastSheet.position = 0; - - await context.sync(); - console.log(`Moved worksheet "${lastSheet.name}" to tab position "${lastSheet.position}"`); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to add, delete, rename and change the position of a worksheet.

-
- -
-

Try it out

-

-

-

- -

- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/54-worksheet/gridlines.yaml b/samples/excel/54-worksheet/gridlines.yaml deleted file mode 100644 index ed691a166..000000000 --- a/samples/excel/54-worksheet/gridlines.yaml +++ /dev/null @@ -1,86 +0,0 @@ -order: 8 -id: excel-worksheet-gridlines -name: Gridlines -description: Hides and shows a worksheet's gridlines. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.8' -script: - content: | - $("#hide-gridlines").click(() => tryCatch(hideGridlines)); - $("#show-gridlines").click(() => tryCatch(showGridlines)); - - async function hideGridlines() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - sheet.showGridlines = false; - - await context.sync(); - }); - } - - async function showGridlines() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - sheet.showGridlines = true; - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |+ -
-

This sample shows how to hide and show gridlines within a worksheet.

-
- -
-

Try it out

- - - - -
- - language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/54-worksheet/list-worksheets.yaml b/samples/excel/54-worksheet/list-worksheets.yaml deleted file mode 100644 index 50e56f674..000000000 --- a/samples/excel/54-worksheet/list-worksheets.yaml +++ /dev/null @@ -1,79 +0,0 @@ -order: 9 -id: excel-worksheet-list-worksheets -name: List worksheets -description: Lists the worksheets in the workbook. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.1' -script: - content: | - $("#list-worksheets").click(() => tryCatch(listWorksheets)); - - async function listWorksheets() { - await Excel.run(async (context) => { - const sheets = context.workbook.worksheets; - sheets.load("items/name"); - - await context.sync(); - - if (sheets.items.length > 1) { - console.log(`There are ${sheets.items.length} worksheets in the workbook:`); - } else { - console.log(`There is one worksheet in the workbook:`); - } - for (let i in sheets.items) { - console.log(sheets.items[i].name); - } - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to list the names of the worksheets in the workbook.

-
- -
-

Try it out

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml b/samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml deleted file mode 100644 index da01e093a..000000000 --- a/samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml +++ /dev/null @@ -1,170 +0,0 @@ -order: 11 -id: excel-worksheet-reference-worksheets-by-relative-position -name: Reference worksheets by relative position -description: Gets a worksheet by using its relative position within the workbook. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.5' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#compare-current-and-previous-year").click(() => tryCatch(compareCurrentWithPreviousTax)); - $("#compare-first-and-last-year").click(() => tryCatch(compareFirstWithMostRecentTaxRate)); - - async function setup() { - await Excel.run(async (context) => { - const sheets = context.workbook.worksheets; - sheets.load("NoPropertiesNeeded"); - - await context.sync(); - - // Make setup repeatable by deleting all worksheets, - // except the default. Note: DEcrement on each loop. - for (let i = sheets.items.length; i > 0; i--) { - if (sheets.items[i]) { - sheets.items[i].delete(); - } - } - - let currentYearSheet: Excel.Worksheet; - let revenue = 10000; - let taxRate = .213; - - for (let year = 2014; year < 2018; year++) { - let sheet = sheets.add(); - sheet.name = `Taxes${year}`; - let taxDataTable = sheet.tables.add('A1:C1', true); - - // Table names must be unique within the whole workbook. - taxDataTable.name = `TaxesCalculation${year}`; - taxDataTable.getHeaderRowRange().values = [["Revenue", "Tax Rate", "Tax Due"]]; - taxDataTable.rows.add(null, [ - [revenue, taxRate, "=A2 * B2"], - ]); - sheet.getRange("A2").numberFormat = [["$#,##0.00"]]; - sheet.getRange("B2").numberFormat = [["0.00%"]]; - sheet.getRange("C2").numberFormat = [["$#,##0.00"]]; - taxDataTable.getRange().format.autofitColumns(); - taxDataTable.getRange().format.autofitRows(); - currentYearSheet = sheet; - revenue += 150; - taxRate += .0025; - } - currentYearSheet.activate(); - - await context.sync(); - }); - } - - async function compareCurrentWithPreviousTax() { - await Excel.run(async (context) => { - const sheets = context.workbook.worksheets; - const currentSheet = sheets.getActiveWorksheet(); - const previousYearSheet = currentSheet.getPrevious(); - const currentTaxDueRange = currentSheet.getRange("C2"); - const previousTaxDueRange = previousYearSheet.getRange("C2"); - - currentSheet.load("name"); - previousYearSheet.load("name"); - currentTaxDueRange.load("text"); - previousTaxDueRange.load("text"); - - await context.sync(); - - let currentYear = currentSheet.name.substr(5, 4); - let previousYear = previousYearSheet.name.substr(5, 4); - console.log("Two Year Tax Due Comparison", `Tax due for ${currentYear} was ${currentTaxDueRange.text[0][0]}\nTax due for ${previousYear} was ${previousTaxDueRange.text[0][0]}`) - - await context.sync(); - }); - } - - async function compareFirstWithMostRecentTaxRate() { - await Excel.run(async (context) => { - const sheets = context.workbook.worksheets; - - // We don't want to include the default worksheet that was created - // when the workbook was created, so our "firstSheet" will be the one - // after the literal first. Note chaining of navigation methods. - const firstSheet = sheets.getFirst().getNext(); - const lastSheet = sheets.getLast(); - const firstTaxRateRange = firstSheet.getRange("B2"); - const lastTaxRateRange = lastSheet.getRange("B2"); - - firstSheet.load("name"); - lastSheet.load("name"); - firstTaxRateRange.load("text"); - lastTaxRateRange.load("text"); - - await context.sync(); - - let firstYear = firstSheet.name.substr(5, 4); - let lastYear = lastSheet.name.substr(5, 4); - console.log(`Tax Rate change from ${firstYear} to ${lastYear}`, `Tax rate for ${firstYear}: ${firstTaxRateRange.text[0][0]}\nTax rate for ${lastYear}: ${lastTaxRateRange.text[0][0]}`) - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to get a reference to a sheet using its relative worksheet position.

-
- -
-

Set up

- -
- -
-

Try it out

-

Select any of the three worksheets for 2015, 1016, or 2017 and press the button to compare the tax due on the current sheet with the previous sheet.

- -

Compare the tax rate on the last sheet with the first sheet.

- -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/54-worksheet/tab-color.yaml b/samples/excel/54-worksheet/tab-color.yaml deleted file mode 100644 index 7e2656a1f..000000000 --- a/samples/excel/54-worksheet/tab-color.yaml +++ /dev/null @@ -1,115 +0,0 @@ -order: 12 -id: excel-worksheet-tab-color -name: Tab color -description: Gets and sets the tab color of a worksheet. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#set-tab-color-to-hex-color").click(() => tryCatch(setTabColorToHexColor)); - $("#set-tab-color-to-named-color").click(() => tryCatch(setTabColorToNamedColor)); - $("#set-tab-color-to-default-color").click(() => tryCatch(setTabColorToDefaultColor)); - $("#get-tab-color").click(() => tryCatch(getTabColor)); - - async function setTabColorToHexColor() { - await Excel.run(async (context) => { - const activeSheet = context.workbook.worksheets.getActiveWorksheet(); - activeSheet.tabColor = "#FF0000"; - - await context.sync(); - }); - } - - async function setTabColorToNamedColor() { - await Excel.run(async (context) => { - const activeSheet = context.workbook.worksheets.getActiveWorksheet(); - activeSheet.tabColor = "yellow"; - - await context.sync(); - }); - } - - async function setTabColorToDefaultColor() { - await Excel.run(async (context) => { - const activeSheet = context.workbook.worksheets.getActiveWorksheet(); - activeSheet.tabColor = ""; - - await context.sync(); - }); - } - - async function getTabColor() { - await Excel.run(async (context) => { - const activeSheet = context.workbook.worksheets.getActiveWorksheet(); - activeSheet.load("name, tabColor"); - - await context.sync(); - - let tabColor = activeSheet.tabColor === "" ? "the default color" : activeSheet.tabColor; - console.log(`Tab color for the "${activeSheet.name}" worksheet is ${tabColor}.`); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to set and get the tab color of a worksheet.

-
- -
-

Try it out

- - - - -

- - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/54-worksheet/worksheet-auto-filter.yaml b/samples/excel/54-worksheet/worksheet-auto-filter.yaml deleted file mode 100644 index b172d97fe..000000000 --- a/samples/excel/54-worksheet/worksheet-auto-filter.yaml +++ /dev/null @@ -1,220 +0,0 @@ -order: 3 -id: excel-worksheet-auto-filter -name: AutoFilter -description: Adds an AutoFilter to a worksheet. -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#add-percent-auto-filter").click(() => tryCatch(addPercentAutoFilter)); - $("#add-custom-auto-filter").click(() => tryCatch(addCustomAutoFilter)); - $("#randomize-data").click(() => tryCatch(randomizeData)); - $("#refresh-auto-filter").click(() => tryCatch(refreshAutoFilter)); - $("#clear-single-auto-filter").click(() => tryCatch(clearSingleAutoFilter)); - $("#remove-all-auto-filters").click(() => tryCatch(removeAllAutoFilters)); - - async function addPercentAutoFilter() { - // This function adds a percentage AutoFilter to the active worksheet - // and applies the filter to a column of the used range. - await Excel.run(async (context) => { - // Retrieve the active worksheet and the used range on that worksheet. - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const farmData = sheet.getUsedRange(); - - // Add a filter that will only show the rows with the top 50% of values in column 3. - sheet.autoFilter.apply(farmData, 3, { - criterion1: "50", - filterOn: Excel.FilterOn.topPercent - }); - - await context.sync(); - }); - } - - async function addCustomAutoFilter() { - // This function adds a custom AutoFilter to the active worksheet - // and applies the filter to a column of the used range. - await Excel.run(async (context) => { - // Retrieve the active worksheet and the used range on that worksheet. - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const farmData = sheet.getUsedRange(); - - // Add a filter that will only show the rows with values that end with the letter "e" in column 1. - sheet.autoFilter.apply(farmData, 1, { - criterion1: "=*e", - filterOn: Excel.FilterOn.custom - }); - - await context.sync(); - }); - } - - async function randomizeData() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const farmData = sheet.getUsedRange(); - farmData.load("rowCount"); - await context.sync(); - - for (let i = 1; i < farmData.rowCount; i++) { - farmData.getCell(i, 3).values = [[Math.round(Math.random() * 5000)]]; - } - - await context.sync(); - }); - } - - async function refreshAutoFilter() { - // This function refreshes the AutoFilter to ensure that changes are captured. - await Excel.run(async (context) => { - // Retrieve the active worksheet. - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // Reapply the filter to capture changes. - sheet.autoFilter.reapply(); - await context.sync(); - }); - } - - async function clearSingleAutoFilter() { - // This function clears the AutoFilter setting from one column. - await Excel.run(async (context) => { - // Retrieve the active worksheet. - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // Clear the filter from only column 3. - sheet.autoFilter.clearColumnCriteria(3); - await context.sync(); - }); - } - - async function removeAllAutoFilters() { - // This function removes all AutoFilters from the active worksheet. - await Excel.run(async (context) => { - // Retrieve the active worksheet. - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - // Remove all filters. - sheet.autoFilter.remove(); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const dataSheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Farm", "Type", "Classification", "Crates Sold Wholesale"], - ["A Farms", "Lime", "Organic", 2000], - ["A Farms", "Lemon", "Organic", 1800], - ["A Farms", "Orange", "Organic", 2200], - ["B Farms", "Lime", "Conventional", 1000], - ["B Farms", "Lemon", "Conventional", 1230], - ["B Farms", "Orange", "Conventional", 800], - ["B Farms", "Orange", "Organic", 500], - ["B Farms", "Lemon", "Organic", 770], - ["B Farms", "Kiwi", "Conventional", 300], - ["B Farms", "Lime", "Organic", 400], - ["C Farms", "Apple", "Organic", 220], - ["C Farms", "Kiwi", "Organic", 120], - ["D Farms", "Apple", "Conventional", 3000], - ["D Farms", "Apple", "Organic", 2800], - ["E Farms", "Lime", "Conventional", 2700], - ["E Farms", "Orange", "Conventional", 2000], - ["E Farms", "Apple", "Conventional", 2200], - ["E Farms", "Kiwi", "Conventional", 1500], - ["F Farms", "Kiwi", "Organic", 150], - ["F Farms", "Lemon", "Conventional", 270] - ]; - - const range = dataSheet.getRange("A1:D21"); - range.values = data; - dataSheet.getRange("A1:D1").format.font.bold = true; - range.format.autofitColumns(); - dataSheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to work with an AutoFilter on a worksheet.

-
- -
-

Setup

- -
- -
-

Try it out

-

Add two filters. One shows only the top half of sales and the other shows only fruits that end with the letter 'e'.

- -

- -

- -

-

When the data in the worksheet or table changes, the AutoFilter needs to be refreshed by your add-in.

- -

- -

- -

- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/54-worksheet/worksheet-copy.yaml b/samples/excel/54-worksheet/worksheet-copy.yaml deleted file mode 100644 index bd11af31b..000000000 --- a/samples/excel/54-worksheet/worksheet-copy.yaml +++ /dev/null @@ -1,111 +0,0 @@ -order: 4 -id: excel-worksheet-copy -name: Copy worksheet -description: Copies the active worksheet to the specified location. -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#copy-worksheet").click(() => tryCatch(run)); - - async function run() { - await Excel.run(async (context) => { - - let myWorkbook = context.workbook; - let sampleSheet = myWorkbook.worksheets.getActiveWorksheet(); - let copiedSheet = sampleSheet.copy("End") - - sampleSheet.load("name"); - copiedSheet.load("name"); - - await context.sync(); - - console.log("'" + sampleSheet.name + "' was copied to '" + copiedSheet.name + "'") - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - let expensesTable = sheet.tables.add('A1:E1', true); - expensesTable.name = "SalesTable"; - - expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]]; - - expensesTable.rows.add(null, [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to copy a worksheet.

-
- -
-

Set up

- -
- -
-

Try it out

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/54-worksheet/worksheet-find-all.yaml b/samples/excel/54-worksheet/worksheet-find-all.yaml deleted file mode 100644 index de104f7e4..000000000 --- a/samples/excel/54-worksheet/worksheet-find-all.yaml +++ /dev/null @@ -1,153 +0,0 @@ -order: 5 -id: excel-worksheet-find-all -name: Find text matches within a worksheet -description: Finds cells within a worksheet based on string matching. -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#findCompleted").click(() => tryCatch(findCompleted)); - $("#findDelayed").click(() => tryCatch(findDelayed)); - $("#findCanceled").click(() => tryCatch(findCanceled)); - - async function findCompleted() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const foundRanges = sheet.findAllOrNullObject("Complete", { - completeMatch: true, - matchCase: false - }); - - await context.sync(); - - if (foundRanges.isNullObject) { - console.log("No complete projects"); - } else { - foundRanges.format.fill.color = "green" - } - }); - } - - async function findDelayed() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const foundRanges = sheet.findAllOrNullObject("Delay", { - completeMatch: false, - matchCase: false - }); - - await context.sync(); - - if (foundRanges.isNullObject) { - console.log("No delayed projects"); - } else { - foundRanges.format.fill.color = "yellow" - } - }); - } - - async function findCanceled() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - // NOTE: In this sample, there are no canceled projects. - // Calling sheet.findAll(...) instead of sheet.findAllOrNullObject(...) - // would throw an ItemNotFound error. - const foundRanges = sheet.findAllOrNullObject("canceled", { - completeMatch: false, - matchCase: false - }); - - await context.sync(); - - if (foundRanges.isNullObject) { - console.log("No canceled projects"); - } else { - foundRanges.format.fill.color = "red" - } - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const projectTable = sheet.tables.add("A1:D1", true); - projectTable.name = "ProjectTable"; - projectTable.getHeaderRowRange().values = [["Project", "Alpha", "Beta", "Ship"]]; - projectTable.rows.add(null, [ - ["Project 1", "Complete", "Ongoing", "On Schedule"], - ["Project 2", "Complete", "Complete", "On Schedule"], - ["Project 3", "Ongoing", "Not Started", "Delayed"], - ["Project 4", "Complete", "Complete", "On Schedule"], - ["Project 5", "Incomplete", "Delayed", "Delays Likely"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to find cells with matching string values across an entire worksheet.

-
-
-

Setup

- -
-
-

Try it out

-

-

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/54-worksheet/worksheet-freeze-panes.yaml b/samples/excel/54-worksheet/worksheet-freeze-panes.yaml deleted file mode 100644 index dd8c0f0f8..000000000 --- a/samples/excel/54-worksheet/worksheet-freeze-panes.yaml +++ /dev/null @@ -1,185 +0,0 @@ -order: 6 -id: excel-worksheet-freeze-panes -name: Frozen panes -description: 'Freezes columns, rows, and a range of cells. Gets the address of the frozen pane. Unfreezes frozen panes.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.7' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - - $("#freeze-columns").click(() => tryCatch(freezeColumns)); - $("#freeze-rows").click(() => tryCatch(freezeRows)); - $("#freeze-at").click(() => tryCatch(freezeAt)); - $("#get-location").click(() => tryCatch(getLocation)); - $("#unfreeze-all-panes").click(() => tryCatch(unfreezeAllPanes)); - - async function freezeColumns() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - // Freeze the first two columns in the worksheet. - sheet.freezePanes.freezeColumns(2); - - await context.sync(); - }); - } - - async function freezeRows() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - // Freeze the top two rows in the worksheet. - sheet.freezePanes.freezeRows(2); - - await context.sync(); - }); - } - - async function freezeAt() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - // Freeze the specified range in top-and-left-most pane of the worksheet. - sheet.freezePanes.freezeAt(sheet.getRange("H2:K5")); - - await context.sync(); - }); - } - - async function getLocation() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const frozenRange = sheet.freezePanes.getLocationOrNullObject(); - frozenRange.load("address"); - - await context.sync(); - - if (frozenRange.isNullObject) { - console.log(`The worksheet does not contain a frozen pane.`); - } else { - console.log(`The address of the frozen range (cells that are frozen in the top-and-left-most pane) is "${frozenRange.address}"`); - } - }); - } - - async function unfreezeAllPanes() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - sheet.freezePanes.unfreeze(); - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const productsData1 = [ - ["Vegetables", "Qty", "Unit Price", "Total Price"], - ["Potatoes", 10, 1.00, "=D3 * E3"], - ["Peppers", 7, 2.50, "=D4 * E4"], - ["Lettuce", 5, 1.50, "=D5 * E5"] - ]; - - const range1 = sheet.getRange("C2:F5"); - range1.values = productsData1; - range1.format.autofitColumns(); - - const header1 = range1.getResizedRange(-3, 0); - header1.format.fill.color = "yellow"; - header1.format.font.bold = true; - - const productsData2 = [ - ["Fruit", "Qty", "Unit Price", "Total Price"], - ["Apples", 10, 2.00, "=I3 * J3"], - ["Bananas", 5, 0.75, "=I4 * J4"], - ["Melons", 8, 3.50, "=I5 * J5"] - ]; - - const range2 = sheet.getRange("H2:K5"); - range2.values = productsData2; - range2.format.autofitColumns(); - - const header2 = range2.getResizedRange(-3, 0); - header2.format.fill.color = "green"; - header2.format.font.bold = true; - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to freeze columns, freeze rows, freeze a range, and manage frozen panes in a worksheet.

-
- -
-

Set up

- -
- -
-

Try it out

-

-

-

-

- -

- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/54-worksheet/worksheet-page-layout.yaml b/samples/excel/54-worksheet/worksheet-page-layout.yaml deleted file mode 100644 index 64c36ead9..000000000 --- a/samples/excel/54-worksheet/worksheet-page-layout.yaml +++ /dev/null @@ -1,216 +0,0 @@ -order: 10 -id: excel-worksheet-page-layout -name: Page layout and print settings -description: Changes the page layout and other settings for printing a worksheet. -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#setPageBreaks").click(() => tryCatch(setPageBreaks)); - $("#center").click(() => tryCatch(center)); - $("#setBlackAndWhite").click(() => tryCatch(setBlackAndWhite)); - $("#setPrintTitleRow").click(() => tryCatch(setPrintTitleRow)); - $("#setPrintArea").click(() => tryCatch(setPrintArea)); - $("#changeOrientation").click(() => tryCatch(changeOrientation)); - $("#setZoom").click(() => tryCatch(setZoom)); - - async function setPageBreaks() { - await Excel.run(async (context) => { - const farmSheet = context.workbook.worksheets.getItem("Print"); - farmSheet.horizontalPageBreaks.add("A21:E21"); - await context.sync(); - }); - } - - async function center() { - await Excel.run(async (context) => { - const farmSheet = context.workbook.worksheets.getItem("Print"); - farmSheet.pageLayout.centerHorizontally = true; - farmSheet.pageLayout.centerVertically = true; - await context.sync(); - }); - } - - async function setBlackAndWhite() { - await Excel.run(async (context) => { - const farmSheet = context.workbook.worksheets.getItem("Print"); - farmSheet.pageLayout.blackAndWhite = true; - await context.sync(); - }); - } - - async function setPrintTitleRow() { - await Excel.run(async (context) => { - const farmSheet = context.workbook.worksheets.getItem("Print"); - farmSheet.pageLayout.setPrintTitleRows("$1:$1"); - await context.sync(); - }); - } - - async function setPrintArea() { - await Excel.run(async (context) => { - const farmSheet = context.workbook.worksheets.getItem("Print"); - farmSheet.pageLayout.setPrintArea("A1:D41"); - await context.sync(); - }); - } - - async function changeOrientation() { - await Excel.run(async (context) => { - const farmSheet = context.workbook.worksheets.getItem("Print"); - farmSheet.pageLayout.orientation = Excel.PageOrientation.landscape; - await context.sync(); - }); - } - - async function setZoom() { - await Excel.run(async (context) => { - const farmSheet = context.workbook.worksheets.getItem("Print"); - farmSheet.pageLayout.zoom = { scale: 200 }; - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Print").delete(); - const printSheet = context.workbook.worksheets.add("Print"); - - let farmTable = printSheet.tables.add("A1:E1", true); - farmTable.name = "FarmTable"; - farmTable.getHeaderRowRange().values = [ - ["Farm", "Type", "Classification", "Crates Sold at Farm", "Crates Sold Wholesale"] - ]; - - farmTable.rows.add(null, [ - ["A Farms", "Lime", "Organic", 300, 2000], - ["A Farms", "Lemon", "Organic", 250, 1800], - ["A Farms", "Orange", "Organic", 200, 2200], - ["B Farms", "Lime", "Conventional", 80, 1000], - ["B Farms", "Lemon", "Conventional", 75, 1230], - ["B Farms", "Orange", "Conventional", 25, 800], - ["B Farms", "Orange", "Organic", 20, 500], - ["B Farms", "Lemon", "Organic", 10, 770], - ["B Farms", "Kiwi", "Conventional", 30, 300], - ["B Farms", "Lime", "Organic", 50, 400], - ["C Farms", "Apple", "Organic", 275, 220], - ["C Farms", "Kiwi", "Organic", 200, 120], - ["D Farms", "Apple", "Conventional", 100, 3000], - ["D Farms", "Apple", "Organic", 80, 2800], - ["E Farms", "Lime", "Conventional", 160, 2700], - ["E Farms", "Orange", "Conventional", 180, 2000], - ["E Farms", "Apple", "Conventional", 245, 2200], - ["E Farms", "Kiwi", "Conventional", 200, 1500], - ["F Farms", "Kiwi", "Organic", 100, 150], - ["F Farms", "Lemon", "Conventional", 150, 270], - ["G Farms", "Lime", "Organic", 300, 2000], - ["G Farms", "Lemon", "Organic", 250, 1800], - ["G Farms", "Orange", "Organic", 200, 2200], - ["H Farms", "Lime", "Conventional", 80, 1000], - ["H Farms", "Lemon", "Conventional", 75, 1230], - ["H Farms", "Orange", "Conventional", 25, 800], - ["H Farms", "Orange", "Organic", 20, 500], - ["H Farms", "Lemon", "Organic", 10, 770], - ["H Farms", "Kiwi", "Conventional", 30, 300], - ["I Farms", "Lime", "Organic", 50, 400], - ["I Farms", "Apple", "Organic", 275, 220], - ["I Farms", "Kiwi", "Organic", 200, 120], - ["I Farms", "Apple", "Conventional", 100, 3000], - ["J Farms", "Apple", "Organic", 80, 2800], - ["J Farms", "Lime", "Conventional", 160, 2700], - ["K Farms", "Orange", "Conventional", 180, 2000], - ["K Farms", "Apple", "Conventional", 245, 2200], - ["L Farms", "Kiwi", "Conventional", 200, 1500], - ["L Farms", "Kiwi", "Organic", 100, 150], - ["L Farms", "Lemon", "Conventional", 150, 270] - ]); - - farmTable.getRange().format.autofitColumns(); - printSheet.activate(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to change page layout and other settings for printing a worksheet.

-
-
-

Setup

- -
-
-

Try it out

-

In Excel, choose View > Page Layout, then observe the page layout changes as you press the following - buttons.

- -

- -

-

In Excel, choose File > Print to see differences in printing before and after you press the following - buttons.

- -

- -

- -

- -

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 diff --git a/samples/excel/54-worksheet/worksheet-range-cell.yaml b/samples/excel/54-worksheet/worksheet-range-cell.yaml deleted file mode 100644 index 176fe8714..000000000 --- a/samples/excel/54-worksheet/worksheet-range-cell.yaml +++ /dev/null @@ -1,156 +0,0 @@ -order: 7 -id: excel-worksheet-worksheet-range-cell -name: Get range or cell -description: 'Gets the used range, the entire range of a worksheet, the specified range, and the specified cell.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - - $("#get-used-range").click(() => tryCatch(getUsedRange)); - $("#get-entire-range").click(() => tryCatch(getEntireRange)); - $("#get-range").click(() => tryCatch(getRange)); - $("#get-cell").click(() => tryCatch(getCell)); - - async function getUsedRange() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getUsedRange(); - range.load("address"); - - await context.sync(); - - console.log(`The address of the used range in the worksheet is "${range.address}"`); - }); - } - - async function getEntireRange() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange(); - range.load("address"); - - await context.sync(); - - console.log(`The address of the entire worksheet range is "${range.address}"`); - }); - } - - async function getRange() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getRange("B2:C5"); - range.load("address"); - - await context.sync(); - - console.log(`The address of the range B2:C5 is "${range.address}"`); - }); - } - - async function getCell() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const range = sheet.getCell(1, 4); - range.load("address"); - - await context.sync(); - - console.log(`The address of the cell in row 2 column 5 is "${range.address}"`); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const data = [ - ["Product", "Qty", "Unit Price", "Total Price"], - ["Almonds", 2, 7.50, "=C3 * D3"], - ["Coffee", 1, 34.50, "=C4 * D4"], - ["Chocolate", 5, 9.56, "=C5 * D5"] - ]; - - const range = sheet.getRange("B2:E5"); - range.values = data; - range.format.autofitColumns(); - - const header = range.getRow(0); - header.format.fill.color = "#4472C4"; - header.format.font.color = "white"; - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to get a range or a cell in a worksheet.

-
- -
-

Set up

- -
- -
-

Try it out

- - - - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/54-worksheet/worksheet-visibility.yaml b/samples/excel/54-worksheet/worksheet-visibility.yaml deleted file mode 100644 index 2dafa0639..000000000 --- a/samples/excel/54-worksheet/worksheet-visibility.yaml +++ /dev/null @@ -1,131 +0,0 @@ -order: 13 -id: excel-worksheet-visibility -name: Visibility -description: Hides and unhides a worksheet. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.1' -script: - content: | - $("#hide-worksheet").click(() => tryCatch(hideWorksheet)); - $("#unhide-worksheet").click(() => tryCatch(unhideWorksheet)); - - async function hideWorksheet() { - await Excel.run(async (context) => { - - const visibleSheets = await filterWorksheetsByVisibility(context, Excel.SheetVisibility.visible); - - if (visibleSheets.length > 1) { - console.log(`Hiding worksheet named "${visibleSheets[0].name}"...`); - - visibleSheets[0].visibility = Excel.SheetVisibility.hidden; - - await context.sync(); - - } else { - console.log("Cannot hide the only visible worksheet"); - } - }); - } - - async function unhideWorksheet() { - await Excel.run(async (context) => { - - const visibleSheets = await filterWorksheetsByVisibility(context, Excel.SheetVisibility.hidden); - - if (visibleSheets.length > 0) { - console.log(`Unhiding worksheet named "${visibleSheets[0].name}"...`); - - visibleSheets[0].visibility = Excel.SheetVisibility.visible; - - await context.sync(); - - } else { - console.log("No hidden worksheets in the workbook"); - } - }); - } - - async function filterWorksheetsByVisibility(context: Excel.RequestContext, visibility: string): Promise { - const sheets = context.workbook.worksheets; - sheets.load("items/name, items/visibility"); - await context.sync(); - - return sheets.items.filter((s) => (s.visibility === visibility)); - } - - async function setup() { - await Excel.run(async (context) => { - const sheets = context.workbook.worksheets; - sheets.load("items"); - - await context.sync(); - - if (sheets.items.length < 2) { - sheets.add(); - - await context.sync(); - } - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to change the visbility of a worksheet.

-
- -
-

Set up

- -
- -
-

Try it out

- - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/90-scenarios/currency-converter.yaml b/samples/excel/90-scenarios/currency-converter.yaml deleted file mode 100644 index 7e57e9818..000000000 --- a/samples/excel/90-scenarios/currency-converter.yaml +++ /dev/null @@ -1,194 +0,0 @@ -order: 5 -id: excel-scenarios-currency-converter -name: Currency Converter -description: Uses an exchange rate API to convert currency values based on their original transaction times. -author: cakriwut -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - /* - * Copyright (c) Riwut Libinuko. All rights reserved. Licensed under the MIT license. - */ - - declare let moment: any; - const tableName = "TransactionTable"; - - let tableSetup: Record = {}; - - $("#convert").click(() => tryCatch(convert)); - $("#setup").click(() => tryCatch(setupSample)); - - /** Main converting function **/ - async function convert() { - await Excel.run(async (context) => { - const table = context.workbook.tables.getItem(tableName); - table.columns.load("items"); - table.rows.load("items,value"); - await context.sync(); - - if (!isTableValid(table.columns.items)) { - console.error( - 'Error: Some of default table header is missing. Required headers: \r\n"Currency","Price (Currency)","Transaction Date","Base","Price in Base"' - ); - return; - } - - const convertedCurrency = await Promise.all( - table.rows.items.map( (row,idx) => { - const priceInBase = row.values[0][tableSetup["Price in Base"]]; - const priceInCurrency = row.values[0][tableSetup["Price (Currency)"]]; - const transactionDate = row.values[0][tableSetup["Transaction Date"]]; - const currency = row.values[0][tableSetup["Currency"]]; - const baseCurrency = row.values[0][tableSetup["Base"]]; - - if (priceInBase === "") { - const dateMoment = moment.fromOADate(transactionDate); - const period = dateMoment.format("YYYY-MM-DD"); - const queryUrl = convertValue(currency, baseCurrency, period, period); - - const result = fetch(queryUrl).then(response => response.json()); - return result; - } else { - return -1; - } - }) - ); - - let index =0; - let skippedRows = []; - for (let row of table.rows.items) { - const priceBaseRange = row.getRange().getCell(0, tableSetup["Price in Base"]); - const priceInCurrency = row.values[0][tableSetup["Price (Currency)"]]; - const baseCurrency = row.values[0][tableSetup["Base"]]; - - if (convertedCurrency[index] == -1) { - skippedRows.push(index+1); - } else { - const converted = convertedCurrency[index].rates[baseCurrency] * priceInCurrency; - priceBaseRange.values = [[converted]]; - } - index++; - } - - if(skippedRows.length > 0) { - if(skippedRows.length == 1) { - console.info(`Row: ${skippedRows.join(',')} has been converted. Skipped.`); - } else { - console.info(`Rows: ${skippedRows.join(',')} have been converted. Skipped.`); - } - } - - await context.sync(); - }); - } - - /** Check if the table contains the necessary columns. - *** These columns can be in any order within the - **/ - function isTableValid(items: Excel.TableColumn[]) { - // Build the column index, search table header - // Currency - origin currency - // Price (Currency) - price in origin currency - // Transaction Date - transaction date - // Base - home currency - // Price in Base - price in base currency - items.forEach((col, idx, arr) => { - tableSetup[col.name] = idx; - }); - if (tableSetup['Currency'] === undefined || tableSetup['Price (Currency)'] === undefined || tableSetup['Transaction Date'] === undefined || tableSetup['Base'] === undefined || tableSetup['Price in Base'] === undefined) { - return false; - } - return true; - } - - /** Request currency exchange on specific date **/ - function convertValue(currencyOrig, currencyBase, start, end) { - // GET https://api.exchangeratesapi.io/latest?symbols=SGD,USD&base=SGD&start_at=2019-10-05&end_at=2019-10-05 - const baseUrl = "https://api.exchangeratesapi.io/latest"; - const query = - "?base=" + currencyOrig + "&symbols=" + currencyBase + "," + currencyOrig + "&start_at=" + start + "&end_at=" + end; - return baseUrl + query; - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - /* Create sample data */ - /* Default header */ - /* "Currency","Price (Currency)","Transaction Date","Base","Price in Base" */ - async function setupSample() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - const transactionTable = sheet.tables.add("A1:F1", true); - transactionTable.name = tableName; - transactionTable.getHeaderRowRange().values = [["Product", "Currency", "Price (Currency)", "Transaction Date", "Base", "Price in Base"]]; - transactionTable.rows.add(null, [ - ["Frames", "MYR", 5000, "2019-10-05", "SGD", null], - ["Chains", "CNY", 12000, "2019-10-04", "SGD", null] - ]); - transactionTable.getRange().format.autofitColumns(); - sheet.activate(); - }); - } - language: typescript -template: - content: | -
-

Simple Currency Converter

-
- -
-

Simple currency converter shows how to read data from a transaction table, and uses currency converter API to - calculate the amount in base currency.

-

The code also performs table validation and identify if the table has predefined headers. You can try to to rearrange the the - column, and see by yourself!

-
- -
-

Set up

- -
- -
-

Try it out

-

The currency conversion is provided by exchangeratesapi.io which uses - exchange rate data published by the European Central Bank. Click "Convert"

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - core-js@2.4.1/client/core.min.js - @types/core-js - jquery@3.1.1 - @types/jquery@3.3.1 - moment@2.18.1 - moment-msdate@0.2.2 \ No newline at end of file diff --git a/samples/excel/90-scenarios/multiple-property-set.yaml b/samples/excel/90-scenarios/multiple-property-set.yaml deleted file mode 100644 index fc6a4c6b6..000000000 --- a/samples/excel/90-scenarios/multiple-property-set.yaml +++ /dev/null @@ -1,143 +0,0 @@ -order: 3 -id: excel-scenarios-multiple-property-set -name: Set multiple properties -description: Sets multiple properties at once with the API object set() method. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#set-multiple-properties-with-object").click(() => tryCatch(setMultiplePropertiesWithObject)); - $("#copy-properties-from-range").click(() => tryCatch(copyPropertiesFromRange)); - - async function setMultiplePropertiesWithObject() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const range = sheet.getRange("B2:E2"); - range.set({ - format: { - fill: { - color: "#4472C4" - }, - font: { - name: "Verdana", - color: "white" - } - } - }) - range.format.autofitColumns(); - await context.sync(); - }); - } - - async function copyPropertiesFromRange() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const sourceRange = sheet.getRange("B2:E2"); - sourceRange.load("format/fill/color, format/font/name, format/font/color"); - await context.sync(); - - // Set properties based on the loaded and synced - // source range. - const targetRange = sheet.getRange("B7:E7"); - targetRange.set(sourceRange); - targetRange.format.autofitColumns(); - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - - const groceryData = [ - ["Product", "Qty", "Unit Price", "Total Price"], - ["Almonds", 2, 7.50, "=C3 * D3"], - ["Coffee", 1, 34.50, "=C4 * D4"], - ["Chocolate", 5, 9.56, "=C5 * D5"] - ]; - - const groceryRange = sheet.getRange("B2:E5"); - groceryRange.values = groceryData; - groceryRange.format.autofitColumns(); - - const bakeryData = [ - ["Product", "Qty", "Unit Price", "Total Price"], - ["Cake", 2, 18.99, "=C8 * D8"], - ["Donuts", 12, 1.25, "=C9 * D9"], - ]; - - const bakeryRange = sheet.getRange("B7:E9"); - bakeryRange.values = bakeryData; - bakeryRange.format.autofitColumns(); - - sheet.activate(); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to format a range.

-
- -
-

Set up

- -
- -
-

Try it out

- - -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/90-scenarios/performance-optimization.yaml b/samples/excel/90-scenarios/performance-optimization.yaml deleted file mode 100644 index b1fa056cc..000000000 --- a/samples/excel/90-scenarios/performance-optimization.yaml +++ /dev/null @@ -1,201 +0,0 @@ -order: 1 -id: excel-performance-optimization -name: Performance optimization -description: 'Optimizes performance by untracking ranges, turning off screen painting, and switching the calculation mode.' -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#refresh-data").click(() => tryCatch(refreshData)); - $("#toggle-tracking").click(() => tryCatch(toggleTracking)); - $("#toggle-screen-painting").click(() => tryCatch(toggleScreenPainting)); - $("#toggle-calculation").click(() => tryCatch(toggleCalculationMode)); - $("#recalculate").click(() => tryCatch(recalculate)); - - const ROW_COUNT = 500; - const COLUMN_COUNT = 20; - - let untrack = false; - let pauseScreenPainting = false; - - async function refreshData() { - await Excel.run(async (context) => { - // Recreate the data in the worksheet with random data. - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - const startTime = Date.now(); - console.log("Starting..."); - - // If other parts of the sample have toggled screen painting off, this will stop screen updating until context.sync is called. - if (pauseScreenPainting) { - context.application.suspendScreenUpdatingUntilNextSync(); - } - - for (let i = 1; i < ROW_COUNT; i++) { - for (let j = 1; j < COLUMN_COUNT; j++) { - let cell = sheet.getCell(i, j); - cell.values = [[i * j * Math.random()]]; - - // If other parts of the sample have toggled tracking off, we will avoid tracking this range and having to manage the proxy objects. - // For more information, see https://learn.microsoft.com/office/dev/add-ins/concepts/resource-limits-and-performance-optimization#untrack-unneeded-proxy-objects - if (untrack) { - cell.untrack(); - } - } - } - - await context.sync(); - - console.log(`Ending. Adding ${ROW_COUNT * COLUMN_COUNT} cells took ${Date.now() - startTime} milliseconds`); - }); - } - - function toggleScreenPainting() { - pauseScreenPainting = !pauseScreenPainting; - if (pauseScreenPainting) { - console.log("Screen updating will be paused when you click Refresh Data."); - } else { - console.log("Screen updating will happen as normal."); - } - } - - function toggleTracking() { - untrack = !untrack; - if (untrack) { - console.log("Proxy range objects will not be tracked when you click Refresh Data."); - } else { - console.log("Proxy range objects will be tracked as normal."); - } - } - - async function toggleCalculationMode() { - await Excel.run(async (context) => { - context.application.load("calculationMode"); - await context.sync(); - - let calculationMode = context.application.calculationMode; - if (calculationMode === Excel.CalculationMode.automatic) { - context.application.calculationMode = Excel.CalculationMode.manual; - console.log(`Calculation mode is now ${Excel.CalculationMode.manual}`); - } else { - context.application.calculationMode = Excel.CalculationMode.automatic; - console.log(`Calculation mode is now ${Excel.CalculationMode.automatic}`); - } - }); - } - - async function recalculate() { - await Excel.run(async (context) => { - context.application.calculate(Excel.CalculationType.full); - }); - } - - async function setup() { - await Excel.run(async (context) => { - // Create a sample worksheet. - const sheet = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample"); - sheet.activate(); - sheet.getCell(0, 0).values = [["Row Total"]]; - - // Add SUM functions for each row to the first column. - let rangeAddressesToUse = []; - for (let row = 1; row < ROW_COUNT; row++) { - let cell = sheet.getCell(row, 0); - let sumRange = cell.getResizedRange(0, COLUMN_COUNT - 1).getOffsetRange(0, 1); - sumRange.load("address"); - - // Store the range objects to avoid calling context.sync in the loop. - rangeAddressesToUse.push(sumRange); - } - - await context.sync(); - rangeAddressesToUse.forEach((value, index) => { - let cell = sheet.getCell(index + 1, 0); - cell.formulas = [[`=SUM(${value.address.substring(value.address.indexOf("!") + 1)})`]]; - }); - - // Add a lot of sample data. - refreshData(); - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows some performance optimizations. Toggle the various performance options, then refresh or - recalculate to see the effects.

-
- -
-

Setup

- -
- -
-

Performance settings

- -

- -

- -

-
-

Try it out

- -

- -

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/90-scenarios/report-generation.yaml b/samples/excel/90-scenarios/report-generation.yaml deleted file mode 100644 index 2add48209..000000000 --- a/samples/excel/90-scenarios/report-generation.yaml +++ /dev/null @@ -1,158 +0,0 @@ -order: 2 -id: excel-scenarios-report-generation -name: Report generation -description: 'Writes data to the workbook, reads and applies basic formatting, and adds a chart bound to that data.' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.1' -script: - content: | - $("#create-report").click(() => tryCatch(createReport)); - - /** Load sample data into a new worksheet and create a chart */ - async function createReport() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.add(); - - try { - await writeSheetData(sheet); - sheet.activate(); - await context.sync(); - } - catch (error) { - // Try to activate the new sheet regardless, to show - // how far the processing got before failing - sheet.activate(); - await context.sync(); - - // Then re-throw the original error, for appropriate error-handling - // (in this snippet, simply showing a notification) - throw error; - } - }); - - console.log("Success!", "Report generation completed."); - } - - async function writeSheetData(sheet: Excel.Worksheet) { - // Set the report title in the worksheet - const titleCell = sheet.getCell(0, 0); - titleCell.values = [["Quarterly Sales Report"]]; - titleCell.format.font.name = "Century"; - titleCell.format.font.size = 26; - - // Create an array containing sample data - const headerNames = ["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]; - const data = [ - ["Frames", 5000, 7000, 6544, 4377], - ["Saddles", 400, 323, 276, 651], - ["Brake levers", 12000, 8766, 8456, 9812], - ["Chains", 1550, 1088, 692, 853], - ["Mirrors", 225, 600, 923, 544], - ["Spokes", 6005, 7634, 4589, 8765] - ]; - - // Write the sample data to the specified range in the worksheet - // and bold the header row - const headerRow = titleCell.getOffsetRange(1, 0) - .getResizedRange(0, headerNames.length - 1); - headerRow.values = [headerNames]; - headerRow.getRow(0).format.font.bold = true; - - const dataRange = headerRow.getOffsetRange(1, 0) - .getResizedRange(data.length - 1, 0); - dataRange.values = data; - - - titleCell.getResizedRange(0, headerNames.length - 1).merge(); - dataRange.format.autofitColumns(); - - const columnRanges = headerNames.map((header, index) => dataRange.getColumn(index).load("format/columnWidth")); - await sheet.context.sync(); - - // For the header (product name) column, make it a minimum of 100px; - const firstColumn = columnRanges.shift(); - if (firstColumn.format.columnWidth < 100) { - console.log("Expanding the first column to 100px"); - firstColumn.format.columnWidth = 100; - } - - // For the remainder, make them identical or a minimum of 60px - let minColumnWidth = 60; - columnRanges.forEach((column, index) => { - console.log(`Column #${index + 1}: auto-fitted width = ${column.format.columnWidth}`); - minColumnWidth = Math.max(minColumnWidth, column.format.columnWidth); - }); - console.log(`Setting data columns to a width of ${minColumnWidth} pixels`); - dataRange.getOffsetRange(0, 1).getResizedRange(0, -1) - .format.columnWidth = minColumnWidth; - - // Add a new chart - const chart = sheet.charts.add( - Excel.ChartType.columnClustered, - dataRange, Excel.ChartSeriesBy.columns); - - // Set the properties and format the chart - const chartTopRow = dataRange.getLastRow().getOffsetRange(2, 0); - chart.setPosition(chartTopRow, chartTopRow.getOffsetRange(14, 0)); - chart.title.text = "Quarterly sales chart"; - chart.legend.position = "Right" - chart.legend.format.fill.setSolidColor("white"); - chart.dataLabels.format.font.size = 15; - chart.dataLabels.format.font.color = "black"; - - const points = chart.series.getItemAt(0).points; - points.getItemAt(0).format.fill.setSolidColor("pink"); - points.getItemAt(1).format.fill.setSolidColor("indigo"); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -
-

This sample shows how to load sample data into the worksheet, and then create a chart.

-
- -
-

Try it out

- -
- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/90-scenarios/working-with-dates.yaml b/samples/excel/90-scenarios/working-with-dates.yaml deleted file mode 100644 index 05761ffdb..000000000 --- a/samples/excel/90-scenarios/working-with-dates.yaml +++ /dev/null @@ -1,146 +0,0 @@ -order: 4 -id: excel-scenarios-working-with-dates -name: Working with dates -description: Shows how to work with dates by using the Moment JavaScript library with the Moment-MSDate plug-in. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - declare var moment: any; - - $("#setup").click(() => tryCatch(setup)); - $("#set-date-value-using-timestamp").click(() => tryCatch(setDateValueUsingTimestamp)); - $("#get-date-value").click(() => tryCatch(getDateValue)); - - async function setDateValueUsingTimestamp() { - await Excel.run(async (context) => { - - const sheet = context.workbook.worksheets.getItem("Sample"); - const now = Date.now(); - console.log(`set (timestamp): ${now}`); - - const nowMoment = moment(now); - console.log(`set (moment): ${JSON.stringify(nowMoment)}`); - - const nowMS = nowMoment.toOADate(); - console.log(`set (MSDate): ${nowMS}`); - - const dateRange = sheet.getRange("B4"); - dateRange.values = [[nowMS]]; - dateRange.numberFormat = [["[$-409]m/d/yy h:mm AM/PM;@"]]; - - dateRange.format.autofitColumns(); - - await context.sync(); - }); - } - - async function getDateValue() { - await Excel.run(async (context) => { - - const sheet = context.workbook.worksheets.getItem("Sample"); - const dateRange = sheet.getRange("B3"); - dateRange.load("values"); - await context.sync(); - - const nowMS = dateRange.values[0][0]; - console.log(`get (MSDate): ${nowMS}`); - - const nowMoment = moment.fromOADate(nowMS); - console.log(`get (moment): ${JSON.stringify(nowMoment)}`); - - const now = nowMoment.unix(); - console.log(`get (timestamp): ${now}`) - - }); - } - - async function setup() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Sample").delete(); - const sheet = context.workbook.worksheets.add("Sample"); - const data = [ - ["Now"], - ["=NOW()"] - ]; - - const dataRange = sheet.getRange("B2:B3"); - dataRange.formulas = data; - - const headerRange = sheet.getRange("B2"); - headerRange.format.font.bold = true; - - const dateRange = sheet.getRange("B3"); - dateRange.numberFormat = [["[$-409]m/d/yy h:mm AM/PM;@"]]; - dateRange.format.autofitColumns(); - - sheet.activate(); - await context.sync(); - }); - } - - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

This sample shows how to set and get date values in a range and manipulating them using the Moment JavaScript library with the Moment-MSDate plug-in.

-
- -
-

Set up

- -
- -
-

Try it out

- - -
- language: html -style: - content: | - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 - - moment@2.18.1 - moment-msdate@0.2.2 \ No newline at end of file diff --git a/samples/excel/99-just-for-fun/color-wheel.yaml b/samples/excel/99-just-for-fun/color-wheel.yaml deleted file mode 100644 index 2bc0828c5..000000000 --- a/samples/excel/99-just-for-fun/color-wheel.yaml +++ /dev/null @@ -1,156 +0,0 @@ -order: 5 -id: excel-just-for-fun-color-wheel -name: Wheel of colors -description: Uses chart formatting to draw a wheel with changing colors. Contributed by Alexander Zlatkovski. -author: AlexanderZlatkovski -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#wheel").click(wheelGo); - $("#stop").click(wheelStop); - - let isStopped: boolean - - const pauseLength = 50; - const numberOfSlices = 32; - - async function wheelGo() { - try { - Excel.run(async (context) => { - isStopped = false; - - // Create a hidden sheet which will contain data for the color wheel chart: - context.workbook.worksheets.getItemOrNullObject("Color Wheel Settings").delete(); - const sheetSettings = context.workbook.worksheets.add("Color Wheel Settings"); - sheetSettings.visibility = Excel.SheetVisibility.hidden; - const dataRange = sheetSettings.getRange("A1:A" + numberOfSlices); - const matrix = new Array(); - for (let r = 0; r < numberOfSlices; r++) { - matrix[r] = new Array(); - for (let c = 0; c < 1; c++) { - matrix[r][c] = 1; - } - } - dataRange.values = matrix; - - // Create a sheet for the color wheel and format it - context.workbook.worksheets.getItemOrNullObject("Color Wheel").delete(); - const sheet = context.workbook.worksheets.add("Color Wheel"); - - sheet.charts.load("id"); - sheet.activate(); - - let theWheel = sheet.charts.add(Excel.ChartType.pie, dataRange, "Auto"); - - theWheel.format.fill.setSolidColor('black') - theWheel.setPosition("A1"); - theWheel.width = 300; - theWheel.height = 300; - theWheel.title.visible = false; - theWheel.legend.visible = false; - - let points = theWheel.series.getItemAt(0).points; - for (let i = 0; i < numberOfSlices; i++) { - points.getItemAt(i).format.fill.setSolidColor("black") - } - - await context.sync(); - sheet.charts.items.forEach(item => item.delete()); - - await pause(700); - - // Draw pretty colors, ad infinitum - while (!isStopped) { - const colorMultiplier = 256 / numberOfSlices; - await loopThroughColors(points, numberOfSlices * 2, i => - rgb(255, colorMultiplier / 2 * i, 0)); /* red to orange to yellow*/ - await loopThroughColors(points, numberOfSlices, i => - rgb(255 - colorMultiplier * i, 255, 0)); /* yellow to green*/ - await loopThroughColors(points, numberOfSlices, i => - rgb(0, 255, colorMultiplier * i)); /* green to blue*/ - await loopThroughColors(points, numberOfSlices, i => - rgb(0, 255 - colorMultiplier * i, 255)); /* blue to indigo*/ - await loopThroughColors(points, numberOfSlices, i => - rgb(colorMultiplier * i, 0, 255)); /* indigo to violet*/ - await loopThroughColors(points, numberOfSlices, i => - rgb(255, 0, 255 - colorMultiplier * i)); /* back from violet to red*/ - } - }); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - - async function loopThroughColors(points: Excel.ChartPointsCollection, max, colorGenerator: (i: number) => string) { - for (let i = 0; i < max; i++) { - if (isStopped) { - return; - } - let X = i % numberOfSlices; - await pause(pauseLength); - let color = colorGenerator(i); - points.getItemAt(X).format.fill.setSolidColor(color); - await points.context.sync(); - } - } - - function wheelStop() { - isStopped = true; - } - - function pause(milliseconds) { - return new Promise(resolve => setTimeout(resolve, milliseconds)) - } - - function rgb(r, g, b) { - return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1) - } - language: typescript -template: - content: |+ -

Spin the rainbow wheel

-
- -
-
- - - language: html -style: - content: | - h2:not(:first-child) { - margin-top: 35px; - } - - - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/99-just-for-fun/gradient.yaml b/samples/excel/99-just-for-fun/gradient.yaml deleted file mode 100644 index d4720d92e..000000000 --- a/samples/excel/99-just-for-fun/gradient.yaml +++ /dev/null @@ -1,226 +0,0 @@ -order: 2 -id: excel-just-for-fun-gradient -name: Gradient -description: Uses range formatting and external libraries to draw a colorful gradient within a range. Contributed by Alexander Zlatkovski. -author: AlexanderZlatkovski -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: |- - initializeColorPickers(); - - // Set up the click handler: - const $drawButton = $("#draw-gradient").click(drawGradient); - $("#random").click(randomizeColors); - - /** Click-handler for drawing the gradient */ - async function drawGradient() { - $drawButton.prop("disabled", true); - - try { - await Excel.run(drawGradientHelper); - } catch (error) { - console.log(error); - } - - $drawButton.prop("disabled", false); - } - - /** Helper function to do the actual gradient-drawing */ - async function drawGradientHelper(context: Excel.RequestContext) { - context.workbook.worksheets.getItemOrNullObject("Gradient").delete(); - const sheet = context.workbook.worksheets.add("Gradient"); - - sheet.getRange().untrack().format.set({ - rowHeight: 15, - columnWidth: 15, - fill: { - color: "#1e1e1e" - } - }); - - let originalSize = parseInt($("#size").val() as string); - const colors2D = createColorArray(originalSize); - - if (Office.context.requirements.isSetSupported("ExcelApi", "1.9")) { - // ExcelApi 1.9 introduced the setCellProperties APIs to efficiently set different properties - // across a range without needing to iterate cell-by-cell. - const cellProperties: Excel.SettableCellProperties[][] = - colors2D.map(row => - row.map(color => - ({ - format: { - fill: { - color: color - } - } - }) - ) - ); - sheet.getRangeByIndexes(1, 1, originalSize, originalSize).setCellProperties(cellProperties); - } else { - let range = sheet.getCell(1, 1).untrack().getResizedRange(originalSize - 1, originalSize - 1).untrack(); - for (let row = 0; row < originalSize; row++) { - for (let col = 0; col < originalSize; col++) { - range.getCell(row, col).untrack().format.fill.color = colors2D[row][col]; - } - } - } - - sheet.activate(); - await context.sync(); - } - - function createColorArray(size: number): string[][] { - // Create a 2D in-memory array to hold the colors - let colors2D = Array(size); - for (let row = 0; row < size; row++) { - colors2D[row] = Array(size); - } - - const topColors = getColorsArray( - $("#top-left").spectrum("get").toRgb(), - $("#top-right").spectrum("get").toRgb(), - size - ); - - const bottomColors = getColorsArray( - $("#bottom-left").spectrum("get").toRgb(), - $("#bottom-right").spectrum("get").toRgb(), - size - ); - - for (let col = 0; col < size; col++) { - const columnColors = getColorsArray(topColors[col], bottomColors[col], size); - for (let row = 0; row < size; row++) { - colors2D[row][col] = tinycolor(columnColors[row]).toHexString(); - } - } - - return colors2D; - } - - /** Helper function to get an array of colors */ - function getColorsArray(color1: ColorFormats.RGB, color2: ColorFormats.RGB, count: number) { - const result = new Array(count); - for (let i = 0; i < count; i++) { - const fraction = i / (count - 1); - result[i] = { - r: color1.r + (color2.r - color1.r) * fraction, - g: color1.g + (color2.g - color1.g) * fraction, - b: color1.b + (color2.b - color1.b) * fraction - }; - } - return result; - } - - function initializeColorPickers() { - $("#color-table input[type='text']").spectrum({ - preferredFormat: "rgb", - showInput: true - }); - } - - function randomizeColors() { - $("#color-table input[type='text']").each((index, element) => { - $(element).spectrum("set", tinycolor.random().toHexString()); - }); - } - language: typescript -template: - content: |- -

Color configuration

- -
-
Top left
- - - - - - - - - -
-
- Bottom right -
-
- - - -

Size - (width x height) -

- - - - -
-
- Uses the Spectrum color picker, and the TinyColor libraries. -
-
- language: html -style: - content: |- - h2:not(:first-child) { - margin-top: 35px; - } - - #color-table { - width: 130px; - margin-bottom: 20px; - } - - #color-table table { - width: 100%; - } - - #color-table td:nth-child(2), - #color-table div:last-child { - text-align: right; - } - - #credits { - margin-top: 60px; - padding: 10px; - background: linear-gradient(rgb(150, 150, 200), white); - } - - #credits div:first-child { - margin-bottom: 6px; - } - - #size { - width: 100%; - } - - #draw-gradient { - width: 100%; - } - language: css -libraries: |- - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 - - tinycolor2@1.4.1/tinycolor.js - @types/tinycolor2 - spectrum-colorpicker@1.8.0/spectrum.js - spectrum-colorpicker@1.8.0/spectrum.css - @types/spectrum diff --git a/samples/excel/99-just-for-fun/path-finder-game.yaml b/samples/excel/99-just-for-fun/path-finder-game.yaml deleted file mode 100644 index b63a27b27..000000000 --- a/samples/excel/99-just-for-fun/path-finder-game.yaml +++ /dev/null @@ -1,235 +0,0 @@ -order: 3 -id: excel-just-for-fun-path-finder-game -name: Path finder -description: Uses range formatting to play a "pathfinder game". Contributed by Alexander Zlatkovski. -author: AlexanderZlatkovski -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: | - $("#setup").click(setup); - $("#repeat").click(repeat); - - const $pruneTheGrid = $("#step-by-step").click(pruneTheGrid); - const $allAtOnce = $("#all-at-once").click(allAtOnce); - - const GRID_ROW_COUNT = 25; - const GRID_COLUMN_COUNT = 30; - - let matrixPrevious: string[][] - - function setup() { - const density = parseInt($("#density").val() as string) / 100; - const symbol = "\u25cf"; - - const matrix = new Array(GRID_ROW_COUNT); - for (let r = 0; r < GRID_ROW_COUNT; r++) { - matrix[r] = new Array(GRID_COLUMN_COUNT); - for (let c = 0; c < GRID_COLUMN_COUNT; c++) { - matrix[r][c] = Math.random() < density ? symbol : ""; - } - } - - matrixPrevious = matrix; - $("#repeat").show(); - - setupHelper(matrix); - } - - function repeat() { - setupHelper(matrixPrevious); - } - - - function setupHelper(matrix: string[][]) { - tryCatch(() => Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Path Finder").delete(); - const sheet = context.workbook.worksheets.add("Path Finder"); - - sheet.getRange().format.set({ - columnWidth: 16, - rowHeight: 16 - }); - - const startCell = sheet.getRange("C5"); - const gridRange = startCell.getResizedRange( - GRID_ROW_COUNT - 1, GRID_COLUMN_COUNT - 1); - - gridRange.format.set({ - font: { color: "#C00000", size: 25 }, - fill: { color: "#E2EFDA" }, - horizontalAlignment: Excel.HorizontalAlignment.center, - verticalAlignment: Excel.VerticalAlignment.center - }); - - gridRange.values = matrix; - - sheet.activate(); - await context.sync(); - })); - } - - async function pruneTheGrid() { - $pruneTheGrid.attr("disabled", "true"); - - await tryCatch(() => Excel.run(async (context) => { - const grid = context.workbook.worksheets - .getActiveWorksheet().getUsedRange().load("values"); - await context.sync(); - - const values = grid.values; - playOnce(grid.values); - grid.values = values; - await context.sync(); - })); - - $pruneTheGrid.removeAttr("disabled"); - } - - async function allAtOnce() { - $allAtOnce.attr("disabled", "true"); - let counter = 0; - - await tryCatch(() => Excel.run(async (context) => { - const grid = context.workbook.worksheets - .getActiveWorksheet().getUsedRange().load("values"); - await context.sync(); - - const values = grid.values; - - let keepGoing = true; - while (keepGoing) { - counter++; - if (!playOnce(grid.values)) { - keepGoing = false; - } - } - - grid.values = values; - await context.sync(); - })); - - console.log("Count of iterations: " + counter); - $allAtOnce.removeAttr("disabled"); - } - - - /** Remove unneeded values from one iteration of playing, and return true if made changes */ - function playOnce(values: string[][]) { - const gridSizeRows = values.length; - const gridSizeColumns = values[0].length; - - let madeChanges = false; - - // Search incoming path left to right, starting at 2nd column - for (let r = 0; r < gridSizeRows; r++) { - for (let c = 1; c < gridSizeColumns; c++) { - const hasAbove = r > 0 ? hasValue(values[r - 1][c - 1]) : false; - const hasAt = hasValue(values[r][c - 1]); - const hasBelow = r < (gridSizeRows - 1) ? - hasValue(values[r + 1][c - 1]) : false; - - const hasAnyValues = hasAbove || hasAt || hasBelow; - if (!hasAnyValues) { - madeChanges = madeChanges || (values[r][c] !== ""); - values[r][c] = ""; - } - } - } - - // Search outgoing path (right to left), starting at first column - for (let r = 0; r < gridSizeRows; r++) { - for (let c = 0; c < gridSizeColumns - 1; c++) { - const hasAbove = r > 0 ? hasValue(values[r - 1][c + 1]) : false; - const hasAt = hasValue(values[r][c + 1]); - const hasBelow = r < (gridSizeRows - 1) ? - hasValue(values[r + 1][c + 1]) : false; - - const hasAnyValues = hasAbove || hasAt || hasBelow; - if (!hasAnyValues) { - madeChanges = madeChanges || (values[r][c] !== ""); - values[r][c] = ""; - } - } - } - - return madeChanges; - } - - function hasValue(value: string) { - return (value.length > 0); - } - - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback: () => OfficeExtension.IPromise) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: | -
-

Check whether there is a path from left to right, moving forward one cell at a time (and only straight or diagonally).

-
- -

Set up

-
-
Circle density (%)
- - - -
-
- -

Find the path:

-
- -
- - -
- language: html -style: - content: |- - section.samples { - margin-top: 10px; - } - - section.setup > *, section.find-path > * { - - margin-bottom: 5px; - margin-left: 20px; - } - - #density { - width: calc(100% - 40px); - margin-bottom: 0; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/99-just-for-fun/patterns.yaml b/samples/excel/99-just-for-fun/patterns.yaml deleted file mode 100644 index ebdf9d0ee..000000000 --- a/samples/excel/99-just-for-fun/patterns.yaml +++ /dev/null @@ -1,202 +0,0 @@ -order: 1 -id: excel-just-for-fun-patterns -name: Colorful Patterns -description: Uses range formatting to draw interesting pattern. Contributed by Alexander Zlatkovski. -author: AlexanderZlatkovski -host: EXCEL -api_set: - ExcelApi: '1.4' -script: - content: |- - $("#squares").click(() => tryCatch(drawSquares)); - $("#spiral").click(() => tryCatch(drawSpiral)); - $("#decoration").click(() => tryCatch(drawDecoration)); - - async function drawSquares() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Patterns").delete(); - const sheet = context.workbook.worksheets.add("Patterns"); - - sheet.activate(); - formatBackground(sheet); - - const size = parseInt($("#size").val() as string); - - for (let i = 0; i < size; i++) { - const width = size * 2 - 2 * i; - const colors = [ - rgb(30 + Math.floor(225 / size * i), 0, 0), - rgb(0, Math.floor(225 / size * i), 0) - ]; - const range = sheet.getCell(i + 1, i + 1).getResizedRange(width - 1, width - 1); - range.format.fill.color = colors[i % 2]; - await context.sync(); - await pause(20); - } - }); - } - - - async function drawSpiral() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Patterns").delete(); - const sheet = context.workbook.worksheets.add("Patterns"); - - sheet.activate(); - formatBackground(sheet); - - const size = Math.floor(parseInt($("#size").val() as string) / 2); - - for (let i = 0; i < size - 1; i++) { - - // i is the number of full turns of the spiral; x, y, z, and w - are lengths of lines that go right, down, left, and up, respectively. - let x = 4 * i + 1; - let y = 4 * i + 2; - let z = 4 * i + 3; - let w = 4 * i + 4; - - let colorFactor = Math.floor(190 / size); - - formatLineRight(size, i, colorFactor, x); - await context.sync(); - await pause(30); - - formatLineDown(size, i, colorFactor, x, y); - await context.sync(); - await pause(30); - - formatLineLeft(size, i, colorFactor, x, y, z); - await context.sync(); - await pause(30); - - formatLineUp(size, i, colorFactor, x, y, z, w); - await context.sync(); - await pause(30); - } - - // Helpers - - function formatLineRight(size, i, colorFactor, x) { - const rangeLineRight = sheet.getCell((size-i)*2-1, (size-i)*2-1).getResizedRange(0, x); - rangeLineRight.format.fill.color = rgb(255 - i * colorFactor, 0, i * colorFactor); - } - - function formatLineDown(size, i, colorFactor, x, y) { - const rangeLineDown = sheet.getCell((size-i)*2-1, (size-i)*2-1 + x).getResizedRange(y, 0); - rangeLineDown.format.fill.color = rgb(250 - i * colorFactor, 0, i * colorFactor + 5); - } - - function formatLineLeft(size, i, colorFactor, x, y, z) { - const rangeLineLeft = sheet.getCell((size-i)*2-1 + y, (size-i)*2-1 + x).getResizedRange(0, -z); - rangeLineLeft.format.fill.color = rgb(245 - i * colorFactor, 0, i * colorFactor + 10); - } - - function formatLineUp(size, i, colorFactor, x, y, z, w) { - const rangeLineUp = sheet.getCell((size-i)*2-1 + y, (size-i)*2-1 + x - z).getResizedRange(-w, 0); - rangeLineUp.format.fill.color = rgb(240 - i * colorFactor, 0, i * colorFactor + 15); - } - }); - } - - async function drawDecoration() { - await Excel.run(async (context) => { - context.workbook.worksheets.getItemOrNullObject("Patterns").delete(); - const sheet = context.workbook.worksheets.add("Patterns"); - - sheet.activate(); - formatBackground(sheet); - - const size = Math.floor(parseInt($("#size").val() as string) / 2); - - for (let i = 0; i < size; i++) { - const range1 = sheet.getCell(2 * i + 1, 2 * i + 1).getResizedRange(size - i, size - i); - const range2 = sheet.getCell(2 * i + 1, 3 * size - i).getResizedRange(size - i, size - i); - const range3 = sheet.getCell(3 * size - i, 2 * i + 1).getResizedRange(size - i, size - i); - const range4 = sheet.getCell(3 * size - i, 3 * size - i).getResizedRange(size - i, size - i); - - let colorFactor = 255 - Math.floor(200 / size * i) - range1.format.fill.color = rgb(colorFactor, 255 - colorFactor, 0); - range2.format.fill.color = rgb(colorFactor, 255 - colorFactor, 0); - range3.format.fill.color = rgb(colorFactor, 255 - colorFactor, 0); - range4.format.fill.color = rgb(colorFactor, 255 - colorFactor, 0); - - await context.sync(); - await pause(30); - } - }); - } - - function rgb(r, g, b) { - return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); - } - - function pause(milliseconds) { - return new Promise(resolve => setTimeout(resolve, milliseconds)); - } - - function formatBackground(sheet: Excel.Worksheet) { - const range = sheet.getRange(); - range.format.columnWidth = 7; - range.format.rowHeight = 7; - range.format.fill.color = "black"; - } - - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - language: typescript -template: - content: |- -

Draw colorful patterns

- -
-
Choose size:
- -
- -
- -

- - -

- - -
- language: html -style: - content: | - h2:not(:first-child) { - margin-top: 35px; - } - - #size { - width: 100%; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file diff --git a/samples/excel/99-just-for-fun/tetrominos.yaml b/samples/excel/99-just-for-fun/tetrominos.yaml deleted file mode 100644 index 3a0850856..000000000 --- a/samples/excel/99-just-for-fun/tetrominos.yaml +++ /dev/null @@ -1,800 +0,0 @@ -order: 4 -id: excel-just-for-fun-tetrominos -name: Tetromino stacking -description: Arrange moving tetromino shapes to form lines. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: '1.9' -script: - content: |- - $("#run").click(() => { - $("#setup").hide(); - tryCatch(run); - }); - - $("#selectedFile").change(() => tryCatch(readImageFromFile)); - $("#focusButton").click(() => tryCatch(focus)); - - let backgroundPicture = getDefaultBackgroundPicture(); - - function readImageFromFile() { - const myFile = document.getElementById("selectedFile"); - const reader = new FileReader(); - - reader.onload = (event) => { - const startIndex = reader.result.toString().indexOf("base64,"); - const myBase64 = reader.result.toString().substr(startIndex + 7); - backgroundPicture = myBase64; - }; - - // Read in the image file as a data URL. - reader.readAsDataURL(myFile.files[0]); - } - - function focus() { - $("#container").focus(); - } - - async function run() { - await Excel.run(async (ctx) => { - const shapes = ctx.workbook.worksheets.getActiveWorksheet().shapes; - shapes.load("items/$none"); - await ctx.sync(); - - shapes.items.forEach((shape) => shape.delete()); - await ctx.sync(); - - const img = shapes.addImage(backgroundPicture); - let cachedShapesByPosition = {}; - - const RENDER_USING_ADD_DELETE = 0; - const RENDER_USING_ADD_FILL = 1; - let renderPolicy = RENDER_USING_ADD_FILL; - - const NUM_ROWS = 20; - const NUM_COLS = 10; - const BLOCK_WIDTH = 30; - const BLOCK_HEIGHT = 30; - const TICK_MS = 500; - - const KEY_ENTER = 13; - const KEY_SPACE = 32; - const KEY_LEFT = 37; - const KEY_RIGHT = 39; - const KEY_DOWN = 40; - const KEY_A = 65; - const KEY_D = 68; - const KEY_R = 82; - - const pieces = [ - [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], - [[0, 0, 2, 0], [0, 0, 2, 0], [0, 0, 2, 0], [0, 0, 2, 0]], - [[0, 0, 3, 0], [0, 3, 3, 0], [0, 0, 3, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 4, 4], [0, 4, 4, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 5, 5, 0], [0, 0, 5, 5], [0, 0, 0, 0]], - [[0, 0, 6, 0], [0, 0, 6, 0], [0, 6, 6, 0], [0, 0, 0, 0]], - [[0, 7, 0, 0], [0, 7, 0, 0], [0, 7, 7, 0], [0, 0, 0, 0]] - ]; - - const background = [ - "#E5E8E8" /* Black */, - "#C0392B" /* Red */, - "#9b59b6" /* Purple */, - "#16a085" /* Deep Green */, - "#58d68d" /* Light Green */, - "#af601a" /* Red Yellow */, - "#F1C40F" /* Light Yellow */ - ]; - - function rotateLeft(piece) { - return [ - [piece[0][3], piece[1][3], piece[2][3], piece[3][3]], - [piece[0][2], piece[1][2], piece[2][2], piece[3][2]], - [piece[0][1], piece[1][1], piece[2][1], piece[3][1]], - [piece[0][0], piece[1][0], piece[2][0], piece[3][0]] - ]; - } - - function rotateRight(piece) { - return [ - [piece[3][0], piece[2][0], piece[1][0], piece[0][0]], - [piece[3][1], piece[2][1], piece[1][1], piece[0][1]], - [piece[3][2], piece[2][2], piece[1][2], piece[0][2]], - [piece[3][3], piece[2][3], piece[1][3], piece[0][3]] - ]; - } - - function intersects(rows, piece, y, x) { - for (let i = 0; i < 4; i++) { - for (let j = 0; j < 4; j++) { - if (piece[i][j]) { - if (y + i >= NUM_ROWS || x + j < 0 || x + j >= NUM_COLS || rows[y + i][x + j]) { - return true; - } - } - } - } - - return false; - } - - function applyPiece(rows, piece, y, x) { - const newRows = []; - for (let i = 0; i < NUM_ROWS; i++) { - newRows[i] = rows[i].slice(); - } - - for (let i = 0; i < 4; i++) { - for (let j = 0; j < 4; j++) { - if (piece[i][j]) { - newRows[y + i][x + j] = piece[i][j]; - } - } - } - - return newRows; - } - - function removeRows(rows) { - const newRows = []; - let k = NUM_ROWS; - for (let i = NUM_ROWS; i-- > 0; ) { - for (let j = 0; j < NUM_COLS; j++) { - if (!rows[i][j]) { - newRows[--k] = rows[i].slice(); - break; - } - } - } - - for (let i = 0; i < k; i++) { - newRows[i] = []; - for (let j = 0; j < NUM_COLS; j++) newRows[i][j] = 0; - } - - return { - rows: newRows, - numRowsKilled: k - }; - } - - function randomPiece() { - return pieces[Math.floor(Math.random() * pieces.length)]; - } - - function coreMovementFunction() { - this.sessionOver = false; - this.rowsCleared = 0; - this.currentPiece = randomPiece(); - this.nextPiece = randomPiece(); - this.pieceY = 0; - this.pieceX = NUM_COLS / 2 - 2; - this.rows = []; - for (let i = 0; i < NUM_ROWS; i++) { - this.rows[i] = []; - for (let j = 0; j < NUM_COLS; j++) { - this.rows[i][j] = 0; - } - } - } - - coreMovementFunction.prototype.reset = function() { - this.sessionOver = false; - this.rowsCleared = 0; - this.currentPiece = randomPiece(); - this.nextPiece = randomPiece(); - this.pieceY = 0; - this.pieceX = NUM_COLS / 2 - 2; - this.rows = []; - for (let i = 0; i < NUM_ROWS; i++) { - this.rows[i] = []; - for (let j = 0; j < NUM_COLS; j++) { - this.rows[i][j] = 0; - } - } - }; - - coreMovementFunction.prototype.tick = function() { - if (this.sessionOver) return false; - - if (sessionInitializing) { - return false; - } - - if (intersects(this.rows, this.currentPiece, this.pieceY + 1, this.pieceX)) { - this.rows = applyPiece(this.rows, this.currentPiece, this.pieceY, this.pieceX); - - const r = removeRows(this.rows); - this.rows = r.rows; - this.rowsCleared += r.numRowsKilled; - - if (intersects(this.rows, this.nextPiece, 0, NUM_COLS / 2 - 2)) { - this.sessionOver = true; - } else { - this.currentPiece = this.nextPiece; - this.pieceY = 0; - this.pieceX = NUM_COLS / 2 - 2; - this.nextPiece = randomPiece(); - } - } else { - this.pieceY += 1; - } - - return true; - }; - - coreMovementFunction.prototype.steerLeft = function() { - if (!intersects(this.rows, this.currentPiece, this.pieceY, this.pieceX - 1)) { - this.pieceX -= 1; - } - }; - - coreMovementFunction.prototype.steerRight = function() { - if (!intersects(this.rows, this.currentPiece, this.pieceY, this.pieceX + 1)) { - this.pieceX += 1; - } - }; - - coreMovementFunction.prototype.steerDown = function() { - if (!intersects(this.rows, this.currentPiece, this.pieceY + 1, this.pieceX)) { - this.pieceY += 1; - } - }; - - coreMovementFunction.prototype.rotateLeft = function() { - const newPiece = rotateLeft(this.currentPiece); - if (!intersects(this.rows, newPiece, this.pieceY, this.pieceX)) { - this.currentPiece = newPiece; - } - }; - - coreMovementFunction.prototype.rotateRight = function() { - const newPiece = rotateRight(this.currentPiece); - if (!intersects(this.rows, newPiece, this.pieceY, this.pieceX)) { - this.currentPiece = newPiece; - } - }; - - coreMovementFunction.prototype.letFall = function() { - while (!intersects(this.rows, this.currentPiece, this.pieceY + 1, this.pieceX)) { - this.pieceY += 1; - } - - this.tick(); - }; - - coreMovementFunction.prototype.getRows = function() { - return applyPiece(this.rows, this.currentPiece, this.pieceY, this.pieceX); - }; - - coreMovementFunction.prototype.getNextPiece = function() { - return this.nextPiece; - }; - - coreMovementFunction.prototype.getRowsCleared = function() { - return this.rowsCleared; - }; - - coreMovementFunction.prototype.getSessionOver = function() { - return this.sessionOver; - }; - - function drawPreview(rows, num_rows, num_cols, domContainer) { - const boardElem = document.createElement("div"); - for (let i = 0; i < num_rows; i++) { - for (let j = 0; j < num_cols; j++) { - const blockElem = document.createElement("div"); - blockElem.classList.add("block"); - if (rows[i][j]) { - blockElem.classList.add("habitated"); - } - - blockElem.style.top = i * BLOCK_HEIGHT + "px"; - blockElem.style.left = j * BLOCK_WIDTH + "px"; - blockElem.style.backgroundColor = background[rows[i][j] - 1]; - boardElem.appendChild(blockElem); - } - } - - domContainer.appendChild(boardElem); - } - - let isDrawing = false; - - async function drawBlocks(rows, num_rows, num_cols, domContainer) { - if (isDrawing) { - return; - } - - isDrawing = true; - - if (renderPolicy == RENDER_USING_ADD_DELETE) { - // #1: Create new shapes on demand - let validShapes = {}; - let shapeCreated = 0; - let shapeKept = 0; - for (let i = 0; i < num_rows; i++) { - for (let j = 0; j < num_cols; j++) { - if (rows[i][j]) { - let top = i * BLOCK_HEIGHT; - let left = j * BLOCK_WIDTH; - const key = top + "-" + left; - - if (cachedShapesByPosition[key]) { - shapeKept += 1; - validShapes[key] = cachedShapesByPosition[key]; - delete cachedShapesByPosition[key]; - } else { - shapeCreated += 1; - const newshp = shapes.addGeometricShape("Rectangle"); - newshp.left = left; - newshp.top = top; - newshp.width = BLOCK_WIDTH; - newshp.height = BLOCK_HEIGHT; - validShapes[key] = newshp; - } - - let color = background[rows[i][j] - 1]; - validShapes[key].fill.setSolidColor(color); - } - } - } - - // #2: Delete shapes no need anymore - let shpDeleted = 0; - for (const key in cachedShapesByPosition) { - if (cachedShapesByPosition.hasOwnProperty(key)) { - shpDeleted += 1; - const shapPendingToDelete = cachedShapesByPosition[key]; - shapPendingToDelete.delete(); - } - } - - // #3: Update the cache - cachedShapesByPosition = validShapes; - } else if (renderPolicy == RENDER_USING_ADD_FILL) { - let countOfShapesRefilled = 0; - let countOfShapesSetToInvisible = 0; - let countOfShapesSetToVisible = 0; - - for (let i = 0; i < num_rows; i++) { - for (let j = 0; j < num_cols; j++) { - let top = i * BLOCK_HEIGHT; - let left = j * BLOCK_WIDTH; - let key = top + "-" + left; - - if (!cachedShapesByPosition[key]) { - throw new Error("Shape should be created before reaching here."); - } - - if (rows[i][j]) { - // show a shape - if (cachedShapesByPosition[key].fill.transparency == 1) { - cachedShapesByPosition[key].fill.transparency = 0; - countOfShapesSetToVisible += 1; - } - - let color = background[rows[i][j] - 1]; - if (color != cachedShapesByPosition[key].fill.foregroundColor) { - cachedShapesByPosition[key].fill.foregroundColor = color; - countOfShapesRefilled += 1; - } - } else { - // hide a shape - if (cachedShapesByPosition[key].fill.transparency == 0) { - cachedShapesByPosition[key].fill.transparency = 1; - countOfShapesSetToInvisible += 1; - } - } - } - } - } - - await ctx.sync(); - isDrawing = false; - } - - function drawCoreMovement(session, isPaused, containerElem) { - const tetrominoElement = document.createElement("div"); - tetrominoElement.classList.add("coreMovementFunction"); - - // following part will be drawn inside the addin pane - drawConsolePane(session, isPaused, tetrominoElement); - - // this will be drawn inside the worksheet rather than the addin pane - drawCoreMovementPane(session, tetrominoElement); - - containerElem.appendChild(tetrominoElement); - } - - function drawCoreMovementPane(session, containerElem) { - const sessionPaneElem = document.createElement("div"); - drawBoard(session, sessionPaneElem); - - containerElem.appendChild(sessionPaneElem); - } - - function drawBoard(session, containerElem) { - const boardPaneElem = document.createElement("div"); - boardPaneElem.classList.add("board"); - - const rows = session.getRows(); - drawBlocks(rows, NUM_ROWS, NUM_COLS, boardPaneElem); - - containerElem.appendChild(boardPaneElem); - } - - function drawConsolePane(session, isPaused, containerElem) { - const consolePaneElem = document.createElement("div"); - consolePaneElem.classList.add("consolePane"); - - const previewText = drawPreviewText(session); - const previewElem = drawSessionPreview(session); - const rowsClearedElem = drawRowsCleared(session, isPaused); - const usageElem = drawSessionUsage(); - - consolePaneElem.appendChild(previewText); - consolePaneElem.appendChild(previewElem); - consolePaneElem.appendChild(rowsClearedElem); - consolePaneElem.appendChild(usageElem); - - containerElem.appendChild(consolePaneElem); - } - - function drawRowsCleared(session, isPaused) { - const rowsCleared = session.getRowsCleared(); - const rowsClearedElem = document.createElement("div"); - rowsClearedElem.classList.add("sessionRowsCleared"); - rowsClearedElem.innerHTML = "

Rows cleared: " + rowsCleared + "

"; - if (isPaused) { - rowsClearedElem.innerHTML += "

PAUSED

"; - } - - if (session.getSessionOver()) { - rowsClearedElem.innerHTML += "

SESSION OVER

"; - } - - return rowsClearedElem; - } - - function drawPreviewText(session) { - const previewTextElem = document.createElement("div"); - previewTextElem.classList.add("previewText"); - previewTextElem.innerHTML = "

Next shape

"; - return previewTextElem; - } - - function drawSessionPreview(session) { - const piece = session.getNextPiece(); - const previewElem = document.createElement("div"); - previewElem.classList.add("preview"); - drawPreview(piece, 4, 4, previewElem); - return previewElem; - } - - function drawSessionUsage() { - const usageElem = document.createElement("div"); - usageElem.classList.add("usage"); - usageElem.innerHTML = ` -

Keyboard controls:

- - - - - - - - - -
Move shape leftLeft arrow
Move shape rightRight arrow
Move shape downDown arrow
Rotate counterclockwiseA
Rotate clockwiseD
Drop shape to bottomSpace
Pause/UnpauseEnter
Restart sessionR
- `; - return usageElem; - } - - let sessionInitializing = false; - async function initializeSceneAsync() { - for (const key in cachedShapesByPosition) { - if (cachedShapesByPosition.hasOwnProperty(key)) { - const shp = cachedShapesByPosition[key]; - shp.delete(); - delete cachedShapesByPosition[key]; - } - } - await ctx.sync(); - - for (let i = 0; i < NUM_ROWS; i++) { - for (let j = 0; j < NUM_COLS; j++) { - if (renderPolicy == RENDER_USING_ADD_FILL) { - let top = i * BLOCK_HEIGHT; - let left = j * BLOCK_WIDTH; - let key = top + "-" + left; - - let newshp = shapes.addGeometricShape("Rectangle"); - newshp.left = left; - newshp.top = top; - newshp.width = BLOCK_WIDTH; - newshp.height = BLOCK_HEIGHT; - - newshp.fill.transparency = 1; - newshp.fill.foregroundColor = "#000000"; - - cachedShapesByPosition[key] = newshp; - } - } - } - - await ctx.sync(); - sessionInitializing = false; - } - - let throttledRedraw; - function redraw(session, isPaused, containerElem) { - containerElem.innerHTML = ""; - - if (sessionInitializing) { - return; - } - - let drawingFactory = function(context) { - return function() { - drawCoreMovement.apply(context, [session, isPaused, containerElem]); - }; - }; - - if (!throttledRedraw) { - throttledRedraw = _.throttle(drawingFactory(this), TICK_MS / 5, { maxWait: TICK_MS }); - } - - throttledRedraw(); - } - - async function run(rootelem, containerElem) { - const session = new coreMovementFunction(); - await initializeSceneAsync(); - - play(); - - function play() { - const intervalHandler = setInterval(function() { - if (session.tick()) { - redraw(session, false, containerElem); - } - }, TICK_MS); - - async function keyHandler(kev) { - if (kev.shiftKey || kev.altKey || kev.metaKey) { - return; - } - - let consumed = true; - let mustpause = false; - if (kev.keyCode === KEY_ENTER) { - mustpause = true; - } else if (kev.keyCode === KEY_R) { - kev.preventDefault(); - consumed = false; - sessionInitializing = true; - session.reset(); - await initializeSceneAsync(); - } else if (kev.keyCode === KEY_LEFT) { - session.steerLeft(); - } else if (kev.keyCode === KEY_RIGHT) { - session.steerRight(); - } else if (kev.keyCode === KEY_DOWN) { - session.steerDown(); - } else if (kev.keyCode === KEY_A) { - session.rotateLeft(); - } else if (kev.keyCode === KEY_D) { - session.rotateRight(); - } else if (kev.keyCode === KEY_SPACE) { - session.letFall(); - } else { - consumed = false; - } - - if (consumed) { - kev.preventDefault(); - if (mustpause) { - rootelem.removeEventListener("keydown", keyHandler); - clearInterval(intervalHandler); - pause(); - } else { - redraw(session, false, containerElem); - } - } - } - - rootelem.addEventListener("keydown", keyHandler); - } - - function pause() { - function keyHandler(kev) { - if (kev.keyCode == KEY_ENTER) { - rootelem.removeEventListener("keydown", keyHandler); - play(); - } - } - - rootelem.addEventListener("keydown", keyHandler); - redraw(session, true, containerElem); - } - } - - await run($("#container")[0], $("#sessionPane")[0]); - - $("#container").focus(); - $("#focus").show(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } catch (error) { - $("#setup").show(); - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } - } - - function getDefaultBackgroundPicture() { - return "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"; - } - language: typescript -template: - content: |- -
-
-

This sample lets you repeatedly stack tetrominos, which are represented by Shapes. Select a background image (or leave blank for the default) and Start!. The controls will then be displayed.

-
- -
-

Select Background Image

-

- -

-
-
-
-
-

-

- language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - - div.container { - position: absolute; - margin: 0; - padding: 0; - top: 0; - left: 0; - height: 100%; - margin-left: 20px; - margin-right: 20px; - } - - div.sessionPane { - display: block; - position: relative; - margin: 0; - padding: 0; - border: none; - width: 100%; - height: 100%; - } - - div.sessionPane div.consolePane { - position: relative; - display: block; - margin: 0; - padding: 0; - width: 100%; - } - - div.consolePane div.previewText { - position: relative; - display: block; - margin: 0; - padding: 0; - font-size: 20pt; - } - - div.consolePane div.sessionRowsCleared { - position: relative; - display: block; - margin: 0; - padding: 0; - font-size: 20pt; - } - - div.consolePane div.preview { - position: relative; - display: block; - margin: 0; - padding: 0; - width: 120px; /* 4 cols * 30px */ - height: 120px; /* 4 rows * 30px */ - background-color: gray; - } - - div.consolePane div.usage { - position: relative; - display: block; - margin: 0; - padding: 0; - } - - div.consolePane div.usage th, - div.consolePane div.usage td { - text-align: left; - } - - div.consolePane div.usage td { - padding-left: 1em; - } - - div.sessionPane { - position: relative; - display: block; - margin-top: 20px; - padding: 0; - width: 300px; /* 10 cols * 30px */ - height: 600px; /* 20 rows * 30px */ - } - - div.sessionPane div.board { - position: relative; - display: block; - margin: 0; - padding: 0; - border: none; - width: 100%; - height: 100%; - } - - div.block { - position: absolute; - width: 29px; - height: 29px; - border: 1px solid black; - } - - div.block.habitated { - border: 1px solid black; - } - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 - - https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js diff --git a/samples/excel/default.yaml b/samples/excel/default.yaml index 10ea5b1db..39134e438 100644 --- a/samples/excel/default.yaml +++ b/samples/excel/default.yaml @@ -1,63 +1,22 @@ -id: excel-default -name: Blank snippet -description: Create a new snippet from a blank template. -author: OfficeDev +id: excel-custom-functions-example +name: New Function +description: Describe the operation the function will perform host: EXCEL api_set: - ExcelApi: '1.1' + CustomFunctionsRuntime: 1.1 script: content: | - $("#run").click(() => tryCatch(run)); - - async function run() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - - console.log("Your code goes here"); - - await context.sync(); - }); - } - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback) { - try { - await callback(); - } - catch (error) { - // Note: In a production add-in, you'd want to notify the user through your add-in's UI. - console.error(error); - } + /** + * Provides an example of creating an custom function. + * @customfunction + * @param {number} radius + * @returns The volume of the sphere. + */ + function exampleFunction(radius) { + return Math.pow(radius, 3) * 4 * Math.PI / 3; } language: typescript -template: - content: | - - language: html -style: - content: |- - section.samples { - margin-top: 20px; - } - - section.samples .ms-Button, section.setup .ms-Button { - display: block; - margin-bottom: 5px; - margin-left: 20px; - min-width: 80px; - } - language: css libraries: | https://appsforoffice.microsoft.com/lib/1/hosted/office.js @types/office-js - - office-ui-fabric-js@1.4.0/dist/css/fabric.min.css - office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css - core-js@2.4.1/client/core.min.js - @types/core-js - - jquery@3.1.1 - @types/jquery@3.3.1 \ No newline at end of file